merge birch to mozilla-central
authorBrad Lassey <blassey@mozilla.com>
Tue, 06 Dec 2011 13:55:36 -0500
changeset 83667 c29569f9df99b5811d674054175032c1eac0138e
parent 83136 bf8259fcab61b5966835b7cfc21ed5565c42fcfc (current diff)
parent 83666 f59768ba385a898aca7202c37db72db005ec8dde (diff)
child 83668 0e397568c71ed693dd8da831d3f2731d5cff6604
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge birch to mozilla-central
config/autoconf.mk.in
configure.in
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
dom/base/nsGlobalWindow.cpp
dom/plugins/base/android/ANPCanvas.cpp
dom/plugins/base/android/ANPPaint.cpp
dom/plugins/base/android/ANPPath.cpp
dom/plugins/base/android/ANPTypeface.cpp
editor/libeditor/base/nsEditor.cpp
embedding/android/AlertNotification.java
embedding/android/AndroidManifest.xml.in
embedding/android/App.java.in
embedding/android/CrashReporter.java.in
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
embedding/android/GeckoBatteryManager.java
embedding/android/GeckoConnectivityReceiver.java
embedding/android/GeckoEvent.java
embedding/android/GeckoInputConnection.java
embedding/android/GeckoSmsManager.java
embedding/android/GeckoSurfaceView.java
embedding/android/LauncherShortcuts.java.in
embedding/android/Makefile.in
embedding/android/NotificationHandler.java.in
embedding/android/Restarter.java.in
embedding/android/SurfaceInfo.java
embedding/android/locales/Makefile.in
embedding/android/locales/en-US/android_strings.dtd
embedding/android/locales/jar.mn
embedding/android/locales/l10n.ini
embedding/android/resources/drawable/crash_reporter.png
embedding/android/resources/drawable/desktop_notification.png
embedding/android/resources/layout/crash_reporter.xml
embedding/android/resources/layout/launch_app_list.xml
embedding/android/resources/layout/launch_app_listitem.xml
embedding/android/resources/layout/notification_icon_text.xml
embedding/android/resources/layout/notification_progress.xml
embedding/android/resources/layout/notification_progress_text.xml
embedding/android/resources/values/colors.xml
embedding/android/resources/values/themes.xml
embedding/android/strings.xml.in
gfx/gl/GLContextProviderEGL.cpp
layout/base/nsPresShell.cpp
layout/base/tests/chrome/Makefile.in
layout/generic/nsFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsSubDocumentFrame.cpp
mobile/android/base/GeckoBatteryManager.java
mobile/xul/installer/package-manifest.in
toolkit/components/places/nsNavHistory.cpp
widget/src/android/nsAppShell.cpp
deleted file mode 100644
deleted file mode 100644
deleted file mode 100644
deleted file mode 100644
deleted file mode 100644
--- a/embedding/android/GeckoSurfaceView.java
+++ /dev/null
@@ -1,833 +0,0 @@
-/* -*- 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) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.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 java.util.*;
-import java.util.concurrent.*;
-import java.util.concurrent.locks.*;
-import java.util.concurrent.atomic.*;
-import java.util.zip.*;
-import java.nio.*;
-
-import android.os.*;
-import android.app.*;
-import android.text.*;
-import android.text.method.*;
-import android.view.*;
-import android.view.inputmethod.*;
-import android.content.*;
-import android.graphics.*;
-import android.widget.*;
-import android.hardware.*;
-import android.location.*;
-import android.graphics.drawable.*;
-import android.content.res.*;
-
-import android.util.*;
-
-/*
- * GeckoSurfaceView implements a GL surface view,
- * similar to GLSurfaceView.  However, since we
- * already have a thread for Gecko, we don't really want
- * a separate renderer thread that GLSurfaceView provides.
- */
-class GeckoSurfaceView
-    extends SurfaceView
-    implements SurfaceHolder.Callback, SensorEventListener, LocationListener
-{
-    private static final String LOG_FILE_NAME = "GeckoSurfaceView";
-
-    public GeckoSurfaceView(Context context) {
-        super(context);
-
-        getHolder().addCallback(this);
-        inputConnection = new GeckoInputConnection(this);
-        setFocusable(true);
-        setFocusableInTouchMode(true);
-        
-        DisplayMetrics metrics = new DisplayMetrics();
-        GeckoApp.mAppContext.getWindowManager().
-            getDefaultDisplay().getMetrics(metrics);
-        mWidth = metrics.widthPixels;
-        mHeight = metrics.heightPixels;
-        mBufferWidth = 0;
-        mBufferHeight = 0;
-
-        mSurfaceLock = new ReentrantLock();
-
-        mEditableFactory = Editable.Factory.getInstance();
-        initEditable("");
-        mIMEState = IME_STATE_DISABLED;
-        mIMETypeHint = "";
-        mIMEActionHint = "";
-    }
-
-    protected void finalize() throws Throwable {
-        super.finalize();
-    }
-
-    void drawSplashScreen() {
-        this.drawSplashScreen(getHolder(), mWidth, mHeight);
-    }
-
-    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;
-        }
-
-        Canvas c = holder.lockCanvas();
-        if (c == null) {
-            Log.i(LOG_FILE_NAME, "canvas is null");
-            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);
-            }
-        }
-        holder.unlockCanvasAndPost(c);
-    }
-
-    /*
-     * Called on main thread
-     */
-
-    public void draw(SurfaceHolder holder, ByteBuffer buffer) {
-        if (buffer == null || buffer.capacity() != (mWidth * mHeight * 2))
-            return;
-
-        synchronized (mSoftwareBuffer) {
-            if (buffer != mSoftwareBuffer || mSoftwareBufferCopy == null)
-                return;
-
-            Canvas c = holder.lockCanvas();
-            if (c == null)
-                return;
-            mSoftwareBufferCopy.copyPixelsFromBuffer(buffer);
-            c.drawBitmap(mSoftwareBufferCopy, 0, 0, null);
-            holder.unlockCanvasAndPost(c);
-        }
-    }
-
-    public void draw(SurfaceHolder holder, Bitmap bitmap) {
-        if (bitmap == null ||
-            bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight)
-            return;
-
-        synchronized (mSoftwareBitmap) {
-            if (bitmap != mSoftwareBitmap)
-                return;
-
-            Canvas c = holder.lockCanvas();
-            if (c == null)
-                return;
-            c.drawBitmap(bitmap, 0, 0, null);
-            holder.unlockCanvasAndPost(c);
-        }
-    }
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-
-        // On pre-Honeycomb, force exactly one frame of the previous size
-        // to render because the surface change is only seen by GLES after we
-        // have swapped the back buffer (i.e. the buffer size only changes 
-        // after the next swap buffer). We need to make sure Gecko's view 
-        // resizes when Android's buffer resizes.
-        // In Honeycomb, the buffer size changes immediately, so rendering a
-        // frame of the previous size is unnecessary (and wrong).
-        if (mDrawMode == DRAW_GLES_2 && 
-            (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)) {
-            // When we get a surfaceChange event, we have 0 to n paint events 
-            // waiting in the Gecko event queue. We will make the first
-            // succeed and the abort the others.
-            mDrawSingleFrame = true;
-            if (!mInDrawing) { 
-                // Queue at least one paint event in case none are queued.
-                GeckoAppShell.scheduleRedraw();
-            }
-            GeckoAppShell.geckoEventSync();
-            mDrawSingleFrame = false;
-            mAbortDraw = false;
-        }
-
-        if (mShowingSplashScreen)
-            drawSplashScreen(holder, width, height);
-
-        mSurfaceLock.lock();
-
-        if (mInDrawing) {
-            Log.w(LOG_FILE_NAME, "surfaceChanged while mInDrawing is true!");
-        }
-
-        boolean invalidSize;
-
-        if (width == 0 || height == 0) {
-            mSoftwareBitmap = null;
-            mSoftwareBuffer = null;
-            mSoftwareBufferCopy = null;
-            invalidSize = true;
-        } else {
-            invalidSize = false;
-        }
-
-        boolean doSyncDraw =
-            mDrawMode == DRAW_2D &&
-            !invalidSize &&
-            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);
-
-        try {
-            DisplayMetrics metrics = new DisplayMetrics();
-            GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
-
-            GeckoEvent e = new GeckoEvent(GeckoEvent.SIZE_CHANGED, width, height,
-                                          metrics.widthPixels, metrics.heightPixels);
-            GeckoAppShell.sendEventToGecko(e);
-        } finally {
-            mSurfaceLock.unlock();
-        }
-
-        if (doSyncDraw) {
-            GeckoAppShell.scheduleRedraw();
-
-            Object syncDrawObject = null;
-            try {
-                syncDrawObject = mSyncDraws.take();
-            } catch (InterruptedException ie) {
-                Log.e(LOG_FILE_NAME, "Threw exception while getting sync draw bitmap/buffer: ", ie);
-            }
-            if (syncDrawObject != null) {
-                if (syncDrawObject instanceof Bitmap)
-                    draw(holder, (Bitmap)syncDrawObject);
-                else
-                    draw(holder, (ByteBuffer)syncDrawObject);
-            } else {
-                Log.e("GeckoSurfaceViewJava", "Synchronised draw object is null");
-            }
-        } else if (!mShowingSplashScreen) {
-            // Make sure a frame is drawn before we return
-            // otherwise we see artifacts or a black screen
-            GeckoAppShell.scheduleRedraw();
-            GeckoAppShell.geckoEventSync();
-        }
-    }
-
-    public void surfaceCreated(SurfaceHolder holder) {
-        Log.i(LOG_FILE_NAME, "surface created");
-        GeckoEvent e = new GeckoEvent(GeckoEvent.SURFACE_CREATED);
-        GeckoAppShell.sendEventToGecko(e);
-        if (mShowingSplashScreen)
-            drawSplashScreen();
-    }
-
-    public void surfaceDestroyed(SurfaceHolder holder) {
-        Log.i(LOG_FILE_NAME, "surface destroyed");
-        mSurfaceValid = false;
-        mSoftwareBuffer = null;
-        mSoftwareBufferCopy = null;
-        mSoftwareBitmap = null;
-        GeckoEvent e = new GeckoEvent(GeckoEvent.SURFACE_DESTROYED);
-        if (mDrawMode == DRAW_GLES_2) {
-            // Ensure GL cleanup occurs before we return.
-            GeckoAppShell.sendEventToGeckoSync(e);
-        } else {
-            GeckoAppShell.sendEventToGecko(e);
-        }
-    }
-
-    public Bitmap getSoftwareDrawBitmap() {
-        if (mSoftwareBitmap == null ||
-            mSoftwareBitmap.getHeight() != mHeight ||
-            mSoftwareBitmap.getWidth() != mWidth) {
-            mSoftwareBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565);
-        }
-
-        mDrawMode = DRAW_2D;
-        return mSoftwareBitmap;
-    }
-
-    public ByteBuffer getSoftwareDrawBuffer() {
-        // We store pixels in 565 format, so two bytes per pixel (explaining
-        // the * 2 in the following check/allocation)
-        if (mSoftwareBuffer == null ||
-            mSoftwareBuffer.capacity() != (mWidth * mHeight * 2)) {
-            mSoftwareBuffer = ByteBuffer.allocateDirect(mWidth * mHeight * 2);
-        }
-
-        if (mSoftwareBufferCopy == null ||
-            mSoftwareBufferCopy.getHeight() != mHeight ||
-            mSoftwareBufferCopy.getWidth() != mWidth) {
-            mSoftwareBufferCopy = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565);
-        }
-
-        mDrawMode = DRAW_2D;
-        return mSoftwareBuffer;
-    }
-
-    public Surface getSurface() {
-        return getHolder().getSurface();
-    }
-
-    /*
-     * Called on Gecko thread
-     */
-
-    public static final int DRAW_ERROR = 0;
-    public static final int DRAW_GLES_2 = 1;
-    public static final int DRAW_2D = 2;
-    // Drawing is disable when the surface buffer
-    // has changed size but we haven't yet processed the
-    // resize event.
-    public static final int DRAW_DISABLED = 3;
-
-    public int beginDrawing() {
-        if (mInDrawing) {
-            Log.e(LOG_FILE_NAME, "Recursive beginDrawing call!");
-            return DRAW_ERROR;
-        }
-
-        // Once we drawn our first frame after resize we can ignore
-        // the other draw events until we handle the resize events.
-        if (mAbortDraw) {
-            return DRAW_DISABLED;
-        }
-
-        /* Grab the lock, which we'll hold while we're drawing.
-         * It gets released in endDrawing(), and is also used in surfaceChanged
-         * to make sure that we don't change our surface details while
-         * we're in the middle of drawing (and especially in the middle of
-         * executing beginDrawing/endDrawing).
-         *
-         * We might not need to hold this lock in between
-         * beginDrawing/endDrawing, and might just be able to make
-         * surfaceChanged, beginDrawing, and endDrawing synchronized,
-         * but this way is safer for now.
-         */
-        mSurfaceLock.lock();
-
-        if (!mSurfaceValid) {
-            Log.e(LOG_FILE_NAME, "Surface not valid");
-            mSurfaceLock.unlock();
-            return DRAW_ERROR;
-        }
-
-        mInDrawing = true;
-        mDrawMode = DRAW_GLES_2;
-        return DRAW_GLES_2;
-    }
-
-    public void endDrawing() {
-        if (!mInDrawing) {
-            Log.e(LOG_FILE_NAME, "endDrawing without beginDrawing!");
-            return;
-        }
-
-       if (mDrawSingleFrame)
-            mAbortDraw = true;
-
-        try {
-            if (!mSurfaceValid) {
-                Log.e(LOG_FILE_NAME, "endDrawing with false mSurfaceValid");
-                return;
-            }
-        } finally {
-            mInDrawing = false;
-
-            if (!mSurfaceLock.isHeldByCurrentThread())
-                Log.e(LOG_FILE_NAME, "endDrawing while mSurfaceLock not held by current thread!");
-
-            mSurfaceLock.unlock();
-        }
-    }
-
-    /* How this works:
-     * Whenever we want to draw, we want to be sure that we do not lock
-     * the canvas unless we're sure we can draw. Locking the canvas clears
-     * the canvas to black in most cases, causing a black flash.
-     * At the same time, the surface can resize/disappear at any moment
-     * unless the canvas is locked.
-     * Draws originate from a different thread so the surface could change
-     * at any moment while we try to draw until we lock the canvas.
-     *
-     * Also, never try to lock the canvas while holding the surface lock
-     * unless you're in SurfaceChanged, in which case the canvas was already
-     * locked. Surface lock -> Canvas lock will lead to AB-BA deadlocks.
-     */
-    public void draw2D(Bitmap bitmap, int width, int height) {
-        // mSurfaceLock ensures that we get mSyncDraw/mSoftwareBitmap/etc.
-        // set correctly before determining whether we should do a sync draw
-        mSurfaceLock.lock();
-        try {
-            if (mSyncDraw) {
-                if (bitmap != mSoftwareBitmap || width != mWidth || height != mHeight)
-                    return;
-                mSyncDraw = false;
-                try {
-                    mSyncDraws.put(bitmap);
-                } catch (InterruptedException ie) {
-                    Log.e(LOG_FILE_NAME, "Threw exception while getting sync draws queue: ", ie);
-                }
-                return;
-            }
-        } finally {
-            mSurfaceLock.unlock();
-        }
-
-        draw(getHolder(), bitmap);
-    }
-
-    public void draw2D(ByteBuffer buffer, int stride) {
-        mSurfaceLock.lock();
-        try {
-            if (mSyncDraw) {
-                if (buffer != mSoftwareBuffer || stride != (mWidth * 2))
-                    return;
-                mSyncDraw = false;
-                try {
-                    mSyncDraws.put(buffer);
-                } catch (InterruptedException ie) {
-                    Log.e(LOG_FILE_NAME, "Threw exception while getting sync bitmaps queue: ", ie);
-                }
-                return;
-            }
-        } finally {
-            mSurfaceLock.unlock();
-        }
-
-        draw(getHolder(), buffer);
-    }
-
-    @Override
-    public boolean onCheckIsTextEditor () {
-        return false;
-    }
-
-    @Override
-    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
-        outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
-        outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE;
-        outAttrs.actionLabel = null;
-        mKeyListener = TextKeyListener.getInstance();
-
-        if (mIMEState == IME_STATE_PASSWORD)
-            outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
-        else if (mIMETypeHint.equalsIgnoreCase("url"))
-            outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_URI;
-        else if (mIMETypeHint.equalsIgnoreCase("email"))
-            outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
-        else if (mIMETypeHint.equalsIgnoreCase("search"))
-            outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
-        else if (mIMETypeHint.equalsIgnoreCase("tel"))
-            outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
-        else if (mIMETypeHint.equalsIgnoreCase("number") ||
-                 mIMETypeHint.equalsIgnoreCase("range"))
-            outAttrs.inputType = InputType.TYPE_CLASS_NUMBER;
-        else if (mIMETypeHint.equalsIgnoreCase("datetime") ||
-                 mIMETypeHint.equalsIgnoreCase("datetime-local"))
-            outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
-                                 InputType.TYPE_DATETIME_VARIATION_NORMAL;
-        else if (mIMETypeHint.equalsIgnoreCase("date"))
-            outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
-                                 InputType.TYPE_DATETIME_VARIATION_DATE;
-        else if (mIMETypeHint.equalsIgnoreCase("time"))
-            outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
-                                 InputType.TYPE_DATETIME_VARIATION_TIME;
-
-        if (mIMEActionHint.equalsIgnoreCase("go"))
-            outAttrs.imeOptions = EditorInfo.IME_ACTION_GO;
-        else if (mIMEActionHint.equalsIgnoreCase("done"))
-            outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE;
-        else if (mIMEActionHint.equalsIgnoreCase("next"))
-            outAttrs.imeOptions = EditorInfo.IME_ACTION_NEXT;
-        else if (mIMEActionHint.equalsIgnoreCase("search"))
-            outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
-        else if (mIMEActionHint.equalsIgnoreCase("send"))
-            outAttrs.imeOptions = EditorInfo.IME_ACTION_SEND;
-        else if (mIMEActionHint != null && mIMEActionHint.length() != 0)
-            outAttrs.actionLabel = mIMEActionHint;
-
-        if (mIMELandscapeFS == false)
-            outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
-
-        inputConnection.reset();
-        return inputConnection;
-    }
-
-    public void setEditable(String contents)
-    {
-        mEditable.removeSpan(inputConnection);
-        mEditable.replace(0, mEditable.length(), contents);
-        mEditable.setSpan(inputConnection, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-        Selection.setSelection(mEditable, contents.length());
-    }
-
-    public void initEditable(String contents)
-    {
-        mEditable = mEditableFactory.newEditable(contents);
-        mEditable.setSpan(inputConnection, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-        Selection.setSelection(mEditable, contents.length());
-    }
-
-    // accelerometer
-    public void onAccuracyChanged(Sensor sensor, int accuracy)
-    {
-    }
-
-    public void onSensorChanged(SensorEvent event)
-    {
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
-    }
-
-    private class GeocoderTask extends AsyncTask<Location, Void, Void> {
-        protected Void doInBackground(Location... location) {
-            try {
-                List<Address> addresses = mGeocoder.getFromLocation(location[0].getLatitude(),
-                                                                    location[0].getLongitude(), 1);
-                // grab the first address.  in the future,
-                // may want to expose multiple, or filter
-                // for best.
-                mLastGeoAddress = addresses.get(0);
-                GeckoAppShell.sendEventToGecko(new GeckoEvent(location[0], mLastGeoAddress));
-            } catch (Exception e) {
-                Log.w(LOG_FILE_NAME, "GeocoderTask "+e);
-            }
-            return null;
-        }
-    }
-
-    // geolocation
-    public void onLocationChanged(Location location)
-    {
-        if (mGeocoder == null)
-            mGeocoder = new Geocoder(getContext(), Locale.getDefault());
-
-        if (mLastGeoAddress == null) {
-            new GeocoderTask().execute(location);
-        }
-        else {
-            float[] results = new float[1];
-            Location.distanceBetween(location.getLatitude(),
-                                     location.getLongitude(),
-                                     mLastGeoAddress.getLatitude(),
-                                     mLastGeoAddress.getLongitude(),
-                                     results);
-            // pfm value.  don't want to slam the
-            // geocoder with very similar values, so
-            // only call after about 100m
-            if (results[0] > 100)
-                new GeocoderTask().execute(location);
-        }
-
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(location, mLastGeoAddress));
-    }
-
-    public void onProviderDisabled(String provider)
-    {
-    }
-
-    public void onProviderEnabled(String provider)
-    {
-    }
-
-    public void onStatusChanged(String provider, int status, Bundle extras)
-    {
-    }
-
-    // event stuff
-    public boolean onTouchEvent(MotionEvent event) {
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
-        return true;
-    }
-
-    @Override
-    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
-        if (event.isSystem())
-            return super.onKeyPreIme(keyCode, event);
-
-        switch (event.getAction()) {
-            case KeyEvent.ACTION_DOWN:
-                return processKeyDown(keyCode, event, true);
-            case KeyEvent.ACTION_UP:
-                return processKeyUp(keyCode, event, true);
-            case KeyEvent.ACTION_MULTIPLE:
-                return onKeyMultiple(keyCode, event.getRepeatCount(), event);
-        }
-        return super.onKeyPreIme(keyCode, event);
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        return processKeyDown(keyCode, event, false);
-    }
-
-    private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_BACK:
-                if (event.getRepeatCount() == 0) {
-                    event.startTracking();
-                    return true;
-                } else {
-                    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:
-            case KeyEvent.KEYCODE_SEARCH:
-                return false;
-            case KeyEvent.KEYCODE_DEL:
-                // See comments in GeckoInputConnection.onKeyDel
-                if (inputConnection != null &&
-                    inputConnection.onKeyDel()) {
-                    return true;
-                }
-                break;
-            case KeyEvent.KEYCODE_ENTER:
-                if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 &&
-                    mIMEActionHint.equalsIgnoreCase("next"))
-                    event = new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB);
-                break;
-            default:
-                break;
-        }
-
-        if (isPreIme && mIMEState != IME_STATE_DISABLED &&
-            (event.getMetaState() & KeyEvent.META_ALT_ON) == 0)
-            // Let active IME process pre-IME key events
-            return false;
-
-        // KeyListener returns true if it handled the event for us.
-        if (mIMEState == IME_STATE_DISABLED ||
-            keyCode == KeyEvent.KEYCODE_ENTER ||
-            keyCode == KeyEvent.KEYCODE_DEL ||
-            (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 ||
-            !mKeyListener.onKeyDown(this, mEditable, keyCode, event))
-            GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
-        return true;
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        return processKeyUp(keyCode, event, false);
-    }
-
-    private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_BACK:
-                if (!event.isTracking() || event.isCanceled())
-                    return false;
-                break;
-            default:
-                break;
-        }
-
-        if (isPreIme && mIMEState != IME_STATE_DISABLED &&
-            (event.getMetaState() & KeyEvent.META_ALT_ON) == 0)
-            // Let active IME process pre-IME key events
-            return false;
-
-        if (mIMEState == IME_STATE_DISABLED ||
-            keyCode == KeyEvent.KEYCODE_ENTER ||
-            keyCode == KeyEvent.KEYCODE_DEL ||
-            (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 ||
-            !mKeyListener.onKeyUp(this, mEditable, keyCode, event))
-            GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
-        return true;
-    }
-
-    @Override
-    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
-        return true;
-    }
-
-    @Override
-    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_BACK:
-                GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
-                return true;
-            case KeyEvent.KEYCODE_MENU:
-                InputMethodManager imm = (InputMethodManager)
-                    getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-                imm.toggleSoftInputFromWindow(getWindowToken(),
-                                              imm.SHOW_FORCED, 0);
-                return true;
-            default:
-                break;
-        }
-        return false;
-    }
-
-    // Is this surface valid for drawing into?
-    boolean mSurfaceValid;
-
-    // Are we actively between beginDrawing/endDrawing?
-    boolean mInDrawing;
-
-    // Used to finish the current buffer before changing the surface size
-    boolean mDrawSingleFrame = false;
-    boolean mAbortDraw = false;
-
-    // Are we waiting for a buffer to draw in surfaceChanged?
-    boolean mSyncDraw;
-
-    // True if gecko requests a buffer
-    int mDrawMode;
-
-    static boolean mShowingSplashScreen = true;
-    static String  mSplashURL = "";
-
-    // let's not change stuff around while we're in the middle of
-    // starting drawing, ending drawing, or changing surface
-    // characteristics
-    ReentrantLock mSurfaceLock;
-
-    // Surface format, from surfaceChanged.  Largely
-    // useless.
-    int mFormat;
-
-    // the dimensions of the surface
-    int mWidth;
-    int mHeight;
-
-    // the dimensions of the buffer we're using for drawing,
-    // that is the software buffer or the EGLSurface
-    int mBufferWidth;
-    int mBufferHeight;
-
-    // IME stuff
-    public static final int IME_STATE_DISABLED = 0;
-    public static final int IME_STATE_ENABLED = 1;
-    public static final int IME_STATE_PASSWORD = 2;
-    public static final int IME_STATE_PLUGIN = 3;
-
-    GeckoInputConnection inputConnection;
-    KeyListener mKeyListener;
-    Editable mEditable;
-    Editable.Factory mEditableFactory;
-    int mIMEState;
-    String mIMETypeHint;
-    String mIMEActionHint;
-    boolean mIMELandscapeFS;
-
-    // Software rendering
-    Bitmap mSoftwareBitmap;
-    ByteBuffer mSoftwareBuffer;
-    Bitmap mSoftwareBufferCopy;
-
-    Geocoder mGeocoder;
-    Address  mLastGeoAddress;
-
-    final SynchronousQueue<Object> mSyncDraws = new SynchronousQueue<Object>();
-}
-
deleted file mode 100644
--- a/embedding/android/SurfaceInfo.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.mozilla.gecko;
-
-public class SurfaceInfo {
-    public int format;
-    public int width;
-    public int height;
-}
new file mode 100644
--- /dev/null
+++ b/mobile/android/LICENSE
@@ -0,0 +1,1333 @@
+This code may be used and redistributed under your choice of:
+
+    * Mozilla Public License, version 1.1 or later
+    * GNU General Public License, version 2.0 or later
+    * GNU Lesser General Public License, version 2.1 or later
+
+The terms of these licenses are included here for reference:
+
+                          MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ---------------
+
+1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+     ``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 ______________________________________.
+
+     The Initial Developer of the Original Code is ________________________.
+     Portions created by ______________________ are Copyright (C) ______
+     _______________________. All Rights Reserved.
+
+     Contributor(s): ______________________________________.
+
+     Alternatively, the contents of this file may be used under the terms
+     of the _____ license (the  "[___] License"), in which case the
+     provisions of [______] License are applicable instead of those
+     above.  If you wish to allow use of your version of this file only
+     under the terms of the [____] License and not to allow others to use
+     your version of this file under the MPL, indicate your decision by
+     deleting  the provisions above and replace  them with the notice and
+     other provisions required by the [___] License.  If you do not delete
+     the provisions above, a recipient may use your version of this file
+     under either the MPL or the [___] License."
+
+     [NOTE: The text of this Exhibit A may differ slightly from the text of
+     the notices in the Source Code files of the Original Code. You should
+     use the text of this Exhibit A rather than the text found in the
+     Original Code Source Code for Your Modifications.]
+
+
+
+
+
+
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+
+
+
+
+
+
+
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
new file mode 100644
--- /dev/null
+++ b/mobile/android/Makefile.in
@@ -0,0 +1,58 @@
+# ***** 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.
+#
+# The Initial Developer of the Original Code is
+# the Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Mark Finkle <mfinkle@mozilla.com>
+#   Joel Maher <jmaher@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 *****
+
+DEPTH      = ../..
+topsrcdir  = @top_srcdir@
+srcdir     = @srcdir@
+VPATH      = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = base chrome locales components modules themes/core app
+
+ifndef LIBXUL_SDK
+PARALLEL_DIRS += $(DEPTH)/xulrunner/tools/redit
+endif
+
+include $(topsrcdir)/config/rules.mk
+include $(topsrcdir)/testing/testsuite-targets.mk
+
+package-mobile-tests:
+	$(MAKE) stage-mochitest DIST_BIN=$(DEPTH)/$(DIST)/bin/xulrunner
+	$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
+	@(cd $(PKG_STAGE) && tar $(TAR_CREATE_FLAGS) - *) | bzip2 -f > $(DIST)/$(PKG_PATH)$(TEST_PACKAGE)
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/Makefile.in
@@ -0,0 +1,171 @@
+# ***** 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.
+#
+# The Initial Developer of the Original Code is
+# the Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   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 *****
+
+DEPTH     = ../../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = profile/extensions
+
+PREF_JS_EXPORTS = $(srcdir)/mobile.js
+DIST_FILES = recommended-addons.json
+
+ifndef LIBXUL_SDK
+ifneq (Android,$(OS_TARGET))
+PROGRAM=$(MOZ_APP_NAME)$(BIN_SUFFIX)
+
+LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
+LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
+LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/build
+LOCAL_INCLUDES += -I$(DEPTH)/build
+
+DEFINES += -DXPCOM_GLUE
+STL_FLAGS=
+
+LIBS += \
+  $(EXTRA_DSO_LIBS) \
+  $(XPCOM_STANDALONE_GLUE_LDOPTS) \
+  $(NULL)
+
+ifeq ($(MOZ_PLATFORM_MAEMO),6)
+LIBS += \
+  $(LIBXUL_DIST)/../widget/src/qt/faststartupqt/$(LIB_PREFIX)faststartupqt.$(LIB_SUFFIX) \
+  $(MOZ_QT_LIBS) \
+  $(NULL)
+LOCAL_INCLUDES += -I$(topsrcdir)/widget/src/qt/faststartupqt $(TK_CFLAGS)
+endif
+
+ifeq ($(OS_ARCH),WINNT)
+OS_LIBS += $(call EXPAND_LIBNAME,version)
+endif
+
+ifdef _MSC_VER
+# Always enter a Windows program through wmain, whether or not we're
+# a console application.
+WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
+endif
+endif
+endif #LIBXUL_SDK
+
+# Make sure the standalone glue doesn't try to get libxpcom.so from mobile/app.
+NSDISTMODE = copy
+
+include $(topsrcdir)/config/rules.mk
+
+APP_ICON = mobile
+
+DEFINES += \
+  -DAPP_NAME=$(MOZ_APP_NAME) \
+  -DAPP_VERSION=$(MOZ_APP_VERSION) \
+  -DMOZ_UPDATER=$(MOZ_UPDATER) \
+  $(NULL)
+
+ifeq ($(OS_ARCH),WINNT)
+REDIT_PATH = $(LIBXUL_DIST)/bin
+endif
+
+APP_BINARY = $(MOZ_APP_NAME)$(BIN_SUFFIX)
+
+ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
+
+APP_NAME = $(MOZ_APP_DISPLAYNAME)
+APP_VERSION = $(MOZ_APP_VERSION)
+
+ifdef MOZ_DEBUG
+APP_NAME := $(APP_NAME)Debug
+endif
+
+AB_CD = $(MOZ_UI_LOCALE)
+
+AB := $(firstword $(subst -, ,$(AB_CD)))
+
+clean clobber repackage::
+	rm -rf $(DIST)/$(APP_NAME).app
+
+ifdef LIBXUL_SDK
+APPFILES = Resources
+else
+APPFILES = MacOS
+endif
+
+libs repackage::
+	mkdir -p $(DIST)/$(APP_NAME).app/Contents/MacOS
+	rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents $(DIST)/$(APP_NAME).app --exclude English.lproj
+	mkdir -p $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj
+	rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj
+	sed -e "s/%APP_VERSION%/$(APP_VERSION)/" -e "s/%APP_NAME%/$(APP_NAME)/" -e "s/%APP_BINARY%/$(APP_BINARY)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(DIST)/$(APP_NAME).app/Contents/Info.plist
+	sed -e "s/%APP_VERSION%/$(APP_VERSION)/" -e "s/%APP_NAME%/$(APP_NAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj/InfoPlist.strings
+	rsync -a $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
+	$(RM) $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/mangle $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/shlibsign
+ifdef LIBXUL_SDK
+	cp $(LIBXUL_DIST)/bin/xulrunner$(BIN_SUFFIX) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(APP_BINARY)
+	rsync -a --exclude nsinstall --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(DIST)/$(APP_NAME).app/Contents/Frameworks
+else
+	rm -f $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM)
+	rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS
+endif
+	printf "APPLMOZB" > $(DIST)/$(APP_NAME).app/Contents/PkgInfo
+
+else # MOZ_WIDGET_TOOLKIT != cocoa
+
+libs::
+ifdef LIBXUL_SDK
+	cp $(LIBXUL_DIST)/bin/xulrunner-stub$(BIN_SUFFIX) $(DIST)/bin/$(APP_BINARY)
+endif
+ifndef SKIP_COPY_XULRUNNER
+ifdef LIBXUL_SDK
+	$(NSINSTALL) -D $(DIST)/bin/xulrunner
+	(cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -)
+endif
+endif # SKIP_COPY_XULRUNNER
+
+ifeq ($(MOZ_PLATFORM_MAEMO),6)
+	$(NSINSTALL) -D $(DIST)/bin/res/drawable
+	cp $(topsrcdir)/mobile/app/maemo/* $(DIST)/bin/res/drawable/
+	cp $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/favicon32.png $(DIST)/bin/res/drawable/
+endif
+	$(NSINSTALL) -D $(DIST)/bin/chrome/icons/default
+
+ifeq ($(OS_ARCH),WINNT)
+	cp $(srcdir)/$(APP_ICON).ico $(DIST)/bin/chrome/icons/default/$(APP_ICON).ico
+	$(REDIT_PATH)/redit$(HOST_BIN_SUFFIX) $(DIST)/bin/$(APP_BINARY) $(srcdir)/$(APP_ICON).ico
+endif
+
+endif
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..06a33376ae618913d5bf2ecbed646e0016353fd0
GIT binary patch
literal 1667
zc%17D@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SBuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFsEgPM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnmCL5R;D3}@Q85*0I
zo15z>7#SEE=o=X68ye{vnp+tgSs558K!Fm_wxX0Ys~{IQs9ivwtx`rwNr9EVetCJh
zUb(Seeo?x<p{1oI$P6PRU7!lx;>x^|#0uTKVr7^KE~&-IMVSR9nfZANAbw&}erbuV
zk`l}dxdpzyaD(%Tp#cR9GX09g0)0b01O41weVFRvlAzQy{HlvXDhpEegHnt0ON)|$
z@sXyCWEFm`Aca8JSos%a0wX0c$0a|xG&eP`#M8xA2`HnNl9^&<U}RxnXlQO?U~Xh!
zW?^V(X=q?+>FDHYW^CkQYH45yGXtAm7ehBAV^bqbOA}*9Lqiug3v*WsXJc1GS2tG^
zOIJ4&m|oAk;*!L?<W!j6OoUzwyn3yii&7Iy@{2<9^K)P+ARr^ZB)>Q#zd*q`*i^wc
zF*!32#0NzW)TOCKnPsUdZbkXI3gGay%EV&7fiWR}L-eMQ6K48A$LOOa7MKt)1%jCH
zqz~l4Gf!$BFvk=Dv&J6TqGARHrp=x%jv*Dd-pttB{m4P&fO?%fH>>@}1a3#2HM%Yv
zHf_7*6jp8h-6G{9*XzlL>kq_<cduQuHb>_V_mRAZE|1v5j=jHQb5J$QXr{|!x#M;c
zPR|~n)z5#n*Id|5faQxm*Jsu;-UzL!n+jyUcR&B>{^wVLdRzIl)cZAd_s^H@-fI^&
z>xeB6+u{8E_y6};EAGDA*W<Q$oy+dKe7a)Y>^VL1JckdY+*ds~$M5;%t68=Vjc>kJ
zM=m{?BJ{LqXZNqFy?s`5`R*1O@)TLfa7Z(+4O^{lIK%PI#iWfDg^su1hHdn4Y;>@V
zV6yAlc3_Ud_K5SHM;Bbyozs|-dCO2d;ltMLH>|HWNuCqEG%d$W+mi9h>Wj*Ho5Uu+
zD&Wud>{V`hxTEdU&poR+XPsS^QoA<H*}^ZdIaX)sjn7w{CbE=F+!OPC>6Kk)TsE9d
zE9R)G;(W0@_p)kC#zqOlzJpP(GYv2J-*#hVtNf_(vP4R>`{?QeM|N(BTDvH0btz+6
z(VNbrNlhnHg61r^{r29KNgpfzFkE~6RU&fzm10fL>i!o~m)I^?E|V-N_{O;JmVlOs
z?l;MVu8IF;attJ7<~=O<u~={N$qY7&SC+3>HK(60(e(5>(v>He;Jk3ct|=@}wk$s%
zw6aC2x9v&gnxK^{{5+q3o_A!UgMz|?*_V$0F0hyqD#F8-di%+-iN_djWSAtS=&G?@
zo)x#HC(!2e<*KFAQv9Wg?bbg#VL#Vz;_0WmR?I*D+?-K4&W)>;DO79X?tl)~l9fAq
z=H%2(OJ&`Bb4|wD&+CQvPrmhpg^%ySMw|1-lM>8k_kOOhx%aW6=K6{EU#l*r7)k0+
z_n!YmuG?+#`n>JGC7HC27iR2@d(FkNpX~uVUkb~f^!QYBd$syb7bT5}9yUqpKg#&C
uABz4qo_+S-ufP9JUzb1nU+B$x24)7^%_VksCk4xZss&G1KbLh*2~7aWsC`!e
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5b3daa54517886abfb729531a627b8edbe98b7ac
GIT binary patch
literal 1657
zc%17D@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SBuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFsEgPM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnmCL5R;D3}@Q85*0I
zo15z>7#SEE=o=X68ye{vnp+tgSs558K!Fm_wxX0Ys~{IQs9ivwtx`rwNr9EVetCJh
zUb(Seeo?x<p{1oI$P6PRU7!lx;>x^|#0uTKVr7^KE~&-IMVSR9nfZANAbw&}erbuV
zk`l}dxdpzyaD(%Tp#cR9GX09g0)0b01O41weVFRvlAzQy{HlvXDhpEegHnt0ON)|$
z@sXyCWEFm`Aca8JSos%a0wX0c$0a|xG&eP`#M8xA2`HnNl9^&<U}RxnXlQO?U~Xh!
zW?^V(X=q?+>FDHYW^CkQYH45yGXtAm7ehBAV^bqjOA}*9Lqiug3v*WsXJc1GS2tG^
zOIJ4&m|oAk;*!L?<W!j6OoUz&yn3yii&7Iy@{2<9^K)P+ARr^ZB)>Q#zd*q`*i^wc
zF*!32#0NzW)TOCKnPsUdZbkXI3gGay%EV&7fiWR}L-eMQ6K48A$LOOa7MKt)1%jCH
zqz~l4Gf!$BFvk=Dv&Q;`YkxB^Fs<}-aSW-r^=8J&u2&8sZQ6Yn3l_MsE-ZiKB=hZ^
zi(?E&lfo8-A1u0iGj{kFJX}}P756pD<!E|AOvi3E$43lJ8htOVoDQ7xO;Y8%ae<vr
zX!R?5`Q?7Av|Kmpbjw`~dExjr@u10a{*4hn#|_ThznV4mV84HP(hm~}9(ljzpZ)j7
z-REdp8M3NgZ~AN2awoUNf-A4Snl1G9d-awWz4--3ahhFC39gO?tFQiAbNzLHKtlWB
zhszQq*k<~uwM=fj_WJ8)jTwH+7jImAH_u&X&63`H0paz0TQYhb+dQWCCvEI-S~wwP
ze%R_(ucbm0<?74+F*jGLZ!8Xokq@%<G!Re}ofQ1Q>(}3=SRS`uZj+=|-aCKhM%nJE
zTmMav$k2MZykh5$vSTXKxmUDb?lG0>?LN5b>Z*)r6DiTPuAUpBZ)@_%`y74GQGB*?
zVZaVak&OArCb2xe=XI`nuiUBUpTpakd@npZKKYEq{oQx<PCYFOZ)VcHAkyV(Gj-1P
z+qqNDrs=ma@m>(>DirfM<7hDXq()oQ#s!L^&VmvabJkyaxg|$Kf;sv8OJVW-6Pz1D
zv|M>uYZG}ozik)(@Urvj<BuDDG`DCZC<r(_EsEUaZ#2_ou3vk_Q+dAjDGD=gzg1&n
z=4NYN5wwzHo2pP}vhPHxhF&-2M1%IjirhWccGt7E=KnwX_~YX*Ck+{9`=}jCFq_>Q
zx=EE$X8Za>|J22~cr4O3&oq$uw=QMsyQvQge*CzdV<y_m-uJUck0;G+_RZ?NM>QLc
zCOLM_OV}EvJF(-&=8)MhSi9VmYu_AHO71@D)PMZ(?lkV}W+MM0M9#ebzW?^yZ_^JZ
zG)S~L&OZBWnL~jogSbW9dU4<7m&*eUW-Ys4V<+F`q9hrUJ<s~;HG%!T@_+08`<6WY
hzc=vD$%J?&9)=o*)QY`Z=dS`)2A-~dF6*2Ung9vHZ^!@u
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9d0a35c192cdcb574d574fe1bf6a326e156046a0
GIT binary patch
literal 1432
zc$}S74NMbf7%oZ{Bq7>513Dp>gUH6D_tXD_!b-2D1<Ocjlo`@++#U3U-j(Y?3q}&%
z7|~@qC9-S`r!p6r8yX`S3<y6%a6tl2nK}Z?%-jOZEwF{5j=4LeWLXSL_9b`sz2Emf
z&-;Ieb8|AIBDY1#WU?r`4R?y)t<n?mocJD?t|cWwu;dGQT(J-!cv@znxFQ;`dx;X-
zNfT66`B!wROt!w5apep7j$IhZd6k5uqYQd|GHIoz2Ym!tN((>{UBa+N@Yl{B5MU@H
zxJToF9X>PdVQkeromZXXBCAVD0|ln10jWVuB=FJ#0R+8etRD*+!DU`d+)Kw02rR1z
zrAF|nQ~8cuz|8S9pi#ofB&>x2EuutJYMoBE6F^}EhF}yz&}2l1sZb1tft3Y{)_AHI
zbK=$&TcTtHJ%ZrFASe(BC<7`b$Cp5e!C;U$P&8T8NcLB;0ufAR{qZ3Noc5DE;}aN;
z1tgg$;wl6q2!=xN`W%i`V%EQsC^2PFknll>5{A59D5UKdoOJQp+J0A+kA|GIpR3?W
zu^z?o|1h;SR8kbZ!CvJVu_#0t&XE;fnicH05fpEf6hmRKS`Q<LP7Ui&SgS`60|FZi
zrVNW#h2k0mjD$Fzh0Vy&<FM8O8`LTjg5XxY&Z0M~EQrNwQ5!5)bqH%`{Q|*~bO_6=
zVsY!5Sj^1RguwAGjw=gwK(2=qIKPMU0p>gn;2=nbm1L<rE1uFkQ%O@+p7R3B`Nf!L
z*oQU$757st^?z~(iOxX(YL?KE*n!e^we>||b$Do2oETmljoJ<)E0cv?v*RXL@Y`Fv
zyN~q0vS|vpyl^-o>*(yREjxc6$VeUg<5HHp_g>sRx9NM}By`5tP(l+eZ%3H=1_z(C
z*OOnemm3F$C;JY-)KJqTS5sMXa{G{}Cu-|b*w@t9zBaeEab)5_<%PtBf`;_r`}4CD
z`moRzS=)cfmDF;zNKT{gahpFFEx9uBU}iC8U}m%V?2AX<AHJVzPJgtN*4+5<O9|^T
zH`cwr%@&<g|8lvU&K})g+f$%q!@=pw&M7da?(U)9nuE5&b<x*j16V8-^X6Fg@a32T
zaLnl&p6Aay0L9{*fOROWz3cDPx8WYe4u$=MqABV4FUMv36^plTR`2~`!|6%3^Sim=
z_P5@+(}xiWA05*)j?~4UiIsm7z9X(9k<iB-yDo2F6yVM2TU*W!nLgWX{;RuPGna`r
zj>IK(wa%WZ>2^Py&N}Dpcc>lY?_yxpU$iG|+F+Dd;LSfyf9jiv+<0L;vSnru+2&1|
zN3Ggx?u&_C<6V!#7l<e)7>NIHH05sD!qBM#{ovyz_k8-^(m&BO=-uqr&&$Iu?mOo+
ziCK(2Z*RT<e=<IkqIK3=4>n!->9-EK?RL+TY$3W(W-NH^ovBAhuS)+)yCny2%_uzd
EHwtVCcmMzZ
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a604e27e79089a1b5e3dd8f35620ef23e1136a9b
GIT binary patch
literal 1448
zc%17D@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAnN?apKg7ec#$`gxH85~pclTsBt
za}(23gHjVyDhp4h+AuIMr)7pjltlRYSS9D@>Lr5I=vCwvFo1xKeMLcHa&~HoLQ-ma
zW}dCm``!DM6f#q6mBLMZ4SWlnQ!_F>s)|yBtNcQetFn_VQ<UuO6l^N2fCl8ImLw`v
z<mTiRTUFR9fz7o7vO&W7N(x{lCE2!05JyG$1}He^7o{qg>KW)J8<-g=m>KFB8k?A#
zo9ieT85kPq8yM*u8tEFETNxW!85k%)ffCTRqLehNAQv~NT|l0#QbtKhft9{~d3m{B
zxv^e;QM$gNrKKgv3?n05pbFjM%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;eqvI7X^E|p
z63h#^1-`y;gY$}^0R;>){ffi_eM3D1{oGuAnCjw^pwu+{s*6J^3sUuiQj7CTi;{uy
zk*17f6@INCg+SL>`4?pZBPB7%B|o_|H#M)s)5TT^D5IB>nPO#NVqsutXl`O)Ze(C)
zVQ6S+XkcmS=;Uf<Y~*5UX<!I51DjqaCkqz?GZ$w|6Jtk1Ll-v-b5{#zV^>30H&+u&
zS2q)wUeCPZlEl2^RG8jOgkC4Sdaay`QWHz^i$e1Ab6_bTAS1sdzc?emK*2fKRKYhf
zIWrH$2SpFmrKv@kWvMA{Mftf3;PAD|#A3gJDItGD^rny#X8J(K=%XbTm=G`pf|&56
z59GizPih`8#}omx#+Hf3dJGJVH#}V&Ln>}vnYOp<kb^*jy5mJR5yz7gL$)m{OM2Sa
z+S&^O*QR|J2>-=&{TGXp*rCX{$MW04IAyrZ%>F&xrR=h4`^_hl9vtM=nN^s!@9x|)
zJwl2s^K^~=G`5`4e_Hgjbo0$U@$0WAJ(zp?Q@GXKy4gNz^LbPzdVC39Ic1WMnxYKf
zZ?-w-({H>jbNzL5dA~l7id?_;#f&eB5-tUc+YdWFT-P0Ux%Q^#_S>ya3lF?}{@L<N
zm2I?q_8RslMLRkC6W9&DD#`a8cf2q|?Myh|oi98tlT^-6xcu@<O~>-d9c53xtAy3Q
zP_ML+t8U_HclHZk88Tz?i7=yeWxHipxLvs4lge!=*S{e`XTjC1pG*tne<jN(9*K!a
zIh%G_nBnck^HS~24`icw(>6<*NcF}uUf_GX_Ftdn#&s`CxV~216>QkQc<$W&nv*QI
zgoLUt>N@|l$UuU}qIPXq^V1^DH?eJr9y~4I>K|PR`}EVM$8GWP;;m78)gx6n7Jlw*
zz3|QFj+UIX(lx<rjA}PM4fN(}>!^rzPxMfEG%JN=Cu6_|(|hl~>$qGtnd|3Px;Ktp
zD#{|%cqUKI_GstprM;QjOM_NUKAUF0VxmyVvCF=7>%&&_eJ}g_d%uf0BOAkfMTZkB
TCQm#MDmy)0{an^LB{Ts5b7u|@
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/macbuild/Contents/Info.plist.in
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleDocumentTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeExtensions</key>
+			<array>
+				<string>html</string>
+				<string>htm</string>
+				<string>shtml</string>
+				<string>xht</string>
+				<string>xhtml</string>
+			</array>
+			<key>CFBundleTypeIconFile</key>
+			<string>document.icns</string>
+			<key>CFBundleTypeName</key>
+			<string>HTML Document</string>
+			<key>CFBundleTypeOSTypes</key>
+			<array>
+				<string>HTML</string>
+			</array>
+			<key>CFBundleTypeRole</key>
+			<string>Viewer</string>
+		</dict>
+		<dict>
+			<key>CFBundleTypeExtensions</key>
+			<array>
+			    <string>text</string>
+				<string>txt</string>
+				<string>js</string>
+				<string>log</string>
+				<string>css</string>
+				<string>xul</string>
+				<string>rdf</string>
+			</array>
+			<key>CFBundleTypeIconFile</key>
+			<string>document.icns</string>
+			<key>CFBundleTypeName</key>
+			<string>Text Document</string>
+			<key>CFBundleTypeOSTypes</key>
+			<array>
+				<string>TEXT</string>
+				<string>utxt</string>
+			</array>
+			<key>CFBundleTypeRole</key>
+			<string>Viewer</string>
+		</dict>
+		<dict>
+			<key>CFBundleTypeExtensions</key>
+			<array>
+				<string>jpeg</string>
+				<string>jpg</string>
+				<string>png</string>
+				<string>gif</string>
+			</array>
+			<key>CFBundleTypeIconFile</key>
+			<string>fileBookmark.icns</string>
+			<key>CFBundleTypeName</key>
+			<string>document.icns</string>
+			<key>CFBundleTypeOSTypes</key>
+			<array>
+				<string>GIFf</string>
+				<string>JPEG</string>
+				<string>PNGf</string>
+			</array>
+			<key>CFBundleTypeRole</key>
+			<string>Viewer</string>
+		</dict>
+	</array>
+	<key>CFBundleExecutable</key>
+	<string>fennec</string>
+	<key>CFBundleGetInfoString</key>
+	<string>%APP_NAME% %APP_VERSION%</string>
+	<key>CFBundleIconFile</key>
+	<string>fennec</string>
+	<key>CFBundleIdentifier</key>
+	<string>org.mozilla.fennec</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>%APP_NAME%</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>%APP_VERSION%</string>
+	<key>CFBundleSignature</key>
+	<string>MOZB</string>
+	<key>CFBundleURLTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleURLIconFile</key>
+			<string>document.icns</string>
+			<key>CFBundleURLName</key>
+			<string>http URL</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>http</string>
+			</array>
+		</dict>
+		<dict>
+			<key>CFBundleURLIconFile</key>
+			<string>document.icns</string>
+			<key>CFBundleURLName</key>
+			<string>https URL</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>https</string>
+			</array>
+		</dict>
+		<dict>
+			<key>CFBundleURLName</key>
+			<string>ftp URL</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>ftp</string>
+			</array>
+		</dict>
+		<dict>
+			<key>CFBundleURLName</key>
+			<string>file URL</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>file</string>
+			</array>
+		</dict>
+	</array>
+	<key>CFBundleVersion</key>
+	<string>%APP_VERSION%</string>
+	<key>NSAppleScriptEnabled</key>
+	<true/>
+	<key>CGDisableCoalescedUpdates</key>
+	<true/>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in
@@ -0,0 +1,1 @@
+CFBundleName = "%APP_NAME%";
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..331fa75db266faf47e13364e0f7d808b13699efe
GIT binary patch
literal 1965
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..38312abac42830818edef700470cf1c59b25bb81
GIT binary patch
literal 4286
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
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/mobile.js
@@ -0,0 +1,691 @@
+/* ***** 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):
+ *   Matt Brubeck <mbrubeck@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 ***** */
+
+#filter substitution
+
+// For browser.xml binding
+//
+// cacheRatio* is a ratio that determines the amount of pixels to cache. The
+// ratio is multiplied by the viewport width or height to get the displayport's
+// width or height, respectively.
+//
+// (divide integer value by 1000 to get the ratio)
+//
+// For instance: cachePercentageWidth is 1500
+//               viewport height is 500
+//               => display port height will be 500 * 1.5 = 750
+//
+pref("toolkit.browser.cacheRatioWidth", 2000);
+pref("toolkit.browser.cacheRatioHeight", 3000);
+
+// How long before a content view (a handle to a remote scrollable object)
+// expires.
+pref("toolkit.browser.contentViewExpire", 3000);
+
+pref("toolkit.defaultChromeURI", "chrome://browser/content/browser.xul");
+pref("general.useragent.compatMode.firefox", true);
+pref("browser.chromeURL", "chrome://browser/content/");
+
+pref("browser.tabs.warnOnClose", true);
+pref("browser.tabs.remote", true);
+
+pref("toolkit.screen.lock", false);
+
+// From libpref/src/init/all.js, extended to allow a slightly wider zoom range.
+pref("zoom.minPercent", 20);
+pref("zoom.maxPercent", 400);
+pref("toolkit.zoomManager.zoomValues", ".2,.3,.5,.67,.8,.9,1,1.1,1.2,1.33,1.5,1.7,2,2.4,3,4");
+
+// Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
+pref("browser.viewport.scaleRatio", -1);
+pref("browser.viewport.desktopWidth", 980);
+
+#ifndef ANDROID
+#ifndef MOZ_PLATFORM_MAEMO
+// On desktop builds, simulate an MDPI tablet by default.
+pref("layout.css.dpi", 160);
+#else
+// Maemo X11 lies about its dpi
+pref("layout.css.dpi", 240);
+#endif
+#endif
+/* allow scrollbars to float above chrome ui */
+pref("ui.scrollbarsCanOverlapContent", 1);
+
+/* cache prefs */
+pref("browser.cache.disk.enable", true);
+pref("browser.cache.disk.capacity", 10240); // kilobytes
+pref("browser.cache.disk.smart_size.enabled", false);
+pref("browser.cache.disk.smart_size.first_run", false);
+
+pref("browser.cache.memory.enable", true);
+pref("browser.cache.memory.capacity", 1024); // kilobytes
+
+/* image cache prefs */
+pref("image.cache.size", 1048576); // bytes
+
+/* offline cache prefs */
+pref("browser.offline-apps.notify", true);
+pref("browser.cache.offline.enable", true);
+pref("browser.cache.offline.capacity", 5120); // kilobytes
+pref("offline-apps.quota.max", 2048); // kilobytes
+pref("offline-apps.quota.warn", 1024); // kilobytes
+
+/* protocol warning prefs */
+pref("network.protocol-handler.warn-external.tel", false);
+pref("network.protocol-handler.warn-external.mailto", false);
+pref("network.protocol-handler.warn-external.vnd.youtube", false);
+
+/* http prefs */
+pref("network.http.pipelining", true);
+pref("network.http.pipelining.ssl", true);
+pref("network.http.proxy.pipelining", true);
+pref("network.http.pipelining.maxrequests" , 6);
+pref("network.http.keep-alive.timeout", 600);
+pref("network.http.max-connections", 6);
+pref("network.http.max-connections-per-server", 4);
+pref("network.http.max-persistent-connections-per-server", 4);
+pref("network.http.max-persistent-connections-per-proxy", 4);
+#ifdef MOZ_PLATFORM_MAEMO
+pref("network.autodial-helper.enabled", true);
+#endif
+
+// See bug 545869 for details on why these are set the way they are
+pref("network.buffer.cache.count", 24);
+pref("network.buffer.cache.size",  16384);
+
+/* history max results display */
+pref("browser.display.history.maxresults", 100);
+
+/* How many times should have passed before the remote tabs list is refreshed */
+pref("browser.display.remotetabs.timeout", 10);
+
+/* session history */
+pref("browser.sessionhistory.max_total_viewers", 1);
+pref("browser.sessionhistory.max_entries", 50);
+
+/* session store */
+pref("browser.sessionstore.resume_session_once", false);
+pref("browser.sessionstore.resume_from_crash", true);
+pref("browser.sessionstore.resume_from_crash_timeout", 60); // minutes
+pref("browser.sessionstore.interval", 10000); // milliseconds
+pref("browser.sessionstore.max_tabs_undo", 1);
+
+/* these should help performance */
+pref("mozilla.widget.force-24bpp", true);
+pref("mozilla.widget.use-buffer-pixmap", true);
+pref("mozilla.widget.disable-native-theme", true);
+pref("layout.reflow.synthMouseMove", false);
+
+/* download manager (don't show the window or alert) */
+pref("browser.download.useDownloadDir", true);
+pref("browser.download.folderList", 1); // Default to ~/Downloads
+pref("browser.download.manager.showAlertOnComplete", false);
+pref("browser.download.manager.showAlertInterval", 2000);
+pref("browser.download.manager.retention", 2);
+pref("browser.download.manager.showWhenStarting", false);
+pref("browser.download.manager.closeWhenDone", true);
+pref("browser.download.manager.openDelay", 0);
+pref("browser.download.manager.focusWhenStarting", false);
+pref("browser.download.manager.flashCount", 2);
+pref("browser.download.manager.displayedHistoryDays", 7);
+
+/* download alerts (disabled above) */
+pref("alerts.slideIncrement", 1);
+pref("alerts.slideIncrementTime", 10);
+pref("alerts.totalOpenTime", 6000);
+pref("alerts.height", 50);
+
+/* download helper */
+pref("browser.helperApps.deleteTempFileOnExit", false);
+
+/* password manager */
+pref("signon.rememberSignons", true);
+pref("signon.expireMasterPassword", false);
+pref("signon.SignonFileName", "signons.txt");
+pref("signon.debug", false);
+
+/* form helper */
+// 0 = disabled, 1 = enabled, 2 = dynamic depending on screen size
+pref("formhelper.mode", 2);
+pref("formhelper.autozoom", true);
+pref("formhelper.autozoom.caret", true);
+pref("formhelper.restore", false);
+
+/* find helper */
+pref("findhelper.autozoom", true);
+
+/* autocomplete */
+pref("browser.formfill.enable", true);
+
+/* spellcheck */
+pref("layout.spellcheckDefault", 0);
+
+/* extension manager and xpinstall */
+pref("xpinstall.whitelist.add", "addons.mozilla.org");
+
+pref("extensions.enabledScopes", 1);
+pref("extensions.autoupdate.enabled", true);
+pref("extensions.autoupdate.interval", 86400);
+pref("extensions.update.enabled", false);
+pref("extensions.update.interval", 86400);
+pref("extensions.dss.enabled", false);
+pref("extensions.dss.switchPending", false);
+pref("extensions.ignoreMTimeChanges", false);
+pref("extensions.logging.enabled", false);
+pref("extensions.hideInstallButton", true);
+pref("extensions.showMismatchUI", false);
+pref("extensions.hideUpdateButton", false);
+
+pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%");
+
+/* preferences for the Get Add-ons pane */
+pref("extensions.getAddons.cache.enabled", true);
+pref("extensions.getAddons.maxResults", 15);
+pref("extensions.getAddons.recommended.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/recommended/");
+pref("extensions.getAddons.recommended.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/list/featured/all/%MAX_RESULTS%/%OS%/%VERSION%");
+pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/search?q=%TERMS%");
+pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%");
+pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/mobile/");
+pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/guid:%IDS%?src=mobile&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
+
+/* preference for the locale picker */
+pref("extensions.getLocales.get.url", "");
+pref("extensions.compatability.locales.buildid", "0");
+
+/* blocklist preferences */
+pref("extensions.blocklist.enabled", true);
+pref("extensions.blocklist.interval", 86400);
+pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
+pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
+
+/* block popups by default, and notify the user about blocked popups */
+pref("dom.disable_open_during_load", true);
+pref("privacy.popups.showBrowserMessage", true);
+
+pref("keyword.enabled", true);
+pref("keyword.URL", "http://www.google.com/m?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q=");
+
+pref("accessibility.typeaheadfind", false);
+pref("accessibility.typeaheadfind.timeout", 5000);
+pref("accessibility.typeaheadfind.flashBar", 1);
+pref("accessibility.typeaheadfind.linksonly", false);
+pref("accessibility.typeaheadfind.casesensitive", 0);
+// zoom key(F7) conflicts with caret browsing on maemo
+pref("accessibility.browsewithcaret_shortcut.enabled", false);
+
+// Whether or not we show a dialog box informing the user that the update was
+// successfully applied.
+pref("app.update.showInstalledUI", false);
+
+// Whether the character encoding menu is under the main Firefox button. This
+// preference is a string so that localizers can alter it.
+pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties");
+pref("intl.charsetmenu.browser.static", "chrome://browser/locale/browser.properties");
+
+// pointer to the default engine name
+pref("browser.search.defaultenginename", "chrome://browser/locale/region.properties");
+// SSL error page behaviour
+pref("browser.ssl_override_behavior", 2);
+pref("browser.xul.error_pages.expert_bad_cert", false);
+
+// disable logging for the search service by default
+pref("browser.search.log", false);
+
+// ordering of search engines in the engine list.
+pref("browser.search.order.1", "chrome://browser/locale/region.properties");
+pref("browser.search.order.2", "chrome://browser/locale/region.properties");
+
+// disable updating
+pref("browser.search.update", false);
+pref("browser.search.update.log", false);
+pref("browser.search.updateinterval", 6);
+
+// enable search suggestions by default
+pref("browser.search.suggest.enabled", true);
+
+// Tell the search service to load search plugins from the locale JAR
+pref("browser.search.loadFromJars", true);
+pref("browser.search.jarURIs", "chrome://browser/locale/searchplugins/");
+
+// tell the search service that we don't really expose the "current engine"
+pref("browser.search.noCurrentEngine", true);
+
+// enable xul error pages
+pref("browser.xul.error_pages.enabled", true);
+
+// Specify emptyRestriction = 0 so that bookmarks appear in the list by default
+pref("browser.urlbar.default.behavior", 0);
+pref("browser.urlbar.default.behavior.emptyRestriction", 0);
+
+// Let the faviconservice know that we display favicons as 32x32px so that it
+// uses the right size when optimizing favicons
+pref("places.favicons.optimizeToDimension", 32);
+
+// various and sundry awesomebar prefs (should remove/re-evaluate
+// these once bug 447900 is fixed)
+pref("browser.urlbar.clickSelectsAll", true);
+pref("browser.urlbar.doubleClickSelectsAll", true);
+pref("browser.urlbar.autoFill", false);
+pref("browser.urlbar.matchOnlyTyped", false);
+pref("browser.urlbar.matchBehavior", 1);
+pref("browser.urlbar.filter.javascript", true);
+pref("browser.urlbar.maxRichResults", 24); // increased so we see more results when portrait
+pref("browser.urlbar.search.chunkSize", 1000);
+pref("browser.urlbar.search.timeout", 100);
+pref("browser.urlbar.restrict.history", "^");
+pref("browser.urlbar.restrict.bookmark", "*");
+pref("browser.urlbar.restrict.tag", "+");
+pref("browser.urlbar.match.title", "#");
+pref("browser.urlbar.match.url", "@");
+pref("browser.urlbar.autocomplete.search_threshold", 5);
+pref("browser.history.grouping", "day");
+pref("browser.history.showSessions", false);
+pref("browser.sessionhistory.max_entries", 50);
+pref("browser.history_expire_days", 180);
+pref("browser.history_expire_days_min", 90);
+pref("browser.history_expire_sites", 40000);
+pref("browser.places.migratePostDataAnnotations", true);
+pref("browser.places.updateRecentTagsUri", true);
+pref("places.frecency.numVisits", 10);
+pref("places.frecency.numCalcOnIdle", 50);
+pref("places.frecency.numCalcOnMigrate", 50);
+pref("places.frecency.updateIdleTime", 60000);
+pref("places.frecency.firstBucketCutoff", 4);
+pref("places.frecency.secondBucketCutoff", 14);
+pref("places.frecency.thirdBucketCutoff", 31);
+pref("places.frecency.fourthBucketCutoff", 90);
+pref("places.frecency.firstBucketWeight", 100);
+pref("places.frecency.secondBucketWeight", 70);
+pref("places.frecency.thirdBucketWeight", 50);
+pref("places.frecency.fourthBucketWeight", 30);
+pref("places.frecency.defaultBucketWeight", 10);
+pref("places.frecency.embedVisitBonus", 0);
+pref("places.frecency.linkVisitBonus", 100);
+pref("places.frecency.typedVisitBonus", 2000);
+pref("places.frecency.bookmarkVisitBonus", 150);
+pref("places.frecency.downloadVisitBonus", 0);
+pref("places.frecency.permRedirectVisitBonus", 0);
+pref("places.frecency.tempRedirectVisitBonus", 0);
+pref("places.frecency.defaultVisitBonus", 0);
+pref("places.frecency.unvisitedBookmarkBonus", 140);
+pref("places.frecency.unvisitedTypedBonus", 200);
+
+// disable color management
+pref("gfx.color_management.mode", 0);
+
+// don't allow JS to move and resize existing windows
+pref("dom.disable_window_move_resize", true);
+
+// prevent click image resizing for nsImageDocument
+pref("browser.enable_click_image_resizing", false);
+
+// open in tab preferences
+// 0=default window, 1=current window/tab, 2=new window, 3=new tab in most window
+pref("browser.link.open_external", 3);
+pref("browser.link.open_newwindow", 3);
+// 0=force all new windows to tabs, 1=don't force, 2=only force those with no features set
+pref("browser.link.open_newwindow.restriction", 0);
+
+// controls which bits of private data to clear. by default we clear them all.
+pref("privacy.item.cache", true);
+pref("privacy.item.cookies", true);
+pref("privacy.item.offlineApps", true);
+pref("privacy.item.history", true);
+pref("privacy.item.formdata", true);
+pref("privacy.item.downloads", true);
+pref("privacy.item.passwords", true);
+pref("privacy.item.sessions", true);
+pref("privacy.item.geolocation", true);
+pref("privacy.item.siteSettings", true);
+pref("privacy.item.syncAccount", true);
+
+#ifdef MOZ_PLATFORM_MAEMO
+pref("plugins.force.wmode", "opaque");
+#endif
+
+// URL to the Learn More link XXX this is the firefox one.  Bug 495578 fixes this.
+pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/");
+
+// enable geo
+pref("geo.enabled", true);
+
+// content sink control -- controls responsiveness during page load
+// see https://bugzilla.mozilla.org/show_bug.cgi?id=481566#c9
+//pref("content.sink.enable_perf_mode",  2); // 0 - switch, 1 - interactive, 2 - perf
+//pref("content.sink.pending_event_mode", 0);
+//pref("content.sink.perf_deflect_count", 1000000);
+//pref("content.sink.perf_parse_time", 50000000);
+
+// Disable methodjit in chrome to save memory
+pref("javascript.options.methodjit.chrome",  false);
+
+pref("javascript.options.mem.high_water_mark", 32);
+
+// Disable the JS engine's gc on memory pressure, since we do one in the mobile
+// browser (bug 669346).
+pref("javascript.options.gc_on_memory_pressure", false);
+
+pref("dom.max_chrome_script_run_time", 0); // disable slow script dialog for chrome
+pref("dom.max_script_run_time", 20);
+
+// JS error console
+pref("devtools.errorconsole.enabled", false);
+
+pref("browser.ui.layout.tablet", -1); // on: 1, off: 0, auto: -1
+
+// kinetic tweakables
+pref("browser.ui.kinetic.updateInterval", 16);
+pref("browser.ui.kinetic.exponentialC", 1400);
+pref("browser.ui.kinetic.polynomialC", 100);
+pref("browser.ui.kinetic.swipeLength", 160);
+
+// zooming
+pref("browser.ui.zoom.pageFitGranularity", 9); // don't zoom to fit by less than 1/9 (11%)
+pref("browser.ui.zoom.animationDuration", 200); // ms duration of double-tap zoom animation
+pref("browser.ui.zoom.reflow", false); // Change text wrapping on double-tap
+pref("browser.ui.zoom.reflow.fontSize", 720);
+
+pref("font.size.inflation.minTwips", 120);
+
+// pinch gesture
+pref("browser.ui.pinch.maxGrowth", 150);     // max pinch distance growth
+pref("browser.ui.pinch.maxShrink", 200);     // max pinch distance shrinkage
+pref("browser.ui.pinch.scalingFactor", 500); // scaling factor for above pinch limits
+
+// Touch radius (area around the touch location to look for target elements),
+// in 1/240-inch pixels:
+pref("browser.ui.touch.left", 8);
+pref("browser.ui.touch.right", 8);
+pref("browser.ui.touch.top", 12);
+pref("browser.ui.touch.bottom", 4);
+pref("browser.ui.touch.weight.visited", 120); // percentage
+
+// plugins
+#if MOZ_PLATFORM_MAEMO == 6
+pref("plugin.disable", false);
+pref("dom.ipc.plugins.enabled", true);
+#elifdef ANDROID
+pref("plugin.disable", false);
+pref("dom.ipc.plugins.enabled", false);
+#else
+pref("plugin.disable", true);
+pref("dom.ipc.plugins.enabled", true);
+#endif
+
+// process priority
+// higher values give content process less CPU time
+#if MOZ_PLATFORM_MAEMO == 5
+pref("dom.ipc.content.nice", 10);
+#else
+pref("dom.ipc.content.nice", 1);
+#endif
+
+// product URLs
+// The breakpad report server to link to in about:crashes
+pref("breakpad.reportURL", "http://crash-stats.mozilla.com/report/index/");
+pref("app.releaseNotesURL", "http://www.mozilla.com/%LOCALE%/mobile/%VERSION%/releasenotes/");
+pref("app.sync.tutorialURL", "https://support.mozilla.com/kb/sync-firefox-between-desktop-and-mobile");
+pref("app.support.baseURL", "http://support.mozilla.com/mobile");
+pref("app.feedbackURL", "http://input.mozilla.com/feedback/");
+pref("app.privacyURL", "http://www.mozilla.com/%LOCALE%/m/privacy.html");
+pref("app.creditsURL", "http://www.mozilla.org/credits/");
+pref("app.channelURL", "http://www.mozilla.org/%LOCALE%/firefox/channel/");
+#if MOZ_UPDATE_CHANNEL == beta
+pref("app.featuresURL", "http://www.mozilla.com/%LOCALE%/mobile/beta/features/");
+pref("app.faqURL", "http://www.mozilla.com/%LOCALE%/mobile/beta/faq/");
+#else
+pref("app.featuresURL", "http://www.mozilla.com/%LOCALE%/mobile/features/");
+pref("app.faqURL", "http://www.mozilla.com/%LOCALE%/mobile/faq/");
+#endif
+
+// Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror)
+pref("security.alternate_certificate_error_page", "certerror");
+
+pref("security.warn_viewing_mixed", false); // Warning is disabled.  See Bug 616712.
+
+// Override some named colors to avoid inverse OS themes
+pref("ui.-moz-dialog", "#efebe7");
+pref("ui.-moz-dialogtext", "#101010");
+pref("ui.-moz-field", "#fff");
+pref("ui.-moz-fieldtext", "#1a1a1a");
+pref("ui.-moz-buttonhoverface", "#f3f0ed");
+pref("ui.-moz-buttonhovertext", "#101010");
+pref("ui.-moz-combobox", "#fff");
+pref("ui.-moz-comboboxtext", "#101010");
+pref("ui.buttonface", "#ece7e2");
+pref("ui.buttonhighlight", "#fff");
+pref("ui.buttonshadow", "#aea194");
+pref("ui.buttontext", "#101010");
+pref("ui.captiontext", "#101010");
+pref("ui.graytext", "#b1a598");
+pref("ui.highlight", "#fad184");
+pref("ui.highlighttext", "#1a1a1a");
+pref("ui.infobackground", "#f5f5b5");
+pref("ui.infotext", "#000");
+pref("ui.menu", "#f7f5f3");
+pref("ui.menutext", "#101010");
+pref("ui.threeddarkshadow", "#000");
+pref("ui.threedface", "#ece7e2");
+pref("ui.threedhighlight", "#fff");
+pref("ui.threedlightshadow", "#ece7e2");
+pref("ui.threedshadow", "#aea194");
+pref("ui.window", "#efebe7");
+pref("ui.windowtext", "#101010");
+pref("ui.windowframe", "#efebe7");
+
+#ifdef MOZ_OFFICIAL_BRANDING
+pref("browser.search.param.yahoo-fr", "moz35");
+pref("browser.search.param.yahoo-fr-cjkt", "moz35");
+pref("browser.search.param.yahoo-fr-ja", "mozff");
+#endif
+
+/* app update prefs */
+pref("app.update.timer", 60000); // milliseconds (1 min)
+
+#ifdef MOZ_UPDATER
+pref("app.update.enabled", true);
+pref("app.update.timerFirstInterval", 20000); // milliseconds
+pref("app.update.auto", false);
+pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@");
+pref("app.update.mode", 1);
+pref("app.update.silent", false);
+pref("app.update.url", "https://aus2.mozilla.org/update/4/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PLATFORM_VERSION%/update.xml");
+pref("app.update.promptWaitTime", 43200);
+pref("app.update.idletime", 60);
+pref("app.update.showInstalledUI", false);
+pref("app.update.incompatible.mode", 0);
+pref("app.update.download.backgroundInterval", 0);
+
+#ifdef MOZ_OFFICIAL_BRANDING
+pref("app.update.interval", 86400);
+pref("app.update.url.manual", "http://www.mozilla.com/%LOCALE%/m/");
+pref("app.update.url.details", "http://www.mozilla.com/%LOCALE%/mobile/releases/");
+#else
+pref("app.update.interval", 28800);
+pref("app.update.url.manual", "http://www.mozilla.com/%LOCALE%/mobile/");
+pref("app.update.url.details", "http://www.mozilla.com/%LOCALE%/mobile/");
+#endif
+#endif
+
+// replace newlines with spaces on paste into single-line text boxes
+pref("editor.singleLine.pasteNewlines", 2);
+
+#ifdef MOZ_PLATFORM_MAEMO
+// update fonts for better readability
+pref("font.default.x-baltic", "SwissA");
+pref("font.default.x-central-euro", "SwissA");
+pref("font.default.x-cyrillic", "SwissA");
+pref("font.default.x-unicode", "SwissA");
+pref("font.default.x-user-def", "SwissA");
+pref("font.default.x-western", "SwissA");
+#endif
+
+#ifdef MOZ_SERVICES_SYNC
+// sync service
+pref("services.sync.client.type", "mobile");
+pref("services.sync.registerEngines", "Tab,Bookmarks,Form,History,Password,Prefs");
+pref("services.sync.autoconnectDelay", 5);
+
+// prefs to sync by default
+pref("services.sync.prefs.sync.browser.startup.homepage.title", true);
+pref("services.sync.prefs.sync.browser.startup.homepage", true);
+pref("services.sync.prefs.sync.browser.tabs.warnOnClose", true);
+pref("services.sync.prefs.sync.browser.ui.zoom.reflow", true);
+pref("services.sync.prefs.sync.devtools.errorconsole.enabled", true);
+pref("services.sync.prefs.sync.javascript.enabled", true);
+pref("services.sync.prefs.sync.lightweightThemes.isThemeSelected", true);
+pref("services.sync.prefs.sync.lightweightThemes.usedThemes", true);
+pref("services.sync.prefs.sync.network.cookie.cookieBehavior", true);
+pref("services.sync.prefs.sync.permissions.default.image", true);
+pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
+pref("services.sync.prefs.sync.signon.rememberSignons", true);
+#endif
+
+// threshold where a tap becomes a drag, in 1/240" reference pixels
+// The names of the preferences are to be in sync with nsEventStateManager.cpp
+pref("ui.dragThresholdX", 25);
+pref("ui.dragThresholdY", 25);
+
+#if MOZ_PLATFORM_MAEMO == 6
+pref("layers.acceleration.disabled", false);
+#elifdef ANDROID
+pref("layers.acceleration.disabled", false);
+#else
+pref("layers.acceleration.disabled", true);
+#endif
+
+pref("notification.feature.enabled", true);
+
+// prevent tooltips from showing up
+pref("browser.chrome.toolbar_tips", false);
+pref("indexedDB.feature.enabled", true);
+pref("dom.indexedDB.warningQuota", 5);
+
+// prevent video elements from preloading too much data
+pref("media.preload.default", 1); // default to preload none
+pref("media.preload.auto", 2);    // preload metadata if preload=auto
+
+//  0: don't show fullscreen keyboard
+//  1: always show fullscreen keyboard
+// -1: show fullscreen keyboard based on threshold pref
+pref("widget.ime.android.landscape_fullscreen", -1);
+pref("widget.ime.android.fullscreen_threshold", 250); // in hundreths of inches
+
+// optimize images memory usage
+pref("image.mem.decodeondraw", true);
+pref("content.image.allow_locking", false);
+pref("image.mem.min_discard_timeout_ms", 10000);
+
+// enable touch events interfaces
+pref("dom.w3c_touch_events.enabled", true);
+pref("dom.w3c_touch_events.safetyX", 5); // escape borders in units of 1/240"
+pref("dom.w3c_touch_events.safetyY", 20); // escape borders in units of 1/240"
+
+#ifdef MOZ_SAFE_BROWSING
+// Safe browsing does nothing unless this pref is set
+pref("browser.safebrowsing.enabled", true);
+
+// Prevent loading of pages identified as malware
+pref("browser.safebrowsing.malware.enabled", true);
+
+// Non-enhanced mode (local url lists) URL list to check for updates
+pref("browser.safebrowsing.provider.0.updateURL", "http://safebrowsing.clients.google.com/safebrowsing/downloads?client={moz:client}&appver={moz:version}&pver=2.2");
+
+pref("browser.safebrowsing.dataProvider", 0);
+
+// Does the provider name need to be localizable?
+pref("browser.safebrowsing.provider.0.name", "Google");
+pref("browser.safebrowsing.provider.0.keyURL", "https://sb-ssl.google.com/safebrowsing/newkey?client={moz:client}&appver={moz:version}&pver=2.2");
+pref("browser.safebrowsing.provider.0.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/report?");
+pref("browser.safebrowsing.provider.0.gethashURL", "http://safebrowsing.clients.google.com/safebrowsing/gethash?client={moz:client}&appver={moz:version}&pver=2.2");
+
+// HTML report pages
+pref("browser.safebrowsing.provider.0.reportGenericURL", "http://{moz:locale}.phish-generic.mozilla.com/?hl={moz:locale}");
+pref("browser.safebrowsing.provider.0.reportErrorURL", "http://{moz:locale}.phish-error.mozilla.com/?hl={moz:locale}");
+pref("browser.safebrowsing.provider.0.reportPhishURL", "http://{moz:locale}.phish-report.mozilla.com/?hl={moz:locale}");
+pref("browser.safebrowsing.provider.0.reportMalwareURL", "http://{moz:locale}.malware-report.mozilla.com/?hl={moz:locale}");
+pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:locale}.malware-error.mozilla.com/?hl={moz:locale}");
+
+// FAQ URLs
+pref("browser.safebrowsing.warning.infoURL", "http://www.mozilla.com/%LOCALE%/%APP%/phishing-protection/");
+pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/%APP%/geolocation/");
+
+// Name of the about: page contributed by safebrowsing to handle display of error
+// pages on phishing/malware hits.  (bug 399233)
+pref("urlclassifier.alternate_error_page", "blocked");
+
+// The number of random entries to send with a gethash request.
+pref("urlclassifier.gethashnoise", 4);
+
+// The list of tables that use the gethash request to confirm partial results.
+pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
+
+// If an urlclassifier table has not been updated in this number of seconds,
+// a gethash request will be forced to check that the result is still in
+// the database.
+pref("urlclassifier.confirm-age", 2700);
+
+// Maximum size of the sqlite3 cache during an update, in bytes
+pref("urlclassifier.updatecachemax", 4194304);
+
+// URL for checking the reason for a malware warning.
+pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
+#endif
+
+// True if this is the first time we are showing about:firstrun
+pref("browser.firstrun.show.uidiscovery", true);
+pref("browser.firstrun.show.localepicker", false);
+
+// True if you always want dump() to work
+//
+// On Android, you also need to do the following for the output
+// to show up in logcat:
+//
+// $ adb shell stop
+// $ adb shell setprop log.redirect-stdio true
+// $ adb shell start
+pref("browser.dom.window.dump.enabled", true);
+
+// controls if we want camera support
+pref("device.camera.enabled", true);
+pref("media.realtime_decoder.enabled", true);
+
+pref("dom.report_all_js_exceptions", true);
+pref("javascript.options.showInConsole", true);
+
+pref("full-screen-api.enabled", true);
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/profile/extensions/Makefile.in
@@ -0,0 +1,67 @@
+# ***** 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.
+#
+# The Initial Developer of the Original Code is
+# the Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   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 *****
+
+DEPTH		= ../../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+EXTENSIONS_DIR = $(call core_abspath,$(DIST))/bin/extensions
+
+include $(DEPTH)/config/autoconf.mk
+
+include $(topsrcdir)/config/rules.mk
+
+ifneq (,$(filter nightly aurora beta,$(MOZ_UPDATE_CHANNEL)))
+EXTENSIONS = \
+  feedback@mobile.mozilla.org \
+  $(NULL)
+
+define _INSTALL_EXTENSION
+$(NSINSTALL) -D $(dir) && \
+  $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(srcdir)/$(dir)/install.rdf.in > $(dir)/install.rdf && \
+  cd $(dir) && \
+  $(ZIP) -r9XD $(EXTENSIONS_DIR)/$(dir).xpi install.rdf && \
+  cd $(srcdir)/$(dir) && \
+  $(ZIP) -r9XD $(EXTENSIONS_DIR)/$(dir).xpi * -x install.rdf.in
+
+endef # do not remove the blank line!
+
+libs::
+	$(NSINSTALL) -D $(EXTENSIONS_DIR)
+	$(foreach dir,$(EXTENSIONS),$(_INSTALL_EXTENSION))
+endif
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/chrome.manifest
@@ -0,0 +1,5 @@
+content feedback content/
+skin    feedback classic/1.0 skin/
+locale  feedback en-US       locale/en-US/
+
+overlay	chrome://browser/content/browser.xul  chrome://feedback/content/overlay.xul
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/content/content.js
@@ -0,0 +1,33 @@
+
+function populateFeedback(aMessage) {
+  let json = aMessage.json;
+
+  let referrer = json.referrer;
+  let URLElem = content.document.getElementById("id_url");
+  if (URLElem)
+    URLElem.value = referrer;
+
+  let URLElems = content.document.getElementsByClassName("url");
+  for (let index=0; index<URLElems.length; index++)
+    URLElems[index].value = referrer;
+
+  let device = json.device || "";
+  let deviceElem = content.document.getElementById("id_device");
+  if (deviceElem)
+    deviceElem.value = device;
+
+  let deviceElems = content.document.getElementsByClassName("device");
+  for (let index=0; index<deviceElems.length; index++)
+    deviceElems[index].value = device;
+
+  let manufacturer = json.manufacturer || "";
+  let manufacturerElem = content.document.getElementById("id_manufacturer");
+  if (manufacturerElem)
+    manufacturerElem.value = manufacturer;
+
+  let manufacturerElems = content.document.getElementsByClassName("manufacturer");
+  for (let index=0; index<manufacturerElems.length; index++)
+    manufacturerElems[index].value = manufacturer;
+}
+
+addMessageListener("Feedback:InitPage", populateFeedback);
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/content/overlay.js
@@ -0,0 +1,148 @@
+/* ***** 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 Feedback.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mark Finkle <mark.finkle@gmail.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 ***** */
+
+var Feedback = {
+  _prefs: [],
+  _device: "",
+  _manufacturer: "",
+
+  init: function(aEvent) {
+    // Delay the widget initialization during startup.
+    let panel = document.getElementById("feedback-container");
+    panel.addEventListener("ToolPanelShown", function delayedInit(aEvent) {
+      panel.removeEventListener("ToolPanelShown", delayedInit, false);
+
+      // A simple frame script to fill in the referrer page and device info
+      messageManager.loadFrameScript("chrome://feedback/content/content.js", true);
+
+      let setting = document.getElementById("feedback-checkCompatibility");
+      setting.setAttribute("pref", Feedback.compatibilityPref);
+      setting.preferenceChanged();
+
+      document.getElementById("feedback-container").hidden = false;
+
+      let feedbackPrefs = document.getElementById("feedback-tools").childNodes;
+      for (let i = 0; i < feedbackPrefs.length; i++) {
+        let pref = feedbackPrefs[i].getAttribute("pref");
+        if (!pref)
+          continue;
+  
+        let value = Services.prefs.getPrefType(pref) == Ci.nsIPrefBranch.PREF_INVALID ? false : Services.prefs.getBoolPref(pref);
+        Feedback._prefs.push({ "name": pref, "value": value });
+      }
+
+      let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
+      Feedback._device = sysInfo.get("device");
+      Feedback._manufacturer = sysInfo.get("manufacturer");
+    }, false);
+  },
+
+  get compatibilityPref() {
+    let result = "extensions.checkCompatibility.";
+    let channel = Services.prefs.getCharPref("app.update.channel");
+    if (channel == "nightly") {
+      result += "nightly";
+    } else {
+      // Copied from toolkit/mozapps/extensions/XPIProvider.jsm
+      const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi;
+      result += Services.appinfo.version.replace(BRANCH_REGEXP, "$1");
+    }
+    delete this.compatibilityPref;
+    return this.compatibilityPref = result;
+  },
+
+  openFeedback: function(aName) {
+    let pref = "extensions.feedback.url." + aName;
+    let url = Services.prefs.getPrefType(pref) == Ci.nsIPrefBranch.PREF_INVALID ? "" : Services.prefs.getCharPref(pref);
+    if (!url)
+      return;
+
+    let currentURL = Browser.selectedBrowser.currentURI.spec;
+    let newTab = BrowserUI.newTab(url, Browser.selectedTab);
+
+    // Tell the feedback page to fill in the referrer URL
+    newTab.browser.messageManager.addMessageListener("DOMContentLoaded", function() {
+      newTab.browser.messageManager.removeMessageListener("DOMContentLoaded", arguments.callee, true);
+      newTab.browser.messageManager.sendAsyncMessage("Feedback:InitPage", { referrer: currentURL, device: Feedback._device, manufacturer: Feedback._manufacturer });
+    });
+  },
+
+  updateRestart: function updateRestart() {
+    let msg = document.getElementById("feedback-messages");
+    if (msg) {
+      let value = "restart-app";
+      let notification = msg.getNotificationWithValue(value);
+      if (notification) {
+        // Check if the prefs are back to the initial state dismiss the restart
+        // notification because if does not make sense anymore
+        for each (let pref in this._prefs) {
+          let value = Services.prefs.getPrefType(pref.name) == Ci.nsIPrefBranch.PREF_INVALID ? false : Services.prefs.getBoolPref(pref.name);
+          if (value != pref.value)
+            return;
+        }
+
+        notification.close();
+        return;
+      }
+  
+      let restartCallback = function(aNotification, aDescription) {
+        // Notify all windows that an application quit has been requested
+        let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
+        Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
+  
+        // If nothing aborted, quit the app
+        if (cancelQuit.data == false) {
+          let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
+          appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
+        }
+      };
+
+      let strings = Strings.browser;
+
+      let buttons = [ {
+        label: strings.GetStringFromName("notificationRestart.button"),
+        accessKey: "",
+        callback: restartCallback
+      } ];
+  
+      let message = strings.GetStringFromName("notificationRestart.normal");
+      msg.appendNotification(message, value, "", msg.PRIORITY_WARNING_LOW, buttons);
+    }
+  }
+};
+
+window.addEventListener("load", Feedback.init, false);
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/content/overlay.xul
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ***** 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 Feedback.
+   -
+   - The Initial Developer of the Original Code is
+   - Mozilla Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 2010
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Mark Finkle <mark.finkle@gmail.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://feedback/skin/overlay.css" type="text/css"?>
+
+<!DOCTYPE window [
+<!ENTITY % feedbackDTD SYSTEM "chrome://browser/locale/feedback.dtd">
+%feedbackDTD;
+]>
+
+<overlay id="feedback-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript" src="chrome://feedback/content/overlay.js"/>
+
+  <box id="panel-controls">
+    <toolbarbutton id="tool-feedback" class="panel-row-button" autocheck="true" type="radio" label="&feedbackHeader2.label;" group="1" linkedpanel="feedback-container" insertafter="tool-addons"/>
+  </box>
+
+  <deck id="panel-items">
+    <vbox id="feedback-container" flex="1" hidden="true">
+      <notificationbox id="feedback-messages" flex="1">
+        <richlistbox id="feedback-list" flex="1" onselect="this.ensureSelectedElementIsVisible()">
+          <label id="feedback-list-header" class="panel-header" value="&feedbackHeader2.label;"/>
+          <settings id="feedback-communicate" label="&feedback.communicate.title;">
+            <setting title="&feedback.feedback.title;" type="control">
+              <button id="feedback-feedback-happy" oncommand="Feedback.openFeedback('happy');"/>
+              <button id="feedback-feedback-sad" oncommand="Feedback.openFeedback('sad');"/>
+            </setting>
+          </settings>
+          <settings id="feedback-tools" label="&feedback.tools.title;">
+            <setting pref="toolkit.telemetry.enabled" title="&feedback.allowTelemetry.title;" type="bool"/>
+            <setting id="feedback-checkCompatibility" title="&feedback.forceCompat.title;" type="bool" inverted="true" oninputchanged="Feedback.updateRestart();"/>
+            <setting pref="devtools.errorconsole.enabled" title="&feedback.errorConsole.title;" type="bool"/>
+          </settings>
+        </richlistbox>
+      </notificationbox>
+    </vbox>
+  </deck>
+</overlay>
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/defaults/preferences/preferences.js
@@ -0,0 +1,2 @@
+pref("extensions.feedback.url.happy", "http://input.mozilla.com/happy");
+pref("extensions.feedback.url.sad", "http://input.mozilla.com/sad");
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/install.rdf.in
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+
+#filter substitution
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>feedback@mobile.mozilla.org</em:id>
+    <em:version>1.0.1</em:version>
+    <em:type>2</em:type>
+
+    <!-- Target Application this extension can install into, 
+         with minimum and maximum supported versions. --> 
+    <em:targetApplication>
+      <Description>
+        <em:id>{a23983c0-fd0e-11dc-95ff-0800200c9a66}</em:id>
+        <em:minVersion>4.0</em:minVersion>
+        <em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+   
+    <!-- Front End MetaData -->
+    <em:name>Feedback</em:name>
+    <em:description>Help make Firefox better by giving feedback.</em:description>
+    <em:creator>Mozilla Corporation</em:creator>
+    <em:iconURL>chrome://feedback/skin/dino-32.png</em:iconURL>
+  </Description>
+</RDF>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d62aed40c7179747bb987753b7dfc4f527c881cd
GIT binary patch
literal 2612
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..35b3a174a5585a0f92f491066ef92dabb975cae9
GIT binary patch
literal 1583
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..49e38c58680a16fc5bc06019df4201907ee8c727
GIT binary patch
literal 2497
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
LNkvXXu0mjfwkp;v
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/skin/overlay.css
@@ -0,0 +1,11 @@
+#tool-feedback {
+  list-style-image: url("chrome://feedback/skin/beta-hdpi.png");
+}
+
+#feedback-feedback-happy {
+  list-style-image: url("chrome://feedback/skin/happy-32.png");
+}
+
+#feedback-feedback-sad {
+  list-style-image: url("chrome://feedback/skin/sad-32.png");
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a59db1ffbf433213346f489938a93ef370f3c611
GIT binary patch
literal 2394
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
M07*qoM6N<$f?Z66lK=n!
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/recommended-addons.json
@@ -0,0 +1,1 @@
+{"addons":[{"id":"cleary@digdug.org","name":"Cleary","type":"extension","version":"1.1","repositoryStatus":4,"creator":{"name":"DigDug","url":"https://addons.mozilla.org/en-US/mobile/user/47146/?src=api"},"description":"Creates a subpage for clearing everything, history, passwords, or just site settings for small time durations. Also adds option to clear everything on shutdown (You'll need to add Quit Fennec in order to have a quit button).","fullDescription":"Creates a subpage for clearing small sets of prefs for certain time durations. Also adds options for \"Clear on shutdown\".","iconURL":"http://static-cdn.addons.mozilla.net/en-US/firefox/images/addon_icon/292493-32.png?modified=1310547725","isPlatformCompatible":true,"eula":null,"screenshots":[{"url":"https://static-cdn.addons.mozilla.net/img/uploads/previews/full/58/58448.png?src=api&modified=1306791981","thumbnailURL":"https://static-cdn.addons.mozilla.net/img/uploads/previews/thumbs/58/58448.png?src=api&modified=1306791981","caption":"The new settings screen. Clicking on the Clear row will show the a subpage with detailed options. You can also select to have Fennec clear history on shutdown (using the Quit Firefox addon)."},{"url":"https://static-cdn.addons.mozilla.net/img/uploads/previews/full/58/58449.png?src=api&modified=1306791981","thumbnailURL":"https://static-cdn.addons.mozilla.net/img/uploads/previews/thumbs/58/58449.png?src=api&modified=1306791981","caption":"The sub options. Clicking any of the clear buttons will clear just that set of history for the time period shown at the top."}],"averageRating":2,"homepageURL":"https://addons.mozilla.org/en-US/mobile/addon/cleary/?src=api","sourceURI":{"spec":"https://addons.mozilla.org/mobile/downloads/file/126109/cleary-1.1-fn-android.xpi?src=api","prePath":"https://addons.mozilla.org","scheme":"https","userPass":"","username":"","password":"","hostPort":"addons.mozilla.org","host":"addons.mozilla.org","port":-1,"path":"/mobile/downloads/file/126109/cleary-1.1-fn-android.xpi?src=api","asciiSpec":"https://addons.mozilla.org/mobile/downloads/file/126109/cleary-1.1-fn-android.xpi?src=api","asciiHost":"addons.mozilla.org","originCharset":"UTF-8","ref":""},"size":11264,"developerComments":"Added repository at: http://hg.mozilla.org/users/wjohnston_mozilla.com/cleary","reviewURL":"https://addons.mozilla.org/en-US/mobile/addon/cleary/reviews/?src=api","reviewCount":2,"totalDownloads":145132,"weeklyDownloads":8825,"dailyUsers":13879,"updateDate":"2011-07-13T09:01:17.000Z","supportURL":"http://hg.mozilla.org/users/wjohnston_mozilla.com/cleary","install":{"name":"Cleary","type":null,"version":"1.1","iconURL":"https://static-cdn.addons.mozilla.net/en-US/firefox/images/addon_icon/292493-32.png?modified=1310547725","releaseNotesURI":null,"file":null,"state":0,"error":0,"progress":0,"maxProgress":-1,"certificate":null,"certName":null,"existingAddon":null,"addon":null,"sourceURI":{"spec":"https://addons.mozilla.org/mobile/downloads/file/126109/cleary-1.1-fn-android.xpi?src=api","prePath":"https://addons.mozilla.org","scheme":"https","userPass":"","username":"","password":"","hostPort":"addons.mozilla.org","host":"addons.mozilla.org","port":-1,"path":"/mobile/downloads/file/126109/cleary-1.1-fn-android.xpi?src=api","asciiSpec":"https://addons.mozilla.org/mobile/downloads/file/126109/cleary-1.1-fn-android.xpi?src=api","asciiHost":"addons.mozilla.org","originCharset":"UTF-8","ref":""},"linkedInstalls":null}},{"id":"clearhistory@mbrubeck.limpet.net","name":"Clear Mobile History","type":"extension","version":"1.0.2","repositoryStatus":4,"creator":{"name":"Matt Brubeck","url":"https://addons.mozilla.org/en-US/mobile/user/5283521/?src=api"},"description":"Add a \"Clear History\" button to the Firefox preferences.","fullDescription":"Clear your mobile Firefox history without clearing your cookies, passwords, etc.","iconURL":"http://static-cdn.addons.mozilla.net/media//img/addon-icons/security-32.png","isPlatformCompatible":true,"eula":null,"screenshots":[{"url":"https://static-cdn.addons.mozilla.net/img/uploads/previews/full/54/54824.png?src=api&modified=1299604932","thumbnailURL":"https://static-cdn.addons.mozilla.net/img/uploads/previews/thumbs/54/54824.png?src=api&modified=1299604932","caption":null}],"averageRating":2,"homepageURL":"https://addons.mozilla.org/en-US/mobile/addon/clear-mobile-history/?src=api","sourceURI":{"spec":"https://addons.mozilla.org/mobile/downloads/file/126990/clear_mobile_history-1.0.2-fn-android.xpi?src=api","prePath":"https://addons.mozilla.org","scheme":"https","userPass":"","username":"","password":"","hostPort":"addons.mozilla.org","host":"addons.mozilla.org","port":-1,"path":"/mobile/downloads/file/126990/clear_mobile_history-1.0.2-fn-android.xpi?src=api","asciiSpec":"https://addons.mozilla.org/mobile/downloads/file/126990/clear_mobile_history-1.0.2-fn-android.xpi?src=api","asciiHost":"addons.mozilla.org","originCharset":"UTF-8","ref":""},"size":2048,"developerComments":"Source code is available at: http://hg.mozilla.org/users/mbrubeck_mozilla.com/clearhistory/","reviewURL":"https://addons.mozilla.org/en-US/mobile/addon/clear-mobile-history/reviews/?src=api","reviewCount":2,"totalDownloads":331354,"weeklyDownloads":16899,"dailyUsers":33852,"updateDate":"2011-07-22T18:20:07.000Z","supportURL":null,"install":{"name":"Clear Mobile History","type":null,"version":"1.0.2","iconURL":"https://static-cdn.addons.mozilla.net/media//img/addon-icons/security-32.png","releaseNotesURI":null,"file":null,"state":0,"error":0,"progress":0,"maxProgress":-1,"certificate":null,"certName":null,"existingAddon":null,"addon":null,"sourceURI":{"spec":"https://addons.mozilla.org/mobile/downloads/file/126990/clear_mobile_history-1.0.2-fn-android.xpi?src=api","prePath":"https://addons.mozilla.org","scheme":"https","userPass":"","username":"","password":"","hostPort":"addons.mozilla.org","host":"addons.mozilla.org","port":-1,"path":"/mobile/downloads/file/126990/clear_mobile_history-1.0.2-fn-android.xpi?src=api","asciiSpec":"https://addons.mozilla.org/mobile/downloads/file/126990/clear_mobile_history-1.0.2-fn-android.xpi?src=api","asciiHost":"addons.mozilla.org","originCharset":"UTF-8","ref":""},"linkedInstalls":null}}],"addonCount":2,"totalResults":-1}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/AboutHomeContent.java
@@ -0,0 +1,293 @@
+/* -*- 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):
+ *   Brad Lassey <blassey@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 android.app.Activity;
+import android.os.Bundle;
+import android.widget.*;
+import android.database.*;
+import android.view.*;
+import android.graphics.*;
+import android.content.*;
+import android.provider.Browser;
+import android.util.Log;
+import java.util.Date;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Browser;
+import android.util.Log;
+import android.view.View;
+import android.widget.ListAdapter;
+import android.widget.GridView;
+import android.widget.SimpleCursorAdapter;
+import java.io.*;
+import java.util.zip.*;
+import android.os.Handler;
+import org.json.*;
+import android.util.AttributeSet;
+
+public class AboutHomeContent extends LinearLayout {
+    public interface UriLoadCallback {
+        public void callback(String uriSpec);
+    }
+
+    UriLoadCallback mUriLoadCallback = null;
+
+    void setUriLoadCallback(UriLoadCallback uriLoadCallback) {
+        mUriLoadCallback = uriLoadCallback;
+    }
+
+    public AboutHomeContent(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+    private static final String LOGTAG = "GeckoAboutHome";
+    private static final String TITLE_KEY = "title";
+    private static final String kAbouthomeWhereClause = Browser.BookmarkColumns.BOOKMARK + " = 1";
+    private static final int kTileWidth = 122;
+
+    private Cursor mCursor;
+    private Uri mUri;
+    private String mTitle;
+
+    protected ListAdapter mGridAdapter;
+    protected ArrayAdapter<String> mAddonAdapter;
+    protected GridView mGrid;
+    protected ListView mAddonList;
+    private Handler mHandler = new Handler();
+
+    public void onActivityContentChanged(Activity activity) {
+        mGrid = (GridView)findViewById(R.id.grid);
+        if (mGrid == null)
+            return;
+
+        mGrid.setOnItemClickListener(mGridOnClickListener);
+
+        // we want to do this: mGrid.setNumColumns(GridView.AUTO_FIT); but it doesn't work
+        Display display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+        int width = display.getWidth();
+        mGrid.setNumColumns((int) Math.floor(width / kTileWidth));
+        mAddonList = (ListView)findViewById(R.id.recommended_addon_list);
+        GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
+            public void run() {
+                mGrid.setAdapter(mGridAdapter);
+            }
+        });
+    }
+
+
+    private AdapterView.OnItemClickListener mGridOnClickListener = new AdapterView.OnItemClickListener() {
+        public void onItemClick(AdapterView<?> parent, View v, int position, long id)
+        {
+            onGridItemClick((GridView)parent, v, position, id);
+        }
+    };
+
+    void init(final Activity activity) {
+        LayoutInflater inflater =
+            (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        inflater.inflate(R.layout.abouthome_content, this);
+
+        GeckoAppShell.getHandler().post(new Runnable() {
+            public void run() {
+                mCursor = activity.managedQuery(Browser.BOOKMARKS_URI,
+                                                null, kAbouthomeWhereClause, null, null);
+                activity.startManagingCursor(mCursor);
+
+                onActivityContentChanged(activity);
+                mAddonAdapter = new ArrayAdapter<String>(activity, R.layout.abouthome_addon_list_item);
+                GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
+                    public void run() {
+                        final SimpleCursorAdapter gridAdapter =
+                            new SimpleCursorAdapter(activity, R.layout.abouthome_grid_box, mCursor,
+                                                    new String[] {Browser.BookmarkColumns.TITLE,
+                                                                  Browser.BookmarkColumns.FAVICON,
+                                                                  Browser.BookmarkColumns.URL,
+                                                                  "thumbnail"},
+                                                    new int[] {R.id.bookmark_title, R.id.bookmark_icon, R.id.bookmark_url, R.id.screenshot});
+                        mGrid.setAdapter(gridAdapter);
+                        gridAdapter.setViewBinder(new AwesomeCursorViewBinder());
+                        mAddonList.setAdapter(mAddonAdapter);
+                    }
+                });
+                readRecommendedAddons(activity);
+            }
+        });
+    }
+
+    InputStream getProfileRecommendedAddonsStream() {
+        try {
+            File profileDir = GeckoApp.mAppContext.getProfileDir();
+            if (profileDir == null)
+                return null;
+            File recommendedAddonsFile = new File(profileDir, "recommended-addons.json");
+            if (!recommendedAddonsFile.exists())
+                return null;
+            return new FileInputStream(recommendedAddonsFile);
+        } catch (FileNotFoundException fnfe) {
+            // ignore
+        }
+        return null;
+    }
+
+    InputStream getRecommendedAddonsStream(Activity activity) throws Exception{
+        InputStream is = getProfileRecommendedAddonsStream();
+        if (is != null)
+            return is;
+        File applicationPackage = new File(activity.getApplication().getPackageResourcePath());
+        ZipFile zip = new ZipFile(applicationPackage);
+        ZipEntry fileEntry = zip.getEntry("recommended-addons.json");
+        return zip.getInputStream(fileEntry);
+    }
+
+    void readRecommendedAddons(final Activity activity) {
+        GeckoAppShell.getHandler().post(new Runnable() {
+            public void run() {
+                try {
+                    byte[] buf = new byte[32768];
+                    InputStream fileStream = getRecommendedAddonsStream(activity);
+                    StringBuffer jsonString = new StringBuffer();
+                    int read = 0;
+                    while ((read = fileStream.read(buf, 0, 32768)) != -1) {
+                        jsonString.append(new String(buf, 0, read));
+                    }
+                    final JSONArray array = new JSONObject(jsonString.toString()).getJSONArray("addons");
+                    GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
+                        public void run() {
+                            try {
+                                for (int i = 0; i < array.length(); i++) {
+                                    JSONObject jsonobj = array.getJSONObject(i);
+                                    mAddonAdapter.add(jsonobj.getString("name"));
+                                    Log.i("GeckoAddons", "addon #" + i +": " + jsonobj.getString("name"));
+                                }
+                            } catch (Exception e) {
+                                Log.i("GeckoAddons", "error reading json file", e);
+                            }
+                        }
+                    });
+                } catch (Exception e) {
+                    Log.i("GeckoAddons", "error reading json file", e);
+                }
+            }
+        });
+    }
+
+    protected void onGridItemClick(GridView l, View v, int position, long id) {
+        mCursor.moveToPosition(position);
+        String spec = mCursor.getString(mCursor.getColumnIndex(Browser.BookmarkColumns.URL));
+        Log.i(LOGTAG, "clicked: " + spec);
+        if (mUriLoadCallback != null)
+            mUriLoadCallback.callback(spec);
+    }
+
+}
+class AwesomeCursorViewBinder implements SimpleCursorAdapter.ViewBinder {
+    private boolean updateImage(View view, Cursor cursor, int faviconIndex) {
+        byte[] b = cursor.getBlob(faviconIndex);
+        ImageView favicon = (ImageView) view;
+
+        if (b == null) {
+            favicon.setImageResource(R.drawable.favicon);
+        } else {
+            Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
+            favicon.setImageBitmap(bitmap);
+        }
+
+        return true;
+    }
+
+    private boolean updateTitle(View view, Cursor cursor, int titleIndex) {
+        String title = cursor.getString(titleIndex);
+        TextView titleView = (TextView)view;
+        // Use the URL instead of an empty title for consistency with the normal URL
+        // bar view - this is the equivalent of getDisplayTitle() in Tab.java
+        if (title == null || title.length() == 0) {
+            int urlIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.URL);
+            title = cursor.getString(urlIndex);
+        }
+
+        titleView.setText(title);
+        return true;
+    }
+
+    private boolean updateUrl(View view, Cursor cursor, int urlIndex) {
+        String title = cursor.getString(urlIndex);
+        TextView urlView = (TextView)view;
+        if (title != null) {
+            int index;
+            if ((index = title.indexOf("://")) != -1)
+                title = title.substring(index + 3);
+            if (title.startsWith("www."))
+                title = title.substring(4);
+            if (title.endsWith("/"))
+                title = title.substring(0, title.length() -1);
+        }
+        urlView.setText(title);
+        return true;
+    }
+
+    @Override
+    public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
+        int faviconIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON);
+        if (columnIndex == faviconIndex) {
+            return updateImage(view, cursor, faviconIndex);
+        }
+
+        int titleIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.TITLE);
+        if (columnIndex == titleIndex) {
+            return updateTitle(view, cursor, titleIndex);
+        }
+
+        int urlIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.URL);
+        if (columnIndex == urlIndex) {
+            return updateUrl(view, cursor, urlIndex);
+        }
+
+        int thumbIndex = cursor.getColumnIndexOrThrow("thumbnail");
+
+        if (columnIndex == thumbIndex) {
+            return updateImage(view, cursor, thumbIndex);
+        }
+
+        // Other columns are handled automatically
+        return false;
+    }
+
+}
rename from embedding/android/AlertNotification.java
rename to mobile/android/base/AlertNotification.java
--- a/embedding/android/AlertNotification.java
+++ b/mobile/android/base/AlertNotification.java
@@ -45,40 +45,41 @@ import android.net.Uri;
 import android.util.Log;
 import android.widget.RemoteViews;
 import java.net.*;
 import java.text.NumberFormat;
 
 public class AlertNotification
     extends Notification
 {
-    Context mContext;
-    int mId;
-    int mIcon;
-    String mTitle;
-    String mText;
-    boolean mProgressStyle;
-    NotificationManager mNotificationManager;
-    double mPrevPercent  = -1;
-    String mPrevAlertText = "";
-    static final double UPDATE_THRESHOLD = .01;
+    private static final String LOGTAG = "GeckoAlertNotification";
+
+    private final int mId;
+    private final int mIcon;
+    private final String mTitle;
+    private final String mText;
+    private final NotificationManager mNotificationManager;
+
+    private boolean mProgressStyle; // = false
+    private double mPrevPercent  = -1;
+    private String mPrevAlertText = "";
+
+    private static final double UPDATE_THRESHOLD = .01;
 
     public AlertNotification(Context aContext, int aNotificationId, int aIcon,
                              String aTitle, String aText, long aWhen) {
         super(aIcon, (aText.length() > 0) ? aText : aTitle, aWhen);
 
-        mContext = aContext;
         mIcon = aIcon;
         mTitle = aTitle;
         mText = aText;
-        mProgressStyle = false;
         mId = aNotificationId;
 
         mNotificationManager = (NotificationManager)
-            mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+            aContext.getSystemService(Context.NOTIFICATION_SERVICE);
     }
 
     public boolean isProgressStyle() {
         return mProgressStyle;
     }
 
     public void show() {
         mNotificationManager.notify(mId, this);
@@ -89,36 +90,36 @@ public class AlertNotification
             return;
 
         // Custom view
         int layout = R.layout.notification_icon_text;
         RemoteViews view = new RemoteViews(GeckoApp.mAppContext.getPackageName(), layout);
         try {
             URL url = new URL(aIconUri.toString());
             Bitmap bm = BitmapFactory.decodeStream(url.openStream());
-            view.setImageViewBitmap(R.id.notificationImage, bm);
-            view.setTextViewText(R.id.notificationTitle, mTitle);
+            view.setImageViewBitmap(R.id.notification_image, bm);
+            view.setTextViewText(R.id.notification_title, mTitle);
             if (mText.length() > 0) {
-                view.setTextViewText(R.id.notificationText, mText);
+                view.setTextViewText(R.id.notification_text, mText);
             }
             contentView = view;
             mNotificationManager.notify(mId, this); 
         } catch(Exception ex) {
-            Log.e("GeckoAlert", "failed to create bitmap", ex);
+            Log.e(LOGTAG, "failed to create bitmap", ex);
         }
     }
 
     public void updateProgress(String aAlertText, long aProgress, long aProgressMax) {
         if (!mProgressStyle) {
             // Custom view
             int layout =  aAlertText.length() > 0 ? R.layout.notification_progress_text : R.layout.notification_progress;
 
             RemoteViews view = new RemoteViews(GeckoApp.mAppContext.getPackageName(), layout);
-            view.setImageViewResource(R.id.notificationImage, mIcon);
-            view.setTextViewText(R.id.notificationTitle, mTitle);
+            view.setImageViewResource(R.id.notification_image, mIcon);
+            view.setTextViewText(R.id.notification_title, mTitle);
             contentView = view;
             flags |= FLAG_ONGOING_EVENT | FLAG_ONLY_ALERT_ONCE;
 
             mProgressStyle = true;
         }
 
         String text;
         double percent = 0;
@@ -128,18 +129,18 @@ public class AlertNotification
         if (aAlertText.length() > 0)
             text = aAlertText;
         else
             text = NumberFormat.getPercentInstance().format(percent); 
 
         if (mPrevAlertText.equals(text) && Math.abs(mPrevPercent - percent) < UPDATE_THRESHOLD)
             return;
 
-        contentView.setTextViewText(R.id.notificationText, text);
-        contentView.setProgressBar(R.id.notificationProgressbar, (int)aProgressMax, (int)aProgress, false);
+        contentView.setTextViewText(R.id.notification_text, text);
+        contentView.setProgressBar(R.id.notification_progressbar, (int)aProgressMax, (int)aProgress, false);
 
         // Update the notification
         mNotificationManager.notify(mId, this);
 
         mPrevPercent = percent;
         mPrevAlertText = text;
     }
 }
rename from embedding/android/AndroidManifest.xml.in
rename to mobile/android/base/AndroidManifest.xml.in
--- a/embedding/android/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -16,19 +16,18 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
 
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission android:name="android.permission.VIBRATE"/>
 
-    <!-- WebSMS -->
-    <uses-permission android:name="android.permission.SEND_SMS"/>
-    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+    <uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/> 
+    <uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"/> 
 
     <uses-feature android:name="android.hardware.location" android:required="false"/>
     <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
     <uses-feature android:name="android.hardware.touchscreen"/>
 
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-feature android:name="android.hardware.camera" android:required="false"/>
     <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
@@ -38,20 +37,20 @@
 #if MOZILLA_OFFICIAL
 		 android:debuggable="false">
 #else
 		 android:debuggable="true">
 #endif
 
         <activity android:name="App"
                   android:label="@MOZ_APP_DISPLAYNAME@"
-                  android:configChanges="keyboard|keyboardHidden|mcc|mnc"
+                  android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation"
                   android:windowSoftInputMode="stateUnspecified|adjustResize"
                   android:launchMode="singleTask"
-                  android:theme="@style/GreyTheme">
+                  android:theme="@style/Gecko">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
 
             <!-- Default browser intents -->
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
@@ -93,37 +92,52 @@
             <intent-filter>
                 <action android:name="org.mozilla.gecko.ACTION_ALERT_CLICK" />
                 <action android:name="org.mozilla.gecko.ACTION_ALERT_CLEAR" />
             </intent-filter>
         </receiver>
 
         <activity android:name="Restarter"
                   android:process="@ANDROID_PACKAGE_NAME@Restarter"
-                  android:theme="@style/GreyTheme"
+                  android:theme="@style/Gecko"
                   android:excludeFromRecents="true">
           <intent-filter>
             <action android:name="org.mozilla.gecko.restart"/>
           </intent-filter>
         </activity>
 
 #if MOZ_CRASHREPORTER
   <activity android:name="CrashReporter"
             android:label="@string/crash_reporter_title"
             android:icon="@drawable/crash_reporter"
+            android:theme="@style/Gecko"
             android:excludeFromRecents="true">
           <intent-filter>
             <action android:name="org.mozilla.gecko.reportCrash" />
           </intent-filter>
 	</activity>
 #endif
 
         <activity android:name="LauncherShortcuts"
                   android:label="@string/launcher_shortcuts_title"
-                  android:theme="@android:style/Theme.Translucent">
+                  android:theme="@style/Gecko.Translucent">
             <!--  This intent-filter allows your shortcuts to be created in the launcher. -->
             <intent-filter>
                 <action android:name="android.intent.action.CREATE_SHORTCUT" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+
+        <activity android:name="org.mozilla.gecko.AwesomeBar"
+                  android:theme="@style/Gecko.Light.NoActionBar"
+                  android:configChanges="orientation"
+                  android:windowSoftInputMode="stateAlwaysVisible|adjustResize"/>
+
+        <activity android:name="org.mozilla.gecko.TabsTray"
+                  android:theme="@style/Gecko.Translucent"/>
+
+        <activity android:name="org.mozilla.gecko.GeckoPreferences"
+                  android:theme="@style/Gecko.TitleBar"
+                  android:label="@string/preferences_title"
+                  android:excludeFromRecents="true"/>
+
     </application>
 </manifest> 
rename from embedding/android/App.java.in
rename to mobile/android/base/App.java.in
--- a/embedding/android/App.java.in
+++ b/mobile/android/base/App.java.in
@@ -39,13 +39,14 @@
 package @ANDROID_PACKAGE_NAME@;
 
 import org.mozilla.gecko.GeckoApp;
 
 public class App extends GeckoApp {
     public String getPackageName() {
 	return "@ANDROID_PACKAGE_NAME@";
     }
+
     public String getContentProcessName() {
         return "@MOZ_CHILD_PROCESS_NAME@";
     }
 };
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/AwesomeBar.java
@@ -0,0 +1,290 @@
+/* -*- 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.File;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageButton;
+
+public class AwesomeBar extends Activity {
+    private static final String LOGTAG = "GeckoAwesomeBar";
+
+    static final String URL_KEY = "url";
+    static final String TITLE_KEY = "title";
+    static final String CURRENT_URL_KEY = "currenturl";
+    static final String TYPE_KEY = "type";
+    static enum Type { ADD, EDIT };
+
+    private String mType;
+    private AwesomeBarTabs mAwesomeTabs;
+    private AwesomeBarEditText mText;
+    private ImageButton mGoButton;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Log.d(LOGTAG, "creating awesomebar");
+
+        setContentView(R.layout.awesomebar_search);
+
+        mAwesomeTabs = (AwesomeBarTabs) findViewById(R.id.awesomebar_tabs);
+        mAwesomeTabs.setOnUrlOpenListener(new AwesomeBarTabs.OnUrlOpenListener() {
+            public void onUrlOpen(AwesomeBarTabs tabs, String url) {
+                openUrlAndFinish(url);
+            }
+        });
+
+        mGoButton = (ImageButton) findViewById(R.id.awesomebar_button);
+        mGoButton.setOnClickListener(new Button.OnClickListener() {
+            public void onClick(View v) {
+                openUrlAndFinish(mText.getText().toString());
+            }
+        });
+
+        mText = (AwesomeBarEditText) findViewById(R.id.awesomebar_text);
+
+        Resources resources = getResources();
+        
+        int padding[] = { mText.getPaddingLeft(),
+                          mText.getPaddingTop(),
+                          mText.getPaddingRight(),
+                          mText.getPaddingBottom() };
+
+        GeckoStateListDrawable states = new GeckoStateListDrawable();
+        states.initializeFilter(GeckoApp.mBrowserToolbar.getHighlightColor());
+        states.addState(new int[] { android.R.attr.state_focused }, resources.getDrawable(R.drawable.address_bar_url_pressed));
+        states.addState(new int[] { android.R.attr.state_pressed }, resources.getDrawable(R.drawable.address_bar_url_pressed));
+        states.addState(new int[] { }, resources.getDrawable(R.drawable.address_bar_url_default));
+        mText.setBackgroundDrawable(states);
+
+        mText.setPadding(padding[0], padding[1], padding[2], padding[3]);
+
+        Intent intent = getIntent();
+        String currentUrl = intent.getStringExtra(CURRENT_URL_KEY);
+        mType = intent.getStringExtra(TYPE_KEY);
+        if (currentUrl != null) {
+            mText.setText(currentUrl);
+            mText.selectAll();
+        }
+
+        mText.setOnKeyPreImeListener(new AwesomeBarEditText.OnKeyPreImeListener() {
+            public boolean onKeyPreIme(View v, int keyCode, KeyEvent event) {
+                InputMethodManager imm =
+                        (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+
+                // If input method is in fullscreen mode, we want to dismiss
+                // it instead of closing awesomebar straight away.
+                if (!imm.isFullscreenMode() && keyCode == KeyEvent.KEYCODE_BACK) {
+                    cancelAndFinish();
+                    return true;
+                }
+
+                return false;
+            }
+        });
+
+        mText.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) {
+                String text = s.toString();
+
+                mAwesomeTabs.filter(text);
+                updateGoButton(text);
+            }
+        });
+
+        mText.setOnKeyListener(new View.OnKeyListener() {
+            public boolean onKey(View v, int keyCode, KeyEvent event) {
+                if (keyCode == KeyEvent.KEYCODE_ENTER) {
+                    if (event.getAction() != KeyEvent.ACTION_DOWN)
+                        return true;
+
+                    openUrlAndFinish(mText.getText().toString());
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        });
+
+        mText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (!hasFocus) {
+                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfiguration) {
+        super.onConfigurationChanged(newConfiguration);
+    }
+
+    @Override
+    public boolean onSearchRequested() {
+        cancelAndFinish();
+        return true;
+    }
+
+    private void updateGoButton(String text) {
+        if (text.length() == 0) {
+            mGoButton.setVisibility(View.GONE);
+            return;
+        }
+
+        mGoButton.setVisibility(View.VISIBLE);
+
+        int imageResource = R.drawable.ic_awesomebar_go;
+        if (!GeckoAppShell.canCreateFixupURI(text)) {
+            imageResource = R.drawable.ic_awesomebar_search;
+        }
+
+        mGoButton.setImageResource(imageResource);
+    }
+
+    private void cancelAndFinish() {
+        setResult(Activity.RESULT_CANCELED);
+        finish();
+    }
+
+    private void openUrlAndFinish(String url) {
+        Intent resultIntent = new Intent();
+        resultIntent.putExtra(URL_KEY, url);
+        resultIntent.putExtra(TYPE_KEY, mType);
+
+        setResult(Activity.RESULT_OK, resultIntent);
+        finish();
+        overridePendingTransition(0, 0);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        // This method is called only if the key event was not handled
+        // by any of the views, which usually means the edit box lost focus
+        if (keyCode == KeyEvent.KEYCODE_BACK ||
+            keyCode == KeyEvent.KEYCODE_MENU ||
+            keyCode == KeyEvent.KEYCODE_SEARCH ||
+            keyCode == KeyEvent.KEYCODE_DPAD_UP ||
+            keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
+            keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
+            keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
+            keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
+            keyCode == KeyEvent.KEYCODE_DEL) {
+            return super.onKeyDown(keyCode, event);
+        } else {
+            int selStart = -1;
+            int selEnd = -1;
+            if (mText.hasSelection()) {
+                selStart = mText.getSelectionStart();
+                selEnd = mText.getSelectionEnd();
+            }
+
+            // Return focus to the edit box, and dispatch the event to it
+            mText.requestFocusFromTouch();
+
+            if (selStart >= 0) {
+                // Restore the selection, which gets lost due to the focus switch
+                mText.setSelection(selStart, selEnd);
+            }
+
+            mText.dispatchKeyEvent(event);
+            return true;
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mAwesomeTabs.destroy();
+    }
+
+    public static class AwesomeBarEditText extends EditText {
+        OnKeyPreImeListener mOnKeyPreImeListener;
+
+        public interface OnKeyPreImeListener {
+            public boolean onKeyPreIme(View v, int keyCode, KeyEvent event);
+        }
+
+        public AwesomeBarEditText(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            mOnKeyPreImeListener = null;
+        }
+
+        @Override
+        public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+            if (mOnKeyPreImeListener != null)
+                return mOnKeyPreImeListener.onKeyPreIme(this, keyCode, event);
+
+            return false;
+        }
+
+        public void setOnKeyPreImeListener(OnKeyPreImeListener listener) {
+            mOnKeyPreImeListener = listener;
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/AwesomeBarTabs.java
@@ -0,0 +1,633 @@
+/* -*- 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) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Lucas Rocha <lucasr@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 android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.LightingColorFilter;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.provider.Browser;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ExpandableListView;
+import android.widget.FilterQueryProvider;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.SimpleExpandableListAdapter;
+import android.widget.TabHost;
+import android.widget.TextView;
+
+import java.lang.ref.WeakReference;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class AwesomeBarTabs extends TabHost {
+    private static final String LOGTAG = "GeckoAwesomeBarTabs";
+
+    private static final String ALL_PAGES_TAB = "all";
+    private static final String BOOKMARKS_TAB = "bookmarks";
+    private static final String HISTORY_TAB = "history";
+
+    private static enum HistorySection { TODAY, YESTERDAY, WEEK, OLDER };
+
+    private Context mContext;
+    private OnUrlOpenListener mUrlOpenListener;
+    private View.OnTouchListener mListTouchListener;
+
+    private SimpleCursorAdapter mAllPagesAdapter;
+    private SimpleCursorAdapter mBookmarksAdapter;
+    private SimpleExpandableListAdapter mHistoryAdapter;
+
+    // FIXME: This value should probably come from a
+    // prefs key (just like XUL-based fennec)
+    private static final int MAX_RESULTS = 100;
+
+    public interface OnUrlOpenListener {
+        public abstract void onUrlOpen(AwesomeBarTabs tabs, String url);
+    }
+
+    private class HistoryListAdapter extends SimpleExpandableListAdapter {
+        public HistoryListAdapter(Context context, List<? extends Map<String, ?>> groupData,
+                int groupLayout, String[] groupFrom, int[] groupTo,
+                List<? extends List<? extends Map<String, ?>>> childData,
+                int childLayout, String[] childFrom, int[] childTo) {
+
+            super(context, groupData, groupLayout, groupFrom, groupTo,
+                  childData, childLayout, childFrom, childTo);
+        }
+
+        @Override
+        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+                View convertView, ViewGroup parent) {
+
+            View childView =
+                    super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent); 
+
+            @SuppressWarnings("unchecked")
+            Map<String,Object> historyItem =
+                    (Map<String,Object>) mHistoryAdapter.getChild(groupPosition, childPosition);
+
+            byte[] b = (byte[]) historyItem.get(Browser.BookmarkColumns.FAVICON);
+            ImageView favicon = (ImageView) childView.findViewById(R.id.favicon);
+
+            if (b == null) {
+                favicon.setImageResource(R.drawable.favicon);
+            } else {
+                Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
+                favicon.setImageBitmap(bitmap);
+            }
+
+            return childView;
+        }
+    }
+
+    private class AwesomeCursorViewBinder implements SimpleCursorAdapter.ViewBinder {
+        private boolean updateFavicon(View view, Cursor cursor, int faviconIndex) {
+            byte[] b = cursor.getBlob(faviconIndex);
+            ImageView favicon = (ImageView) view;
+
+            if (b == null) {
+                favicon.setImageResource(R.drawable.favicon);
+            } else {
+                Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
+                favicon.setImageBitmap(bitmap);
+            }
+
+            return true;
+        }
+
+        private boolean updateTitle(View view, Cursor cursor, int titleIndex) {
+            String title = cursor.getString(titleIndex);
+            TextView titleView = (TextView)view;
+            // Use the URL instead of an empty title for consistency with the normal URL
+            // bar view - this is the equivalent of getDisplayTitle() in Tab.java
+            if (title == null || title.length() == 0) {
+                int urlIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.URL);
+                title = cursor.getString(urlIndex);
+            }
+
+            titleView.setText(title);
+            return true;
+        }
+
+        @Override
+        public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
+            int faviconIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON);
+            if (columnIndex == faviconIndex) {
+                return updateFavicon(view, cursor, faviconIndex);
+            }
+
+            int titleIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.TITLE);
+            if (columnIndex == titleIndex) {
+                return updateTitle(view, cursor, titleIndex);
+            }
+
+            // Other columns are handled automatically
+            return false;
+        }
+    }
+
+    private class BookmarksQueryTask extends AsyncTask<Void, Void, Cursor> {
+        protected Cursor doInBackground(Void... arg0) {
+            ContentResolver resolver = mContext.getContentResolver();
+
+            return resolver.query(Browser.BOOKMARKS_URI,
+                                  null,
+                                  // Select all bookmarks with a non-empty URL. When the history
+                                  // is empty there appears to be a dummy entry in the database
+                                  // which has a title of "Bookmarks" and no URL; the length restriction
+                                  // is to avoid picking that up specifically.
+                                  Browser.BookmarkColumns.BOOKMARK + " = 1 AND LENGTH(" + Browser.BookmarkColumns.URL + ") > 0",
+                                  null,
+                                  Browser.BookmarkColumns.TITLE);
+        }
+
+        protected void onPostExecute(Cursor cursor) {
+            // Load the list using a custom adapter so we can create the bitmaps
+            mBookmarksAdapter = new SimpleCursorAdapter(
+                mContext,
+                R.layout.awesomebar_row,
+                cursor,
+                new String[] { AwesomeBar.TITLE_KEY,
+                               AwesomeBar.URL_KEY,
+                               Browser.BookmarkColumns.FAVICON },
+                new int[] { R.id.title, R.id.url, R.id.favicon }
+            );
+
+            mBookmarksAdapter.setViewBinder(new AwesomeCursorViewBinder());
+
+            final ListView bookmarksList = (ListView) findViewById(R.id.bookmarks_list);
+
+            bookmarksList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                    handleItemClick(bookmarksList, position);
+                }
+            });
+
+            bookmarksList.setAdapter(mBookmarksAdapter);
+        }
+    }
+
+    private class HistoryQueryTask extends AsyncTask<Void, Void, Pair<List,List>> {
+        private static final long MS_PER_DAY = 86400000;
+        private static final long MS_PER_WEEK = MS_PER_DAY * 7;
+
+        protected Pair<List,List> doInBackground(Void... arg0) {
+            Pair<List,List> result = null;
+            ContentResolver resolver = mContext.getContentResolver();
+
+            Cursor cursor =
+                    resolver.query(Browser.BOOKMARKS_URI,
+                                   null,
+                                   // Bookmarks that have not been visited have a date value
+                                   // of 0, so don't pick them up in the history view.
+                                   Browser.BookmarkColumns.DATE + " > 0",
+                                   null,
+                                   Browser.BookmarkColumns.DATE + " DESC LIMIT " + MAX_RESULTS);
+
+            Date now = new Date();
+            now.setHours(0);
+            now.setMinutes(0);
+            now.setSeconds(0);
+
+            long today = now.getTime();
+
+            // Split the list of urls into separate date range groups
+            // and show it in an expandable list view.
+            List<List<Map<String,?>>> childrenLists = null;
+            List<Map<String,?>> children = null;
+            List<Map<String,?>> groups = null;
+            HistorySection section = null;
+
+            // Move cursor before the first row in preparation
+            // for the iteration.
+            cursor.moveToPosition(-1);
+
+            // Split the history query results into adapters per time
+            // section (today, yesterday, week, older). Queries on content
+            // Browser content provider don't support limitting the number
+            // of returned rows so we limit it here.
+            while (cursor.moveToNext()) {
+                long time = cursor.getLong(cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.DATE));
+                HistorySection itemSection = getSectionForTime(time, today);
+
+                if (groups == null)
+                    groups = new LinkedList<Map<String,?>>();
+
+                if (childrenLists == null)
+                    childrenLists = new LinkedList<List<Map<String,?>>>();
+
+                if (section != itemSection) {
+                    if (section != null) {
+                        groups.add(createGroupItem(section));
+                        childrenLists.add(children);
+                    }
+
+                    section = itemSection;
+                    children = new LinkedList<Map<String,?>>();
+                }
+
+                children.add(createHistoryItem(cursor));
+            }
+
+            // Add any remaining section to the list if it hasn't
+            // been added to the list after the loop.
+            if (section != null && children != null) {
+                groups.add(createGroupItem(section));
+                childrenLists.add(children);
+            }
+
+            // Close the query cursor as we won't use it anymore
+            cursor.close();
+
+            if (groups != null && childrenLists != null) {
+                result = Pair.create((List) groups, (List) childrenLists);
+            }
+
+            return result;
+        }
+
+        public Map<String,?> createHistoryItem(Cursor cursor) {
+            Map<String,Object> historyItem = new HashMap<String,Object>();
+
+            String url = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.URL_KEY));
+            String title = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.TITLE_KEY));
+            byte[] favicon = cursor.getBlob(cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON));
+
+            // Use the URL instead of an empty title for consistency with the normal URL
+            // bar view - this is the equivalent of getDisplayTitle() in Tab.java
+            if (title == null || title.length() == 0)
+                title = url;
+
+            historyItem.put(AwesomeBar.URL_KEY, url);
+            historyItem.put(AwesomeBar.TITLE_KEY, title);
+
+            if (favicon != null)
+                historyItem.put(Browser.BookmarkColumns.FAVICON, favicon);
+
+            return historyItem;
+        }
+
+        public Map<String,?> createGroupItem(HistorySection section) {
+            Map<String,String> groupItem = new HashMap<String,String>();
+
+            groupItem.put(AwesomeBar.TITLE_KEY, getSectionName(section));
+
+            return groupItem;
+        }
+
+        private String getSectionName(HistorySection section) {
+            Resources resources = mContext.getResources();
+
+            switch (section) {
+            case TODAY:
+                return resources.getString(R.string.history_today_section);
+            case YESTERDAY:
+                return resources.getString(R.string.history_yesterday_section);
+            case WEEK:
+                return resources.getString(R.string.history_week_section);
+            case OLDER:
+                return resources.getString(R.string.history_older_section);
+            }
+
+            return null;
+        }
+
+        private void expandAllGroups(ExpandableListView historyList) {
+            int groupCount = mHistoryAdapter.getGroupCount();
+
+            for (int i = 0; i < groupCount; i++) {
+                historyList.expandGroup(i);
+            }
+        }
+
+        private HistorySection getSectionForTime(long time, long today) {
+            long delta = today - time;
+
+            if (delta < 0) {
+                return HistorySection.TODAY;
+            } else if (delta > 0 && delta < MS_PER_DAY) {
+                return HistorySection.YESTERDAY;
+            } else if (delta > MS_PER_DAY && delta < MS_PER_WEEK) {
+                return HistorySection.WEEK;
+            }
+
+            return HistorySection.OLDER;
+        }
+
+        @SuppressWarnings("unchecked")
+        protected void onPostExecute(Pair<List,List> result) {
+            // FIXME: display some sort of message when there's no history
+            if (result == null)
+                return;
+
+            mHistoryAdapter = new HistoryListAdapter(
+                mContext,
+                result.first,
+                R.layout.awesomebar_header_row,
+                new String[] { AwesomeBar.TITLE_KEY },
+                new int[] { R.id.title },
+                result.second,
+                R.layout.awesomebar_row,
+                new String[] { AwesomeBar.TITLE_KEY, AwesomeBar.URL_KEY },
+                new int[] { R.id.title, R.id.url }
+            );
+
+            final ExpandableListView historyList =
+                    (ExpandableListView) findViewById(R.id.history_list);
+
+            historyList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
+                public boolean onChildClick(ExpandableListView parent, View view,
+                        int groupPosition, int childPosition, long id) {
+                    handleHistoryItemClick(groupPosition, childPosition);
+                    return true;
+                }
+            });
+
+            // This is to disallow collapsing the expandable groups in the
+            // history expandable list view to mimic simpler sections. We should
+            // Remove this if we decide to allow expanding/collapsing groups.
+            historyList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
+                public boolean onGroupClick(ExpandableListView parent, View v,
+                        int groupPosition, long id) {
+                    return true;
+                }
+            });
+
+            historyList.setAdapter(mHistoryAdapter);
+
+            expandAllGroups(historyList);
+        }
+    }
+
+    public AwesomeBarTabs(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        Log.d(LOGTAG, "Creating AwesomeBarTabs");
+
+        mContext = context;
+
+        // Load layout into the custom view
+        LayoutInflater inflater =
+                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        inflater.inflate(R.layout.awesomebar_tabs, this);
+
+        // This should be called before adding any tabs
+        // to the TabHost.
+        setup();
+
+        mListTouchListener = new View.OnTouchListener() {
+            public boolean onTouch(View view, MotionEvent event) {
+                hideSoftInput(view);
+                return false;
+            }
+        };
+
+        addAllPagesTab();
+        addBookmarksTab();
+        addHistoryTab();
+
+        setOnTabChangedListener(new TabHost.OnTabChangeListener() {
+            @Override
+            public void onTabChanged(String tabId) {
+                boolean hideSoftInput = true;
+
+                // Lazy load bookmarks and history lists. Only query the database
+                // if those lists requested by user.
+                if (tabId.equals(BOOKMARKS_TAB) && mBookmarksAdapter == null) {
+                    new BookmarksQueryTask().execute();
+                } else if (tabId.equals(HISTORY_TAB) && mHistoryAdapter == null) {
+                    new HistoryQueryTask().execute();
+                } else {
+                    hideSoftInput = false;
+                }
+
+                // Always dismiss SKB when changing to lazy-loaded tabs
+                if (hideSoftInput) {
+                    View tabView = getCurrentTabView();
+                    hideSoftInput(tabView);
+                }
+            }
+        });
+
+        // Initialize "App Pages" list with no filter
+        filter("");
+    }
+
+    private TabSpec addAwesomeTab(String id, int titleId, int contentId) {
+        TabSpec tab = newTabSpec(id);
+
+        LayoutInflater inflater =
+                (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        View indicatorView = inflater.inflate(R.layout.awesomebar_tab_indicator, null);
+        Drawable background = indicatorView.getBackground();
+        try {
+            background.setColorFilter(new LightingColorFilter(Color.WHITE, GeckoApp.mBrowserToolbar.getHighlightColor()));
+        } catch (Exception e) {
+            Log.d(LOGTAG, "background.setColorFilter failed " + e);            
+        }
+        TextView title = (TextView) indicatorView.findViewById(R.id.title);
+        title.setText(titleId);
+
+        tab.setIndicator(indicatorView);
+        tab.setContent(contentId);
+
+        addTab(tab);
+
+        return tab;
+    }
+
+    private void addAllPagesTab() {
+        Log.d(LOGTAG, "Creating All Pages tab");
+
+        addAwesomeTab(ALL_PAGES_TAB,
+                      R.string.awesomebar_all_pages_title,
+                      R.id.all_pages_list);
+
+        // Load the list using a custom adapter so we can create the bitmaps
+        mAllPagesAdapter = new SimpleCursorAdapter(
+            mContext,
+            R.layout.awesomebar_row,
+            null,
+            new String[] { AwesomeBar.TITLE_KEY,
+                           AwesomeBar.URL_KEY,
+                           Browser.BookmarkColumns.FAVICON },
+            new int[] { R.id.title, R.id.url, R.id.favicon }
+        );
+
+        mAllPagesAdapter.setViewBinder(new AwesomeCursorViewBinder());
+
+        mAllPagesAdapter.setFilterQueryProvider(new FilterQueryProvider() {
+            public Cursor runQuery(CharSequence constraint) {
+                ContentResolver resolver = mContext.getContentResolver();
+
+                return resolver.query(Browser.BOOKMARKS_URI,
+                                      null,
+                                      // The length restriction on URL is for the same reason as in the general bookmark query
+                                      // (see comment earlier in this file).
+                                      "(" + Browser.BookmarkColumns.URL + " LIKE ? OR " + Browser.BookmarkColumns.TITLE + " LIKE ?)"
+                                        + " AND LENGTH(" + Browser.BookmarkColumns.URL + ") > 0", 
+                                      new String[] {"%" + constraint.toString() + "%", "%" + constraint.toString() + "%",},
+                                      // ORDER BY is number of visits times a multiplier from 1 - 120 of how recently the site 
+                                      // was accessed with a site accessed today getting 120 and a site accessed 119 or more 
+                                      // days ago getting 1
+                                      Browser.BookmarkColumns.VISITS + " * MAX(1, (" +
+                                      Browser.BookmarkColumns.DATE + " - " + new Date().getTime() + ") / 86400000 + 120) DESC LIMIT " + MAX_RESULTS);
+            }
+        });
+
+        final ListView allPagesList = (ListView) findViewById(R.id.all_pages_list);
+
+        allPagesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                handleItemClick(allPagesList, position);
+            }
+        });
+
+        allPagesList.setAdapter(mAllPagesAdapter);
+        allPagesList.setOnTouchListener(mListTouchListener);
+    }
+
+    private void addBookmarksTab() {
+        Log.d(LOGTAG, "Creating Bookmarks tab");
+
+        addAwesomeTab(BOOKMARKS_TAB,
+                      R.string.awesomebar_bookmarks_title,
+                      R.id.bookmarks_list);
+
+        ListView bookmarksList = (ListView) findViewById(R.id.bookmarks_list);
+        bookmarksList.setOnTouchListener(mListTouchListener);
+
+        // Only load bookmark list when tab is actually used.
+        // See OnTabChangeListener above.
+    }
+
+    private void addHistoryTab() {
+        Log.d(LOGTAG, "Creating History tab");
+
+        addAwesomeTab(HISTORY_TAB,
+                      R.string.awesomebar_history_title,
+                      R.id.history_list);
+
+        ListView historyList = (ListView) findViewById(R.id.history_list);
+        historyList.setOnTouchListener(mListTouchListener);
+
+        // Only load history list when tab is actually used.
+        // See OnTabChangeListener above.
+    }
+
+    private void hideSoftInput(View view) {
+        InputMethodManager imm =
+                (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+
+        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
+    }
+
+    private void handleHistoryItemClick(int groupPosition, int childPosition) {
+        @SuppressWarnings("unchecked")
+        Map<String,Object> historyItem =
+                (Map<String,Object>) mHistoryAdapter.getChild(groupPosition, childPosition);
+
+        String url = (String) historyItem.get(AwesomeBar.URL_KEY);
+
+        if (mUrlOpenListener != null)
+            mUrlOpenListener.onUrlOpen(this, url);
+    }
+
+    private void handleItemClick(ListView list, int position) {
+        Cursor cursor = (Cursor) list.getItemAtPosition(position);
+        String url = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.URL_KEY));
+
+        if (mUrlOpenListener != null)
+            mUrlOpenListener.onUrlOpen(this, url);
+    }
+
+    public void setOnUrlOpenListener(OnUrlOpenListener listener) {
+        mUrlOpenListener = listener;
+    }
+
+    public void destroy() {
+        Cursor allPagesCursor = mAllPagesAdapter.getCursor();
+        if (allPagesCursor != null)
+            allPagesCursor.close();
+
+        if (mBookmarksAdapter != null) {
+            Cursor bookmarksCursor = mBookmarksAdapter.getCursor();
+            if (bookmarksCursor != null)
+                bookmarksCursor.close();
+        }
+    }
+
+    public void filter(String searchTerm) {
+        // Don't let the tab's content steal focus on tab switch
+        setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+
+        // Ensure the 'All Pages' tab is selected
+        setCurrentTabByTag(ALL_PAGES_TAB);
+
+        // Restore normal focus behavior on tab host
+        setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+
+        // The tabs should only be visible if there's no on-going search
+        int tabsVisibility = (searchTerm.length() == 0 ? View.VISIBLE : View.GONE);
+        getTabWidget().setVisibility(tabsVisibility);
+
+        // Perform the actual search
+        mAllPagesAdapter.getFilter().filter(searchTerm);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/BrowserToolbar.java
@@ -0,0 +1,269 @@
+/* -*- 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) 2009-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *   Matt Brubeck <mbrubeck@mozilla.com>
+ *   Vivien Nicolas <vnicolas@mozilla.com>
+ *   Lucas Rocha <lucasr@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 android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.Typeface;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.animation.TranslateAnimation;
+import android.view.Gravity;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.TextSwitcher;
+import android.widget.ViewSwitcher.ViewFactory;
+
+public class BrowserToolbar extends LinearLayout {
+    final private Button mAwesomeBar;
+    final private ImageButton mTabs;
+    final public ImageButton mFavicon;
+    final public ImageButton mStop;
+    final public ImageButton mSiteSecurity;
+    final private AnimationDrawable mProgressSpinner;
+    final private TextSwitcher mTabsCount;
+
+    final private Context mContext;
+    final private Handler mHandler;
+    final private int mColor;
+    final private int mCounterColor;
+
+    final private int mDuration;
+    final private TranslateAnimation mSlideUpIn;
+    final private TranslateAnimation mSlideUpOut;
+    final private TranslateAnimation mSlideDownIn;
+    final private TranslateAnimation mSlideDownOut;
+
+    private int mCount;
+
+    public BrowserToolbar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mContext = context;
+
+        // Get the device's highlight color
+        ContextThemeWrapper wrapper = new ContextThemeWrapper(mContext, android.R.style.TextAppearance);
+        TypedArray typedArray = wrapper.getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorHighlight });
+        mColor = typedArray.getColor(typedArray.getIndex(0), 0);
+
+        // Load layout into the custom view
+        LayoutInflater inflater =
+                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        inflater.inflate(R.layout.browser_toolbar, this);
+
+        mAwesomeBar = (Button) findViewById(R.id.awesome_bar);
+        mAwesomeBar.setOnClickListener(new Button.OnClickListener() {
+            public void onClick(View v) {
+                onAwesomeBarSearch();
+            }
+        });
+
+        Resources resources = getResources();
+        
+        int padding[] = { mAwesomeBar.getPaddingLeft(),
+                          mAwesomeBar.getPaddingTop(),
+                          mAwesomeBar.getPaddingRight(),
+                          mAwesomeBar.getPaddingBottom() };
+
+        GeckoStateListDrawable states = new GeckoStateListDrawable();
+        states.initializeFilter(mColor);
+        states.addState(new int[] { android.R.attr.state_pressed }, resources.getDrawable(R.drawable.address_bar_url_pressed));
+        states.addState(new int[] { }, resources.getDrawable(R.drawable.address_bar_url_default));
+        mAwesomeBar.setBackgroundDrawable(states);
+
+        mAwesomeBar.setPadding(padding[0], padding[1], padding[2], padding[3]);
+
+        mTabs = (ImageButton) findViewById(R.id.tabs);
+        mTabs.setOnClickListener(new Button.OnClickListener() {
+            public void onClick(View v) {
+                if (Tabs.getInstance().getCount() > 1)
+                    showTabs();
+                else
+                    addTab();
+            }
+        });
+        mTabs.setImageLevel(1);
+
+        mCounterColor = 0x99ffffff;
+
+        mTabsCount = (TextSwitcher) findViewById(R.id.tabs_count);
+        mTabsCount.setFactory(new ViewFactory() {
+            public View makeView() {
+                TextView text = new TextView(mContext);
+                text.setGravity(Gravity.CENTER);
+                text.setTextSize(16);
+                text.setTextColor(mCounterColor);
+                text.setTypeface(text.getTypeface(), Typeface.BOLD);
+                return text;
+            } 
+        });
+        mCount = 0;
+        mTabsCount.setText("0");
+
+        mFavicon = (ImageButton) findViewById(R.id.favicon);
+        mSiteSecurity = (ImageButton) findViewById(R.id.site_security);
+        mProgressSpinner = (AnimationDrawable) resources.getDrawable(R.drawable.progress_spinner);
+        
+        mStop = (ImageButton) findViewById(R.id.stop);
+        mStop.setOnClickListener(new Button.OnClickListener() {
+            public void onClick(View v) {
+                doStop();
+            }
+        });
+
+        mHandler = new Handler();
+        mSlideUpIn = new TranslateAnimation(0, 0, 30, 0);
+        mSlideUpOut = new TranslateAnimation(0, 0, 0, -30);
+        mSlideDownIn = new TranslateAnimation(0, 0, -30, 0);
+        mSlideDownOut = new TranslateAnimation(0, 0, 0, 30);
+
+        mDuration = 750;
+        mSlideUpIn.setDuration(mDuration);
+        mSlideUpOut.setDuration(mDuration);
+        mSlideDownIn.setDuration(mDuration);
+        mSlideDownOut.setDuration(mDuration);
+    }
+
+    private void onAwesomeBarSearch() {
+        GeckoApp.mAppContext.onEditRequested();
+    }
+
+    private void addTab() {
+        GeckoApp.mAppContext.addTab();
+    }
+
+    private void showTabs() {
+        GeckoApp.mAppContext.showTabs();
+    }
+
+    private void doStop() {
+        GeckoApp.mAppContext.doStop();
+    }
+
+    public int getHighlightColor() {
+        return mColor;
+    }
+    
+    public void updateTabs(int count) {
+        if (mCount > count) {
+            mTabsCount.setInAnimation(mSlideDownIn);
+            mTabsCount.setOutAnimation(mSlideDownOut);
+        } else if (mCount < count) {
+            mTabsCount.setInAnimation(mSlideUpIn);
+            mTabsCount.setOutAnimation(mSlideUpOut);
+        }
+
+        if (count > 1)
+            mTabs.setImageLevel(count);
+        else
+            mTabs.setImageLevel(0);
+
+        mTabsCount.setVisibility(View.VISIBLE);
+        mTabsCount.setText(String.valueOf(count));
+        mCount = count;
+
+        mHandler.postDelayed(new Runnable() {
+            public void run() {
+                ((TextView) mTabsCount.getCurrentView()).setTextColor(mColor);
+            }
+        }, mDuration);
+
+        mHandler.postDelayed(new Runnable() {
+            public void run() {
+                if (Tabs.getInstance().getCount() == 1) {
+                    mTabs.setImageLevel(1);
+                    mTabsCount.setVisibility(View.GONE);
+                    ((TextView) mTabsCount.getCurrentView()).setTextColor(mCounterColor);
+                } else {
+                    ((TextView) mTabsCount.getCurrentView()).setTextColor(mCounterColor);
+                }
+            }
+        }, 2 * mDuration);
+    }
+
+    public void setProgressVisibility(boolean visible) {
+        if (visible) {
+            mFavicon.setImageDrawable(mProgressSpinner);
+            mProgressSpinner.start();
+            setStopVisibility(true);
+        } else {
+            mProgressSpinner.stop();
+            setStopVisibility(false);
+            setFavicon(Tabs.getInstance().getSelectedTab().getFavicon());
+        }
+    }
+
+    public void setStopVisibility(boolean visible) {
+        mStop.setVisibility(visible ? View.VISIBLE : View.GONE);
+        mSiteSecurity.setVisibility(visible ? View.GONE : View.VISIBLE);
+    }
+
+    public void setTitle(CharSequence title) {
+        mAwesomeBar.setText(title);
+    }
+
+    public void setFavicon(Drawable image) {
+        if (Tabs.getInstance().getSelectedTab().isLoading())
+            return;
+
+        if (image != null)
+            mFavicon.setImageDrawable(image);
+        else
+            mFavicon.setImageResource(R.drawable.favicon);
+    }
+    
+    public void setSecurityMode(String mode) {
+        if (mode.equals("identified") || mode.equals("verified"))
+            mSiteSecurity.setImageLevel(1);
+        else
+            mSiteSecurity.setImageLevel(0);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/ConfirmPreference.java
@@ -0,0 +1,79 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 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 Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brad Lassey <blassey@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 android.content.Context;
+import android.preference.DialogPreference;
+import android.provider.Browser;
+import android.util.AttributeSet;
+import android.util.Log;
+
+class ConfirmPreference extends DialogPreference {
+    private static final String LOGTAG = "GeckoConfirmPreference";
+
+    private String mAction = null;
+    private Context mContext = null;
+    public ConfirmPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mAction = attrs.getAttributeValue(null, "action");
+        mContext = context;
+    }
+    public ConfirmPreference(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mAction = attrs.getAttributeValue(null, "action");
+        mContext = context;
+    }
+    protected void onDialogClosed(boolean positiveResult) {
+        if (!positiveResult)
+            return;
+        if ("clear_history".equalsIgnoreCase(mAction)) {
+            GeckoAppShell.getHandler().post(new Runnable(){
+                public void run() {
+                    Browser.clearHistory(mContext.getContentResolver());
+                }
+            });
+        } else if ("clear_private_data".equalsIgnoreCase(mAction)) {
+            GeckoAppShell.getHandler().post(new Runnable(){
+                public void run() {
+                    GeckoAppShell.sendEventToGecko(new GeckoEvent("Sanitize:ClearAll", null));
+                }
+            });
+        }
+        Log.i(LOGTAG, "action: " + mAction);
+    }
+}
rename from embedding/android/CrashReporter.java.in
rename to mobile/android/base/CrashReporter.java.in
--- a/embedding/android/CrashReporter.java.in
+++ b/mobile/android/base/CrashReporter.java.in
@@ -33,304 +33,304 @@
  * 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 ***** */
 
 #filter substitution
 package @ANDROID_PACKAGE_NAME@;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
 
-import android.app.*;
-import android.content.*;
-import android.os.*;
-import android.util.*;
-import android.view.*;
-import android.view.View.*;
-import android.widget.*;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
 
-import org.mozilla.gecko.*;
-import java.util.*;
-import java.io.*;
-import java.net.*;
-import java.nio.channels.*;
+import org.mozilla.gecko.R;
 
 public class CrashReporter extends Activity
 {
-  static final String kMiniDumpPathKey = "upload_file_minidump";
-  static final String kPageURLKey = "URL";
-  static final String kNotesKey = "Notes";
-  Handler mHandler = null;
-  ProgressDialog mProgressDialog;
-  File mPendingMinidumpFile;
-  File mPendingExtrasFile;
-  HashMap<String, String> mExtrasStringMap;
+    private static final String LOGTAG = "GeckoCrashReporter";
+
+    private static final String PASSED_MINI_DUMP_KEY = "minidumpPath";
+    private static final String MINI_DUMP_PATH_KEY = "upload_file_minidump";
+    private static final String PAGE_URL_KEY = "URL";
+    private static final String NOTES_KEY = "Notes";
+    private static final String SERVER_URL_KEY = "ServerURL";
+
+    private static final String CRASH_REPORT_DIR = "/data/data/@ANDROID_PACKAGE_NAME@/files/mozilla/Crash Reports/";
+    private static final String PENDING_DIR = CRASH_REPORT_DIR + "pending";
+    private static final String SUBMITTED_DIR = CRASH_REPORT_DIR + "submitted";
+
+    private Handler mHandler;
+    private ProgressDialog mProgressDialog;
+    private File mPendingMinidumpFile;
+    private File mPendingExtrasFile;
+    private HashMap<String, String> mExtrasStringMap;
 
-  boolean moveFile(File inFile, File outFile)
-  {
-    Log.i("GeckoCrashReporter", "moving " + inFile + " to " + outFile);
-    if (inFile.renameTo(outFile))
-      return true;
-    try {
-      outFile.createNewFile();
-      Log.i("GeckoCrashReporter", "couldn't rename minidump file");
-      // so copy it instead
-      FileChannel inChannel = new FileInputStream(inFile).getChannel();
-      FileChannel outChannel = new FileOutputStream(outFile).getChannel();
-      long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
-      inChannel.close();
-      outChannel.close();
+    private boolean moveFile(File inFile, File outFile) {
+        Log.i(LOGTAG, "moving " + inFile + " to " + outFile);
+        if (inFile.renameTo(outFile))
+            return true;
+        try {
+            outFile.createNewFile();
+            Log.i(LOGTAG, "couldn't rename minidump file");
+            // so copy it instead
+            FileChannel inChannel = new FileInputStream(inFile).getChannel();
+            FileChannel outChannel = new FileOutputStream(outFile).getChannel();
+            long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
+            inChannel.close();
+            outChannel.close();
 
-      if (transferred > 0)
-        inFile.delete();
-    } catch (Exception e) {
-      Log.e("GeckoCrashReporter",
-            "exception while copying minidump file: ", e);
-      return false;
+            if (transferred > 0)
+                inFile.delete();
+        } catch (Exception e) {
+            Log.e(LOGTAG, "exception while copying minidump file: ", e);
+            return false;
+        }
+        return true;
     }
-    return true;
-  }
 
-  void doFinish() {
-    if (mHandler != null) {
-      mHandler.post(new Runnable(){
-        public void run() {
-          finish();
-        }});
+    private void doFinish() {
+        if (mHandler != null) {
+            mHandler.post(new Runnable() {
+                public void run() {
+                    finish();
+                }
+            });
+        }
+    }
+
+    @Override
+    public void finish() {
+        if (mProgressDialog.isShowing()) {
+            mProgressDialog.dismiss();
+        }
+        super.finish();
     }
-  }
 
-  @Override
-  public void finish()
-  {
-    mProgressDialog.dismiss();
-    super.finish();
-  }
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // mHandler is created here so runnables can be run on the main thread
+        mHandler = new Handler();
+        setContentView(R.layout.crash_reporter);
+        mProgressDialog = new ProgressDialog(this);
+        mProgressDialog.setMessage(getString(R.string.sending_crash_report));
 
-  @Override
-  public void onCreate(Bundle savedInstanceState)
-  {
-    super.onCreate(savedInstanceState);
-    // mHandler is created here so runnables can be run on the main thread
-    mHandler = new Handler();
-    setContentView(R.layout.crash_reporter);
-    mProgressDialog = new ProgressDialog(CrashReporter.this);
-    mProgressDialog.setMessage(getString(R.string.sending_crash_report));
+        final Button restartButton = (Button) findViewById(R.id.restart);
+        final Button closeButton = (Button) findViewById(R.id.close);
+        String passedMinidumpPath = getIntent().getStringExtra(PASSED_MINI_DUMP_KEY);
+        File passedMinidumpFile = new File(passedMinidumpPath);
+        File pendingDir = new File(PENDING_DIR);
+        pendingDir.mkdirs();
+        mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName());
+        moveFile(passedMinidumpFile, mPendingMinidumpFile);
+
+        File extrasFile = new File(passedMinidumpPath.replaceAll(".dmp", ".extra"));
+        mPendingExtrasFile = new File(pendingDir, extrasFile.getName());
+        moveFile(extrasFile, mPendingExtrasFile);
+
+        mExtrasStringMap = new HashMap<String, String>();
+        readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap);
+    }
+
+    private void backgroundSendReport() {
+        final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report);
+        if (!sendReportCheckbox.isChecked()) {
+            doFinish();
+            return;
+        }
 
-    final Button restartButton = (Button) findViewById(R.id.restart);
-    final Button closeButton = (Button) findViewById(R.id.close);
-    String passedMinidumpPath = getIntent().getStringExtra("minidumpPath");
-    File passedMinidumpFile = new File(passedMinidumpPath);
-    File pendingDir =
-      new File("/data/data/@ANDROID_PACKAGE_NAME@/files/mozilla/Crash Reports/pending");
-    pendingDir.mkdirs();
-    mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName());
-    moveFile(passedMinidumpFile, mPendingMinidumpFile);
+        mProgressDialog.show();
+        new Thread(new Runnable() {
+            public void run() {
+                sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile);
+            }
+        }).start();
+    }
+
+    public void onCloseClick(View v) {  // bound via crash_reporter.xml
+        backgroundSendReport();
+    }
+
+    public void onRestartClick(View v) {  // bound via crash_reporter.xml
+        doRestart();
+        backgroundSendReport();
+    }
 
-    File extrasFile = new File(passedMinidumpPath.replaceAll(".dmp", ".extra"));
-    mPendingExtrasFile = new File(pendingDir, extrasFile.getName());
-    moveFile(extrasFile, mPendingExtrasFile);
+    private boolean readStringsFromFile(String filePath, Map<String, String> stringMap) {
+        try {
+            BufferedReader reader = new BufferedReader(new FileReader(filePath));
+            return readStringsFromReader(reader, stringMap);
+        } catch (Exception e) {
+            Log.e(LOGTAG, "exception while reading strings: ", e);
+            return false;
+        }
+    }
 
-    mExtrasStringMap = new HashMap<String, String>();
-    readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap);
-  }
-
-  void backgroundSendReport()
-  {
-    final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report);
-    if (!sendReportCheckbox.isChecked()) {
-      doFinish();
-      return;
+    private boolean readStringsFromReader(BufferedReader reader, Map<String, String> stringMap) throws IOException {
+        String line;
+        while ((line = reader.readLine()) != null) {
+            int equalsPos = -1;
+            if ((equalsPos = line.indexOf('=')) != -1) {
+                String key = line.substring(0, equalsPos);
+                String val = unescape(line.substring(equalsPos + 1));
+                stringMap.put(key, val);
+            }
+        }
+        reader.close();
+        return true;
     }
 
-    mProgressDialog.show();
-    new Thread(new Runnable() {
-      public void run() {
-        sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile);
-      }}).start();
-  }
-
-  public void onCloseClick(View v)
-  {
-    backgroundSendReport();
-  }
-
-  public void onRestartClick(View v)
-  {
-    doRestart();
-    backgroundSendReport();
-  }
-
-  boolean readStringsFromFile(String filePath, Map stringMap)
-  {
-    try {
-      BufferedReader reader = new BufferedReader(
-        new FileReader(filePath));
-      return readStringsFromReader(reader, stringMap);
-    } catch (Exception e) {
-      Log.e("GeckoCrashReporter", "exception while reading strings: ", e);
-      return false;
+    private String generateBoundary() {
+        // Generate some random numbers to fill out the boundary
+        int r0 = (int)((double)Integer.MAX_VALUE * Math.random());
+        int r1 = (int)((double)Integer.MAX_VALUE * Math.random());
+        return String.format("---------------------------%08X%08X", r0, r1);
     }
-  }
-
-  boolean readStringsFromReader(BufferedReader reader, Map stringMap)
-    throws java.io.IOException
-  {
-    String line;
-    while ((line = reader.readLine()) != null) {
-      int equalsPos = -1;
-      if ((equalsPos = line.indexOf('=')) != -1) {
-        String key = line.substring(0, equalsPos);
-        String val = unescape(line.substring(equalsPos + 1));
-        stringMap.put(key, val);
-      }
-    }
-    reader.close();
-    return true;
-  }
-
-  String generateBoundary()
-  {
-    // Generate some random numbers to fill out the boundary
-    int r0 = (int)((double)Integer.MAX_VALUE * Math.random());
-    int r1 = (int)((double)Integer.MAX_VALUE * Math.random());
-
-    return String.format("---------------------------%08X%08X", r0, r1);
-  }
-
-  void sendPart(OutputStream os, String boundary, String name, String data)
-  {
-    try {
-      os.write(("--" + boundary + "\r\n" +
-                "Content-Disposition: form-data; name=\"" +
-                name + "\"\r\n\r\n" +
-                data + "\r\n").getBytes());
-    } catch (Exception ex) {
-      Log.e("GeckoCrashReporter", "Exception when sending \"" + name + "\"", ex);
-    }
-  }
-
-  void sendFile(OutputStream os, String boundary, String name, File file)
-    throws IOException
-  {
-    os.write(("--" + boundary + "\r\n" +
-              "Content-Disposition: form-data; " +
-              "name=\"" + name + "\"; " +
-              "filename=\"" + file.getName() + "\"\r\n" +
-              "Content-Type: application/octet-stream\r\n" +
-              "\r\n").getBytes());
-    FileChannel fc =
-      new FileInputStream(file).getChannel();
-    fc.transferTo(0, fc.size(), Channels.newChannel(os));
-    fc.close();
-  }
 
-  void sendReport(File minidumpFile, Map<String, String> extras,
-                  File extrasFile)
-  {
-    Log.i("GeckoCrashReport", "sendReport: " + minidumpFile.getPath());
-    final CheckBox includeURLCheckbox = (CheckBox) findViewById(R.id.include_url);
-
-    String spec = extras.get("ServerURL");
-    if (spec == null)
-      doFinish();
-
-    Log.i("GeckoCrashReport", "server url: " + spec);
-    try {
-      URL url = new URL(spec);
-      HttpURLConnection conn = (HttpURLConnection)url.openConnection();
-      conn.setRequestMethod("POST");
-      String boundary = generateBoundary();
-      conn.setDoOutput(true);
-      conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
-
-      OutputStream os = conn.getOutputStream();
-      Iterator<String> keys = extras.keySet().iterator();
-      while (keys.hasNext()) {
-        String key = keys.next();
-        if (key.equals(kPageURLKey)) {
-          if (includeURLCheckbox.isChecked())
-            sendPart(os, boundary, key, extras.get(key));
-        } else if (!key.equals("ServerURL") && !key.equals(kNotesKey)) {
-          sendPart(os, boundary, key, extras.get(key));
+    private void sendPart(OutputStream os, String boundary, String name, String data) {
+        try {
+            os.write(("--" + boundary + "\r\n" +
+                      "Content-Disposition: form-data; name=\"" + name + "\"\r\n" +
+                      "\r\n" +
+                      data + "\r\n"
+                     ).getBytes());
+        } catch (Exception ex) {
+            Log.e(LOGTAG, "Exception when sending \"" + name + "\"", ex);
         }
-      }
-
-      // Add some extra information to notes so its displayed by 
-      // crash-stats.mozilla.org. Remove this when bug 607942 is fixed.
-      String notes = extras.containsKey(kNotesKey) ? extras.get(kNotesKey) + 
-        "\n" : "";
-      if (@MOZ_MIN_CPU_VERSION@ < 7)
-        notes += "nothumb Build\n";
-      notes += Build.MANUFACTURER + " ";
-      notes += Build.MODEL + "\n";
-      notes += Build.FINGERPRINT;
-      sendPart(os, boundary, kNotesKey, notes);
+    }
 
-      sendPart(os, boundary, "Min_ARM_Version", "@MOZ_MIN_CPU_VERSION@");
-      sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER);
-      sendPart(os, boundary, "Android_Model", Build.MODEL);
-      sendPart(os, boundary, "Android_Board", Build.BOARD);
-      sendPart(os, boundary, "Android_Brand", Build.BRAND);
-      sendPart(os, boundary, "Android_Device", Build.DEVICE);
-      sendPart(os, boundary, "Android_Display", Build.DISPLAY);
-      sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT);
-      sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI); 
-      if (Build.VERSION.SDK_INT >= 8) {
-        try {
-          sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2);
-          sendPart(os, boundary, "Android_Hardware", Build.HARDWARE);
-        } catch (Exception ex) {
-          Log.e("GeckoCrashReporter", "Exception while sending SDK version 8 keys", ex);
-        }
-      }
-      sendPart(os, boundary, "Android_Version",  Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
-
-      sendFile(os, boundary, kMiniDumpPathKey, minidumpFile);
-      os.write(("\r\n--" + boundary + "--\r\n").getBytes());
-      os.flush();
-      os.close();
-      BufferedReader br = new BufferedReader(
-        new InputStreamReader(conn.getInputStream()));
-      HashMap<String, String>  responseMap = new HashMap<String, String>();
-      readStringsFromReader(br, responseMap);
-
-      if (conn.getResponseCode() == conn.HTTP_OK) {
-        File submittedDir = new File(
-          "/data/data/@ANDROID_PACKAGE_NAME@/files/mozilla/Crash Reports/submitted");
-        submittedDir.mkdirs();
-        minidumpFile.delete();
-        extrasFile.delete();
-        String crashid = responseMap.get("CrashID");
-        File file = new File(submittedDir, crashid + ".txt");
-        FileOutputStream fos = new FileOutputStream(file);
-        fos.write("Crash ID: ".getBytes());
-        fos.write(crashid.getBytes());
-        fos.close();
-      }
-    } catch (IOException e) {
-      Log.e("GeckoCrashReporter", "exception during send: ", e);
+    private void sendFile(OutputStream os, String boundary, String name, File file) throws IOException {
+        os.write(("--" + boundary + "\r\n" +
+                  "Content-Disposition: form-data; name=\"" + name + "\"; " +
+                  "filename=\"" + file.getName() + "\"\r\n" +
+                  "Content-Type: application/octet-stream\r\n" +
+                  "\r\n"
+                 ).getBytes());
+        FileChannel fc = new FileInputStream(file).getChannel();
+        fc.transferTo(0, fc.size(), Channels.newChannel(os));
+        fc.close();
     }
 
-    doFinish();
-  }
+    private void sendReport(File minidumpFile, Map<String, String> extras, File extrasFile) {
+        Log.i(LOGTAG, "sendReport: " + minidumpFile.getPath());
+        final CheckBox includeURLCheckbox = (CheckBox) findViewById(R.id.include_url);
+
+        String spec = extras.get(SERVER_URL_KEY);
+        if (spec == null)
+            doFinish();
+
+        Log.i(LOGTAG, "server url: " + spec);
+        try {
+            URL url = new URL(spec);
+            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
+            conn.setRequestMethod("POST");
+            String boundary = generateBoundary();
+            conn.setDoOutput(true);
+            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
+
+            OutputStream os = conn.getOutputStream();
+            for (String key : extras.keySet()) {
+                if (key.equals(PAGE_URL_KEY)) {
+                    if (includeURLCheckbox.isChecked())
+                        sendPart(os, boundary, key, extras.get(key));
+                } else if (!key.equals(SERVER_URL_KEY) && !key.equals(NOTES_KEY)) {
+                    sendPart(os, boundary, key, extras.get(key));
+                }
+            }
+
+            // Add some extra information to notes so its displayed by
+            // crash-stats.mozilla.org. Remove this when bug 607942 is fixed.
+            StringBuffer sb = new StringBuffer();
+            sb.append(extras.containsKey(NOTES_KEY) ? extras.get(NOTES_KEY) + "\n" : "");
+            if (@MOZ_MIN_CPU_VERSION@ < 7)
+                sb.append("nothumb Build\n");
+            sb.append(Build.MANUFACTURER).append(' ')
+              .append(Build.MODEL).append('\n')
+              .append(Build.FINGERPRINT);
+            sendPart(os, boundary, NOTES_KEY, sb.toString());
 
-  void doRestart()
-  {
-    try {
-      String action = "android.intent.action.MAIN";
-      Intent intent = new Intent(action);
-      intent.setClassName("@ANDROID_PACKAGE_NAME@",
-                          "@ANDROID_PACKAGE_NAME@.App");
-      Log.i("GeckoCrashReporter", intent.toString());
-      startActivity(intent);
-    } catch (Exception e) {
-      Log.e("GeckoCrashReporter", "error while trying to restart", e);
+            sendPart(os, boundary, "Min_ARM_Version", "@MOZ_MIN_CPU_VERSION@");
+            sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER);
+            sendPart(os, boundary, "Android_Model", Build.MODEL);
+            sendPart(os, boundary, "Android_Board", Build.BOARD);
+            sendPart(os, boundary, "Android_Brand", Build.BRAND);
+            sendPart(os, boundary, "Android_Device", Build.DEVICE);
+            sendPart(os, boundary, "Android_Display", Build.DISPLAY);
+            sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT);
+            sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI);
+            if (Build.VERSION.SDK_INT >= 8) {
+                try {
+                    sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2);
+                    sendPart(os, boundary, "Android_Hardware", Build.HARDWARE);
+                } catch (Exception ex) {
+                    Log.e(LOGTAG, "Exception while sending SDK version 8 keys", ex);
+                }
+            }
+            sendPart(os, boundary, "Android_Version",  Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
+
+            sendFile(os, boundary, MINI_DUMP_PATH_KEY, minidumpFile);
+            os.write(("\r\n--" + boundary + "--\r\n").getBytes());
+            os.flush();
+            os.close();
+            BufferedReader br = new BufferedReader(
+                new InputStreamReader(conn.getInputStream()));
+            HashMap<String, String>  responseMap = new HashMap<String, String>();
+            readStringsFromReader(br, responseMap);
+
+            if (conn.getResponseCode() == conn.HTTP_OK) {
+                File submittedDir = new File(SUBMITTED_DIR);
+                submittedDir.mkdirs();
+                minidumpFile.delete();
+                extrasFile.delete();
+                String crashid = responseMap.get("CrashID");
+                File file = new File(submittedDir, crashid + ".txt");
+                FileOutputStream fos = new FileOutputStream(file);
+                fos.write("Crash ID: ".getBytes());
+                fos.write(crashid.getBytes());
+                fos.close();
+            }
+        } catch (IOException e) {
+            Log.e(LOGTAG, "exception during send: ", e);
+        }
+
+        doFinish();
     }
-  }
 
-  public String unescape(String string)
-  {
-    return string.replaceAll("\\\\", "\\").replaceAll("\\n", "\n")
-      .replaceAll("\\t", "\t");
-  }
+    private void doRestart() {
+        try {
+            String action = "android.intent.action.MAIN";
+            Intent intent = new Intent(action);
+            intent.setClassName("@ANDROID_PACKAGE_NAME@",
+                                "@ANDROID_PACKAGE_NAME@.App");
+            Log.i(LOGTAG, intent.toString());
+            startActivity(intent);
+        } catch (Exception e) {
+            Log.e(LOGTAG, "error while trying to restart", e);
+        }
+    }
+
+    private String unescape(String string) {
+        return string.replaceAll("\\\\", "\\").replaceAll("\\n", "\n").replaceAll("\\t", "\t");
+    }
 }
-
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/DoorHanger.java
@@ -0,0 +1,162 @@
+/* -*- 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):
+ *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
+ *   Sriram Ramasubramanian <sriram@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.util.Date;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.TextView;
+
+import org.json.JSONObject;
+import org.json.JSONException;
+
+public class DoorHanger extends LinearLayout implements Button.OnClickListener {
+    private Context mContext;
+    private LinearLayout mChoicesLayout;
+    private TextView mTextView;
+    private Button mButton;
+    private LayoutParams mLayoutParams;
+    public Tab mTab;
+    // value used to identify the notification
+    private String mValue;
+
+    private int mPersistence = 0;
+    private long mTimeout = 0;
+
+    public DoorHanger(Context aContext, String aValue) {
+        super(aContext);
+
+        mContext = aContext;
+        mValue = aValue;
+
+        setOrientation(VERTICAL);
+        setBackgroundResource(R.drawable.doorhanger_shadow_bg);
+
+        // Load layout into the custom view
+        LayoutInflater inflater =
+                (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(R.layout.doorhanger, this);
+        hide();
+
+        mTextView = (TextView) findViewById(R.id.doorhanger_title);
+        mChoicesLayout = (LinearLayout) findViewById(R.id.doorhanger_choices);
+
+        mLayoutParams = new LayoutParams(LayoutParams.FILL_PARENT,
+                                         LayoutParams.FILL_PARENT,
+                                         1.0f);
+    }
+
+    public void addButton(String aText, int aCallback) {
+        Button mButton = new Button(mContext);
+        mButton.setText(aText);
+        mButton.setTag(Integer.toString(aCallback));
+        mButton.setOnClickListener(this);
+        mChoicesLayout.addView(mButton, mLayoutParams);
+    }
+
+    public void onClick(View v) {
+        GeckoEvent e = new GeckoEvent("Doorhanger:Reply", v.getTag().toString());
+        GeckoAppShell.sendEventToGecko(e);
+        mTab.removeDoorHanger(mValue);
+
+        // This will hide the doorhanger (and hide the popup if there are no
+        // more doorhangers to show)
+        GeckoApp.mDoorHangerPopup.updatePopup();
+    }
+
+    public void show() {
+        setVisibility(View.VISIBLE);
+    }
+
+    public void hide() {
+        setVisibility(View.GONE);
+    }
+
+    public boolean isVisible() {
+        return getVisibility() == View.VISIBLE;
+    }
+
+    public String getValue() {
+        return mValue;
+    }
+
+    public void setText(String aText) {
+        mTextView.setText(aText);
+    }
+
+    public Tab getTab() {
+        return mTab;
+    }
+
+    public void setTab(Tab tab) {
+        mTab = tab;
+    }
+
+    public void setOptions(JSONObject options) {
+        try {
+            mPersistence = options.getInt("persistence");
+        } catch (JSONException e) { }
+
+        try {
+            mTimeout = options.getLong("timeout");
+        } catch (JSONException e) { }
+    }
+
+    // This method checks with persistence and timeout options to see if
+    // it's okay to remove a doorhanger.
+    public boolean shouldRemove() {
+        // If persistence is set to -1, the doorhanger will never be
+        // automatically removed.
+        if (mPersistence != 0) {
+            mPersistence--;
+            return false;
+        }
+
+        if (new Date().getTime() <= mTimeout) {
+            return false;
+        }
+
+        return true;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/DoorHangerPopup.java
@@ -0,0 +1,168 @@
+/* -*- 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):
+ *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
+ *   Sriram Ramasubramanian <sriram@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.util.HashMap;
+import java.util.Iterator;
+
+import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.PopupWindow;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.RelativeLayout;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.json.JSONException;
+
+public class DoorHangerPopup extends PopupWindow {
+    private static final String LOGTAG = "GeckoDoorHangerPopup";
+
+    private Context mContext;
+    private LinearLayout mContent;
+
+    public DoorHangerPopup(Context aContext) {
+        super(aContext);
+        mContext = aContext;
+
+        setBackgroundDrawable(new BitmapDrawable());
+        setOutsideTouchable(true);
+        setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.doorhangerpopup, null);
+        mContent = (LinearLayout) layout.findViewById(R.id.doorhanger_container);
+        
+        setContentView(layout);
+    }
+
+    public void addDoorHanger(String message, String value, JSONArray buttons,
+                              Tab tab, JSONObject options) {
+        Log.i(LOGTAG, "Adding a DoorHanger to Tab: " + tab.getId());
+
+        // Replace the doorhanger if it already exists
+        DoorHanger dh = tab.getDoorHanger(value);
+        if (dh != null) {
+            tab.removeDoorHanger(value);
+        }
+        dh = new DoorHanger(mContent.getContext(), value);
+ 
+        // Set the doorhanger text and buttons
+        dh.setText(message);
+        for (int i = 0; i < buttons.length(); i++) {
+            try {
+                JSONObject buttonObject = buttons.getJSONObject(i);
+                String label = buttonObject.getString("label");
+                int callBackId = buttonObject.getInt("callback");
+                dh.addButton(label, callBackId);
+            } catch (JSONException e) {
+                Log.i(LOGTAG, "JSON throws " + e);
+            }
+         }
+        dh.setOptions(options);
+
+        dh.setTab(tab);
+        tab.addDoorHanger(value, dh);
+        mContent.addView(dh);
+
+        updatePopup();
+    }
+
+    // Updates popup contents to show doorhangers for the selected tab
+    public void updatePopup() {
+        Tab tab = Tabs.getInstance().getSelectedTab();
+        if (tab == null) {
+            hidePopup();
+            return;
+        }
+        
+        Log.i(LOGTAG, "Showing all doorhangers for tab: " + tab.getId());
+ 
+        HashMap<String, DoorHanger> doorHangers = tab.getDoorHangers();
+        // Hide the popup if there aren't any doorhangers to show
+        if (doorHangers == null || doorHangers.size() == 0) {
+            hidePopup();
+            return;
+        }
+
+        // Hide old doorhangers
+        for (int i = 0; i < mContent.getChildCount(); i++) {
+            DoorHanger dh = (DoorHanger) mContent.getChildAt(i);
+            dh.hide();
+        }
+
+        // Show the doorhangers for the tab
+        for (DoorHanger dh : doorHangers.values()) {
+            dh.show();
+        }
+
+        showPopup();
+    }
+
+    public void hidePopup() {
+        if (isShowing()) {
+            Log.i(LOGTAG, "Hiding the DoorHangerPopup");
+            dismiss();
+        }
+    }
+
+    public void showPopup() {
+        Log.i(LOGTAG, "Showing the DoorHangerPopup");
+        fixBackgroundForFirst();
+
+        if (isShowing())
+            update();
+        else
+            showAsDropDown(GeckoApp.mBrowserToolbar.mFavicon);
+    }
+
+    private void fixBackgroundForFirst() {
+        for (int i=0; i < mContent.getChildCount(); i++) {
+            DoorHanger dh = (DoorHanger) mContent.getChildAt(i);
+            if (dh.isVisible()) {
+                dh.setBackgroundResource(R.drawable.doorhanger_bg);
+                break;
+            }
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/Favicons.java
@@ -0,0 +1,424 @@
+/* -*- 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):
+ *   Lucas Rocha <lucasr@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 android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.provider.Browser;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class Favicons {
+    private static final String LOGTAG = "GeckoFavicons";
+
+    public static final long NOT_LOADING = 0;
+
+    private Context mContext;
+    private DatabaseHelper mDbHelper;
+
+    private Map<Long,LoadFaviconTask> mLoadTasks;
+    private long mNextFaviconLoadId;
+
+    public interface OnFaviconLoadedListener {
+        public void onFaviconLoaded(String url, Drawable favicon);
+    }
+
+    private class DatabaseHelper extends SQLiteOpenHelper {
+        private static final String DATABASE_NAME = "favicon_urls.db";
+        private static final String TABLE_NAME = "favicon_urls";
+        private static final int DATABASE_VERSION = 1;
+
+        private static final String COLUMN_ID = "_id";
+        private static final String COLUMN_FAVICON_URL = "favicon_url";
+        private static final String COLUMN_PAGE_URL = "page_url";
+
+        DatabaseHelper(Context context) {
+            super(context, DATABASE_NAME, null, DATABASE_VERSION);
+            Log.d(LOGTAG, "Creating DatabaseHelper");
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            Log.d(LOGTAG, "Creating database for favicon URLs");
+
+            db.execSQL("CREATE TABLE " + TABLE_NAME + " (" +
+                       COLUMN_ID + " INTEGER PRIMARY KEY," +
+                       COLUMN_FAVICON_URL + " TEXT NOT NULL," +
+                       COLUMN_PAGE_URL + " TEXT UNIQUE NOT NULL" +
+                       ");");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.w(LOGTAG, "Upgrading favicon URLs database from version " +
+                  oldVersion + " to " + newVersion + ", which will destroy all old data");
+
+            // Drop table completely
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
+
+            // Recreate database
+            onCreate(db);
+        }
+
+        public String getFaviconUrlForPageUrl(String pageUrl) {
+            Log.d(LOGTAG, "Calling getFaviconUrlForPageUrl() for " + pageUrl);
+
+            SQLiteDatabase db = mDbHelper.getReadableDatabase();
+
+            SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+            qb.setTables(TABLE_NAME);
+
+            Cursor c = qb.query(
+                db,
+                new String[] { COLUMN_FAVICON_URL },
+                COLUMN_PAGE_URL + " = ?",
+                new String[] { pageUrl },
+                null, null, null
+            );
+
+            if (!c.moveToFirst()) {
+                c.close();
+                return null;
+            }
+
+            String url = c.getString(c.getColumnIndexOrThrow(COLUMN_FAVICON_URL));
+            c.close();
+            return url;
+        }
+
+        public void setFaviconUrlForPageUrl(String pageUrl, String faviconUrl) {
+            Log.d(LOGTAG, "Calling setFaviconUrlForPageUrl() for " + pageUrl);
+
+            SQLiteDatabase db = mDbHelper.getWritableDatabase();
+
+            ContentValues values = new ContentValues();
+            values.put(COLUMN_FAVICON_URL, faviconUrl);
+            values.put(COLUMN_PAGE_URL, pageUrl);
+
+            db.replace(TABLE_NAME, null, values);
+        }
+    }
+
+    public Favicons(Context context) {
+        Log.d(LOGTAG, "Creating Favicons instance");
+
+        mContext = context;
+        mDbHelper = new DatabaseHelper(context);
+
+        mLoadTasks = new HashMap<Long,LoadFaviconTask>();
+        mNextFaviconLoadId = 0;
+    }
+
+    public long loadFavicon(String pageUrl, String faviconUrl,
+            OnFaviconLoadedListener listener) {
+
+        // Handle the case where page url is empty
+        if (pageUrl == null || pageUrl.length() == 0) {
+            if (listener != null)
+                listener.onFaviconLoaded(null, null);
+        }
+
+        LoadFaviconTask task = new LoadFaviconTask(pageUrl, faviconUrl, listener);
+
+        long taskId = task.getId();
+        mLoadTasks.put(taskId, task);
+
+        task.execute();
+
+        Log.d(LOGTAG, "Calling loadFavicon() with URL = " + pageUrl +
+                        " and favicon URL = " + faviconUrl +
+                        " (" + taskId + ")");
+
+        return taskId;
+    }
+
+    public boolean cancelFaviconLoad(long taskId) {
+        Log.d(LOGTAG, "Requesting cancelation of favicon load (" + taskId + ")");
+
+        if (!mLoadTasks.containsKey(taskId))
+            return false;
+
+        Log.d(LOGTAG, "Cancelling favicon load (" + taskId + ")");
+
+        LoadFaviconTask task = mLoadTasks.get(taskId);
+        return task.cancel(false);
+    }
+
+    public void close() {
+        Log.d(LOGTAG, "Closing Favicons database");
+        mDbHelper.close();
+
+        // Cancel any pending tasks
+        Set<Long> taskIds = mLoadTasks.keySet();
+        Iterator iter = taskIds.iterator();
+        while (iter.hasNext()) {
+            long taskId = (Long) iter.next();
+            cancelFaviconLoad(taskId);
+        }
+    }
+
+    private class LoadFaviconTask extends AsyncTask<Void, Void, BitmapDrawable> {
+        private long mId;
+        private String mPageUrl;
+        private String mFaviconUrl;
+        private OnFaviconLoadedListener mListener;
+
+        public LoadFaviconTask(String pageUrl, String faviconUrl, OnFaviconLoadedListener listener) {
+            mId = ++mNextFaviconLoadId;
+            mPageUrl = pageUrl;
+            mFaviconUrl = faviconUrl;
+            mListener = listener;
+
+            Log.d(LOGTAG, "Creating LoadFaviconTask with URL = " + pageUrl +
+                          " and favicon URL = " + faviconUrl);
+        }
+
+        // Runs in background thread
+        private BitmapDrawable loadFaviconFromDb() {
+            Log.d(LOGTAG, "Loading favicon from DB for URL = " + mPageUrl);
+
+            ContentResolver resolver = mContext.getContentResolver();
+
+            Cursor c = resolver.query(Browser.BOOKMARKS_URI,
+                                      new String[] { Browser.BookmarkColumns.FAVICON },
+                                      Browser.BookmarkColumns.URL + " = ?",
+                                      new String[] { mPageUrl },
+                                      null);
+
+            if (!c.moveToFirst()) {
+                c.close();
+                return null;
+            }
+
+            int faviconIndex = c.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON);
+            
+            byte[] b = c.getBlob(faviconIndex);
+            c.close();
+            if (b == null)
+                return null;
+
+            Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
+
+            Log.d(LOGTAG, "Loaded favicon from DB successfully for URL = " + mPageUrl);
+
+            return new BitmapDrawable(bitmap);
+        }
+
+        // Runs in background thread
+        private void saveFaviconToDb(BitmapDrawable favicon) {
+            Bitmap bitmap = favicon.getBitmap();
+
+            ByteArrayOutputStream stream = new ByteArrayOutputStream();
+            bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
+
+            ContentValues values = new ContentValues();
+            values.put(Browser.BookmarkColumns.FAVICON, stream.toByteArray());
+            values.put(Browser.BookmarkColumns.URL, mPageUrl);
+
+            ContentResolver resolver = mContext.getContentResolver();
+
+            Log.d(LOGTAG, "Saving favicon on browser database for URL = " + mPageUrl);
+            resolver.update(Browser.BOOKMARKS_URI,
+                            values,
+                            Browser.BookmarkColumns.URL + " = ?",
+                            new String[] { mPageUrl });
+
+
+            Log.d(LOGTAG, "Saving favicon URL for URL = " + mPageUrl);
+            mDbHelper.setFaviconUrlForPageUrl(mPageUrl, mFaviconUrl);
+        }
+
+        // Runs in background thread
+        private BitmapDrawable downloadFavicon(URL faviconUrl) {
+            Log.d(LOGTAG, "Downloading favicon for URL = " + mPageUrl +
+                          " with favicon URL = " + mFaviconUrl);
+
+            // due to android bug 6066, we must download the entire image before using it
+            // http://code.google.com/p/android/issues/detail?id=6066
+            HttpURLConnection urlConnection = null;
+            BufferedInputStream contentStream = null;
+            ByteArrayInputStream byteStream = null;
+            BitmapDrawable image = null;
+
+            try {
+                urlConnection = (HttpURLConnection) faviconUrl.openConnection();
+                int length = urlConnection.getContentLength();
+                contentStream = new BufferedInputStream(urlConnection.getInputStream(), length);
+                byte[] bytes = new byte[length];
+                int pos = 0;
+                int offset = 0;
+                while ((pos = contentStream.read(bytes, offset, length - offset)) > 0)
+                    offset += pos;
+                if (length == offset) {
+                    byteStream = new ByteArrayInputStream(bytes);
+                    image = (BitmapDrawable) Drawable.createFromStream(byteStream, "src");
+                }
+            } catch (Exception e) {
+                Log.d(LOGTAG, "Error downloading favicon: " + e);
+            } finally {
+                if (urlConnection != null)
+                    urlConnection.disconnect();
+                try {
+                    if (contentStream != null)
+                        contentStream.close();
+                    if (byteStream != null)
+                        byteStream.close();
+                } catch (IOException e) {
+                    Log.d(LOGTAG, "error closing favicon stream");
+                }
+            }
+
+            if (image != null) {
+                Log.d(LOGTAG, "Downloaded favicon successfully for URL = " + mPageUrl);
+                saveFaviconToDb(image);
+            }
+
+            return image;
+        }
+
+        @Override
+        protected BitmapDrawable doInBackground(Void... unused) {
+            BitmapDrawable image = null;
+            URL pageUrl = null;
+
+            if (isCancelled())
+                return null;
+
+            // Handle the case of malformed URL
+            try {
+                pageUrl = new URL(mPageUrl);
+            } catch (MalformedURLException e) {
+                Log.d(LOGTAG, "The provided URL is not valid: " + e);
+                return null;
+            }
+
+            URL faviconUrl = null;
+
+            // Handle the case of malformed favicon URL
+            try {
+                // If favicon is empty, fallback to default favicon URI
+                if (mFaviconUrl == null || mFaviconUrl.length() == 0) {
+                    faviconUrl = new URL(pageUrl.getProtocol(), pageUrl.getAuthority(), "/favicon.ico");
+                    mFaviconUrl = faviconUrl.toString();
+                } else {
+                    faviconUrl = new URL(mFaviconUrl);
+                }
+            } catch (MalformedURLException e) {
+                Log.d(LOGTAG, "The provided favicon URL is not valid: " + e);
+                return null;
+            }
+
+            Log.d(LOGTAG, "Favicon URL is now: " + mFaviconUrl);
+
+            if (isCancelled())
+                return null;
+
+            String storedFaviconUrl = mDbHelper.getFaviconUrlForPageUrl(mPageUrl);
+            if (storedFaviconUrl != null && storedFaviconUrl.equals(mFaviconUrl)) {
+                image = loadFaviconFromDb();
+
+                if (isCancelled())
+                    return null;
+
+                // If favicon URL is defined but the favicon image is not
+                // stored in the database for some reason, we force download.
+                if (image == null) {
+                    image = downloadFavicon(faviconUrl);
+                }
+            } else {
+                image = downloadFavicon(faviconUrl);
+            }
+
+            return image;
+        }
+
+        @Override
+        protected void onPostExecute(final BitmapDrawable image) {
+            Log.d(LOGTAG, "LoadFaviconTask finished for URL = " + mPageUrl +
+                          " (" + mId + ")");
+
+            mLoadTasks.remove(mId);
+
+            if (mListener != null) {
+                // We want to always run the listener on UI thread
+                GeckoApp.mAppContext.runOnUiThread(new Runnable() {
+                    public void run() {
+                        mListener.onFaviconLoaded(mPageUrl, image);
+                    }
+                });
+            }
+        }
+
+        @Override
+        protected void onCancelled() {
+            Log.d(LOGTAG, "LoadFaviconTask cancelled for URL = " + mPageUrl +
+                          " (" + mId + ")");
+
+            mLoadTasks.remove(mId);
+
+            // Note that we don't call the listener callback if the
+            // favicon load is cancelled.
+        }
+
+        public long getId() {
+            return mId;
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/FloatUtils.java
@@ -0,0 +1,46 @@
+/* -*- 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):
+ *   Chris Lord <chrislord.net@gmail.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.lang.Math;
+
+public final class FloatUtils {
+    public static boolean fuzzyEquals(float a, float b) {
+        return (Math.abs(a - b) < 1e-6);
+    }
+}
rename from embedding/android/GeckoApp.java
rename to mobile/android/base/GeckoApp.java
--- a/embedding/android/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1,9 +1,9 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 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/
  *
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009-2010
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Vladimir Vukicevic <vladimir@pobox.com>
  *   Matt Brubeck <mbrubeck@mozilla.com>
  *   Vivien Nicolas <vnicolas@mozilla.com>
+ *   Sriram Ramasubramanian <sriram@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
@@ -34,74 +35,145 @@
  * 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 org.mozilla.gecko.gfx.FloatSize;
+import org.mozilla.gecko.gfx.GeckoSoftwareLayerClient;
+import org.mozilla.gecko.gfx.IntSize;
+import org.mozilla.gecko.gfx.LayerController;
+import org.mozilla.gecko.gfx.LayerView;
+import org.mozilla.gecko.gfx.PlaceholderLayerClient;
+import org.mozilla.gecko.gfx.RectUtils;
+import org.mozilla.gecko.gfx.ViewportMetrics;
+import org.mozilla.gecko.Tab.HistoryEntry;
+
 import java.io.*;
 import java.util.*;
 import java.util.zip.*;
+import java.net.URL;
 import java.nio.*;
 import java.nio.channels.FileChannel;
 import java.util.concurrent.*;
 import java.lang.reflect.*;
+import java.net.*;
+
+import org.json.*;
 
 import android.os.*;
 import android.app.*;
 import android.text.*;
 import android.view.*;
 import android.view.inputmethod.*;
+import android.view.ViewGroup.LayoutParams;
 import android.content.*;
 import android.content.res.*;
 import android.graphics.*;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.BitmapDrawable;
 import android.widget.*;
 import android.hardware.*;
+import android.location.*;
 
 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.*;
 import dalvik.system.*;
 
 abstract public class GeckoApp
-    extends Activity
+    extends Activity implements GeckoEventListener, SensorEventListener, LocationListener
 {
-    private static final String LOG_FILE_NAME     = "GeckoApp";
+    private static final String LOGTAG = "GeckoApp";
 
-    public static final String ACTION_ALERT_CLICK = "org.mozilla.gecko.ACTION_ALERT_CLICK";
-    public static final String ACTION_ALERT_CLEAR = "org.mozilla.gecko.ACTION_ALERT_CLEAR";
-    public static final String ACTION_WEBAPP      = "org.mozilla.gecko.WEBAPP";
-    public static final String ACTION_DEBUG       = "org.mozilla.gecko.DEBUG";
-    public static final String ACTION_BOOKMARK    = "org.mozilla.gecko.BOOKMARK";
+    public static final String ACTION_ALERT_CLICK   = "org.mozilla.gecko.ACTION_ALERT_CLICK";
+    public static final String ACTION_ALERT_CLEAR   = "org.mozilla.gecko.ACTION_ALERT_CLEAR";
+    public static final String ACTION_WEBAPP        = "org.mozilla.gecko.WEBAPP";
+    public static final String ACTION_DEBUG         = "org.mozilla.gecko.DEBUG";
+    public static final String ACTION_BOOKMARK      = "org.mozilla.gecko.BOOKMARK";
+    public static final String SAVED_STATE_URI      = "uri";
+    public static final String SAVED_STATE_TITLE    = "title";
+    public static final String SAVED_STATE_VIEWPORT = "viewport";
+    public static final String SAVED_STATE_SCREEN   = "screen";
 
-    public static AbsoluteLayout mainLayout;
-    public static GeckoSurfaceView surfaceView;
+    private LinearLayout mMainLayout;
+    private AbsoluteLayout mGeckoLayout;
     public static SurfaceView cameraView;
     public static GeckoApp mAppContext;
-    public static boolean mFullscreen = false;
+    public static boolean mFullScreen = false;
     public static File sGREDir = null;
-    static Thread mLibLoadThread = null;
+    public static Menu sMenu;
     public Handler mMainHandler;
+    private File mProfileDir;
+    private static boolean sIsGeckoReady = false;
+
     private IntentFilter mConnectivityFilter;
+    private IntentFilter mBatteryFilter;
+    private IntentFilter mSmsFilter;
+
     private BroadcastReceiver mConnectivityReceiver;
+    private BroadcastReceiver mSmsReceiver;
     private BroadcastReceiver mBatteryReceiver;
-    private BroadcastReceiver mSmsReceiver;
+
+    public static BrowserToolbar mBrowserToolbar;
+    public static DoorHangerPopup mDoorHangerPopup;
+    public Favicons mFavicons;
+
+    private Geocoder mGeocoder;
+    private Address  mLastGeoAddress;
+    private static LayerController mLayerController;
+    private static PlaceholderLayerClient mPlaceholderLayerClient;
+    private static GeckoSoftwareLayerClient mSoftwareLayerClient;
+    AboutHomeContent mAboutHomeContent;
+    boolean mUserDefinedProfile = false;
+
+    public String mLastUri;
+    public String mLastTitle;
+    public String mLastViewport;
+    public byte[] mLastScreen;
+    public int mOwnActivityDepth = 0;
+
+    private Vector<View> mPluginViews = new Vector<View>();
 
-    enum LaunchState {PreLaunch, Launching, WaitForDebugger,
-                      Launched, GeckoRunning, GeckoExiting};
-    private static LaunchState sLaunchState = LaunchState.PreLaunch;
+    public interface OnTabsChangedListener {
+        public void onTabsChanged(Tab tab);
+    }
+    
+    private static ArrayList<OnTabsChangedListener> mTabsChangedListeners;
+
+    static class ExtraMenuItem implements MenuItem.OnMenuItemClickListener {
+        String label;
+        String icon;
+        int id;
+        public boolean onMenuItemClick(MenuItem item) {
+            Log.i(LOGTAG, "menu item clicked");
+            GeckoAppShell.sendEventToGecko(new GeckoEvent("Menu:Clicked", Integer.toString(id)));
+            return true;
+        }
+    }
+
+    static Vector<ExtraMenuItem> sExtraMenuItems = new Vector<ExtraMenuItem>();
+
+    public enum LaunchState {Launching, WaitForDebugger,
+                             Launched, GeckoRunning, GeckoExiting};
+    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;
+    private static final int CAMERA_CAPTURE_REQUEST = 3;
 
-    static boolean checkLaunchState(LaunchState checkState) {
+    public static boolean checkLaunchState(LaunchState checkState) {
         synchronized(sLaunchState) {
             return sLaunchState == checkState;
         }
     }
 
     static void setLaunchState(LaunchState setState) {
         synchronized(sLaunchState) {
             sLaunchState = setState;
@@ -138,26 +210,26 @@ abstract public class GeckoApp
     public static final String PLUGIN_ACTION = "android.webkit.PLUGIN";
 
     /**
      * A plugin that wish to be loaded in the WebView must provide this permission
      * in their AndroidManifest.xml.
      */
     public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
 
-    private static final String LOGTAG = "PluginManager";
-
     private static final String PLUGIN_SYSTEM_LIB = "/system/lib/plugins/";
 
     private static final String PLUGIN_TYPE = "type";
     private static final String TYPE_NATIVE = "native";
     public ArrayList<PackageInfo> mPackageInfoCache = new ArrayList<PackageInfo>();
 
     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),
                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
 
         synchronized(mPackageInfoCache) {
 
             // clear the list of existing packageInfo objects
@@ -168,16 +240,24 @@ abstract public class GeckoApp
 
                 // retrieve the plugin's service information
                 ServiceInfo serviceInfo = info.serviceInfo;
                 if (serviceInfo == null) {
                     Log.w(LOGTAG, "Ignore bad plugin");
                     continue;
                 }
 
+                // Blacklist HTC's flash lite.
+                // See bug #704516 - We're not quite sure what Flash Lite does,
+                // but loading it causes Flash to give errors and fail to draw.
+                if (serviceInfo.packageName.equals("com.htc.flashliteplugin")) {
+                    Log.w(LOGTAG, "Skipping HTC's flash lite plugin");
+                    continue;
+                }
+
                 Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName);
 
 
                 // retrieve information from the plugin's manifest
                 PackageInfo pkgInfo;
                 try {
                     pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
                                     PackageManager.GET_PERMISSIONS
@@ -263,437 +343,1279 @@ abstract public class GeckoApp
                 }
 
                 // if all checks have passed then make the plugin available
                 mPackageInfoCache.add(pkgInfo);
                 directories.add(directory);
             }
         }
 
-        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;
+    }
+
+    String getPluginPackage(String pluginLib) {
+
+        if (pluginLib == null || pluginLib.length() == 0) {
+            return null;
+        }
+
+        synchronized(mPackageInfoCache) {
+            for (PackageInfo pkgInfo : mPackageInfoCache) {
+                if (pluginLib.contains(pkgInfo.packageName)) {
+                    return pkgInfo.packageName;
+                }
+            }
+        }
+
+        return null;
     }
 
     Class<?> getPluginClass(String packageName, String className)
             throws NameNotFoundException, ClassNotFoundException {
         Context pluginContext = this.mAppContext.createPackageContext(packageName,
                 Context.CONTEXT_INCLUDE_CODE |
                 Context.CONTEXT_IGNORE_SECURITY);
         ClassLoader pluginCL = pluginContext.getClassLoader();
         return pluginCL.loadClass(className);
     }
 
     // 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;
 
+                String args = intent.getStringExtra("args");
+                if (args != null && args.contains("-profile")) {
+                    // XXX: TO-DO set mProfileDir to the path passed in
+                    mUserDefinedProfile = true;
+                }
+
         if (intent == null)
             intent = getIntent();
-        final Intent i = intent;
-        new Thread() {
+
+        prefetchDNS(intent.getData());
+        new GeckoThread(intent, mLastUri, mLastTitle).start();
+
+        return true;
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu)
+    {
+        sMenu = menu;
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.layout.gecko_menu, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu aMenu)
+    {
+        Iterator<ExtraMenuItem> i = sExtraMenuItems.iterator();
+        while (i.hasNext()) {
+            final ExtraMenuItem item = i.next();
+            if (aMenu.findItem(item.id) == null) {
+                final MenuItem mi = aMenu.add(aMenu.NONE, item.id, aMenu.NONE, item.label);
+                if (item.icon != null) {
+                    if (item.icon.startsWith("data")) {
+                        byte[] raw = Base64.decode(item.icon.substring(22), Base64.DEFAULT);
+                        Bitmap bitmap = BitmapFactory.decodeByteArray(raw, 0, raw.length);
+                        BitmapDrawable drawable = new BitmapDrawable(bitmap);
+                        mi.setIcon(drawable);
+                    }
+                    else if (item.icon.startsWith("jar:") || item.icon.startsWith("file://")) {
+                        GeckoAppShell.getHandler().post(new Runnable() {
+                            public void run() {
+                                try {
+                                    URL url = new URL(item.icon);
+                                    InputStream is = (InputStream) url.getContent();
+                                    Drawable drawable = Drawable.createFromStream(is, "src");
+                                    mi.setIcon(drawable);
+                                } catch(Exception e) {
+                                    Log.e(LOGTAG, "onPrepareOptionsMenu: Unable to set icon", e);
+                                }
+                            }
+                        });
+                    }
+                }
+                mi.setOnMenuItemClickListener(item);
+            }
+        }
+
+        if (!sIsGeckoReady)
+            aMenu.findItem(R.id.preferences).setEnabled(false);
+
+        Tab tab = Tabs.getInstance().getSelectedTab();
+        MenuItem bookmark = aMenu.findItem(R.id.bookmark);
+        MenuItem forward = aMenu.findItem(R.id.forward);
+        MenuItem share = aMenu.findItem(R.id.share);
+        MenuItem agentMode = aMenu.findItem(R.id.agent_mode);
+
+        if (tab == null) {
+            bookmark.setEnabled(false);
+            forward.setEnabled(false);
+            share.setEnabled(false);
+            return true;
+        }
+        
+        bookmark.setEnabled(true);
+        bookmark.setCheckable(true);
+        
+        if (tab.isBookmark()) {
+            bookmark.setChecked(true);
+            bookmark.setIcon(R.drawable.ic_menu_bookmark_remove);
+            bookmark.setTitle(R.string.bookmark_remove);
+        } else {
+            bookmark.setChecked(false);
+            bookmark.setIcon(R.drawable.ic_menu_bookmark_add);
+            bookmark.setTitle(R.string.bookmark_add);
+        }
+
+        forward.setEnabled(tab.canDoForward());
+
+        // Don't share about:, chrome: and file: URIs
+        String scheme = Uri.parse(tab.getURL()).getScheme();
+        share.setEnabled(!scheme.equals("about") && !scheme.equals("chrome") && !scheme.equals("file"));
+
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        Tab tab = null;
+        Intent intent = null;
+        switch (item.getItemId()) {
+            case R.id.quit:
+                synchronized(sLaunchState) {
+                    if (sLaunchState == LaunchState.GeckoRunning)
+                        GeckoAppShell.notifyGeckoOfEvent(
+                            new GeckoEvent("Browser:Quit", null));
+                    else
+                        System.exit(0);
+                    sLaunchState = LaunchState.GeckoExiting;
+                }
+                return true;
+            case R.id.bookmark:
+                tab = Tabs.getInstance().getSelectedTab();
+                if (tab != null) {
+                    if (item.isChecked()) {
+                        tab.removeBookmark();
+                        Toast.makeText(this, R.string.bookmark_removed, Toast.LENGTH_SHORT).show();
+                        item.setIcon(R.drawable.ic_menu_bookmark_add);
+                        item.setTitle(R.string.bookmark_add);
+                    } else {
+                        tab.addBookmark();
+                        Toast.makeText(this, R.string.bookmark_added, Toast.LENGTH_SHORT).show();
+                        item.setIcon(R.drawable.ic_menu_bookmark_remove);
+                        item.setTitle(R.string.bookmark_remove);
+                    }
+                }
+                return true;
+            case R.id.share:
+                tab = Tabs.getInstance().getSelectedTab();
+                if (tab != null) {
+                  GeckoAppShell.openUriExternal(tab.getURL(), "text/plain", "", "",
+                                                Intent.ACTION_SEND, tab.getTitle());
+                }
+                return true;
+            case R.id.reload:
+                doReload();
+                return true;
+            case R.id.forward:
+                doForward();
+                return true;
+            case R.id.save_as_pdf:
+                GeckoAppShell.sendEventToGecko(new GeckoEvent("SaveAs:PDF", null));
+                return true;
+            case R.id.preferences:
+                intent = new Intent(this, GeckoPreferences.class);
+                startActivity(intent);
+                return true;
+            case R.id.addons:
+                GeckoAppShell.sendEventToGecko(new GeckoEvent("about:addons"));
+                return true;
+            case R.id.agent_mode:
+                Tab selectedTab = Tabs.getInstance().getSelectedTab();
+                if (selectedTab == null)
+                    return true;
+                JSONObject args = new JSONObject();
+                try {
+                    args.put("agent", selectedTab.getAgentMode() == Tab.AgentMode.MOBILE ? "desktop" : "mobile");
+                    args.put("tabId", selectedTab.getId());
+                } catch (JSONException e) {
+                    Log.e(LOGTAG, "error building json arguments");
+                }
+                GeckoAppShell.sendEventToGecko(new GeckoEvent("AgentMode:Change", args.toString()));
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+    public String getLastViewport() {
+        return mLastViewport;
+    }
+
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        if (mOwnActivityDepth > 0)
+            return; // we're showing one of our own activities and likely won't get paged out
+        if (outState == null)
+            outState = new Bundle();
+        mRememberLastScreenRunnable.run();
+        outState.putString(SAVED_STATE_URI, mLastUri);
+        outState.putString(SAVED_STATE_TITLE, mLastTitle);
+        outState.putString(SAVED_STATE_VIEWPORT, mLastViewport);
+        outState.putByteArray(SAVED_STATE_SCREEN, mLastScreen);
+    }
+
+    Runnable mRememberLastScreenRunnable = new Runnable() {; 
+        public void run() {
+            synchronized (this) {
+                if (mUserDefinedProfile)
+                    return;
+
+                Tab tab = Tabs.getInstance().getSelectedTab();
+                if (tab == null)
+                    return;
+
+                HistoryEntry lastHistoryEntry = tab.getLastHistoryEntry();
+                if (lastHistoryEntry == null)
+                    return;
+
+                if (getLayerController().getLayerClient() != mSoftwareLayerClient)
+                    return;
+
+                if (mLastUri == lastHistoryEntry.mUri &&
+                    mLastTitle == lastHistoryEntry.mTitle)
+                    return;
+   
+                mLastViewport = mSoftwareLayerClient.getGeckoViewportMetrics().toJSON();
+                mLastUri = lastHistoryEntry.mUri;
+                mLastTitle = lastHistoryEntry.mTitle;
+                Bitmap bitmap = mSoftwareLayerClient.getBitmap();
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
+                mLastScreen = bos.toByteArray();
+            }
+        }
+    };
+
+    private void maybeCancelFaviconLoad(Tab tab) {
+        long faviconLoadId = tab.getFaviconLoadId();
+
+        if (faviconLoadId == Favicons.NOT_LOADING)
+            return;
+
+        // Cancel pending favicon load task
+        mFavicons.cancelFaviconLoad(faviconLoadId);
+
+        // Reset favicon load state
+        tab.setFaviconLoadId(Favicons.NOT_LOADING);
+    }
+
+    private void loadFavicon(final Tab tab) {
+        maybeCancelFaviconLoad(tab);
+
+        long id = mFavicons.loadFavicon(tab.getURL(), tab.getFaviconURL(),
+                        new Favicons.OnFaviconLoadedListener() {
+
+            public void onFaviconLoaded(String pageUrl, Drawable favicon) {
+                // Leave favicon UI untouched if we failed to load the image
+                // for some reason.
+                if (favicon == null)
+                    return;
+
+                Log.i(LOGTAG, "Favicon successfully loaded for URL = " + pageUrl);
+
+                // The tab might be pointing to another URL by the time the
+                // favicon is finally loaded, in which case we simply ignore it.
+                if (!tab.getURL().equals(pageUrl))
+                    return;
+
+                Log.i(LOGTAG, "Favicon is for current URL = " + pageUrl);
+
+                tab.updateFavicon(favicon);
+                tab.setFaviconLoadId(Favicons.NOT_LOADING);
+
+                if (Tabs.getInstance().isSelectedTab(tab))
+                    mBrowserToolbar.setFavicon(tab.getFavicon());
+
+                onTabsChanged(tab);
+            }
+        });
+
+        tab.setFaviconLoadId(id);
+    }
+
+    void handleLocationChange(final int tabId, final String uri) {
+        final Tab tab = Tabs.getInstance().getTab(tabId);
+        if (tab == null)
+            return;
+        
+        String oldBaseURI = tab.getURL();
+        tab.updateURL(uri);
+
+        String baseURI = uri;
+        if (baseURI.indexOf('#') != -1)
+            baseURI = uri.substring(0, uri.indexOf('#'));
+
+        if (oldBaseURI != null && oldBaseURI.indexOf('#') != -1)
+            oldBaseURI = oldBaseURI.substring(0, oldBaseURI.indexOf('#'));
+        
+        if (baseURI.equals(oldBaseURI))
+            return;
+
+        tab.updateFavicon(null);
+        tab.updateFaviconURL(null);
+        tab.updateSecurityMode("unknown");
+        tab.removeTransientDoorHangers();
+
+        maybeCancelFaviconLoad(tab);
+
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                if (Tabs.getInstance().isSelectedTab(tab)) {
+                    mBrowserToolbar.setTitle(uri);
+                    mBrowserToolbar.setFavicon(null);
+                    mBrowserToolbar.setSecurityMode("unknown");
+                    mDoorHangerPopup.updatePopup();
+                }
+            }
+        });
+    }
+
+    void handleSecurityChange(final int tabId, final String mode) {
+        final Tab tab = Tabs.getInstance().getTab(tabId);
+        if (tab == null)
+            return;
+
+        tab.updateSecurityMode(mode);
+        
+        mMainHandler.post(new Runnable() { 
+            public void run() {
+                if (Tabs.getInstance().isSelectedTab(tab))
+                    mBrowserToolbar.setSecurityMode(mode);
+            }
+        });
+    }
+
+    File getProfileDir() {
+        if (mProfileDir == null && !mUserDefinedProfile) {
+            File mozDir = new File(GeckoAppShell.sHomeDir, "mozilla");
+            File[] profiles = mozDir.listFiles(new FileFilter() {
+                public boolean accept(File pathname) {
+                    return pathname.getName().endsWith(".default");
+                }
+            });
+            if (profiles.length == 1)
+                mProfileDir = profiles[0];
+            // XXX: TO-DO read profiles.ini to get the default profile
+        }
+        return mProfileDir;
+    }
+
+    void addTab() {
+        showAwesomebar(AwesomeBar.Type.ADD);
+    }
+
+    void showTabs() {
+        Intent intent = new Intent(mAppContext, TabsTray.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+        startActivity(intent);
+        overridePendingTransition(R.anim.grow_fade_in, 0);
+    }
+
+    public static void registerOnTabsChangedListener(OnTabsChangedListener listener) {
+        if (mTabsChangedListeners == null)
+            mTabsChangedListeners = new ArrayList<OnTabsChangedListener>();
+        
+        mTabsChangedListeners.add(listener);
+    }
+
+    public static void unregisterOnTabsChangedListener(OnTabsChangedListener listener) {
+        if (mTabsChangedListeners == null)
+            return;
+        
+        mTabsChangedListeners.remove(listener);
+    }
+
+    public void onTabsChanged(Tab tab) {
+        if (mTabsChangedListeners == null)
+            return;
+
+        Iterator items = mTabsChangedListeners.iterator();
+        while (items.hasNext()) {
+            ((OnTabsChangedListener) items.next()).onTabsChanged(tab);
+        }
+    }
+
+    public void handleMessage(String event, JSONObject message) {
+        Log.i(LOGTAG, "Got message: " + event);
+        try {
+            if (event.equals("Menu:Add")) {
+                String name = message.getString("name");
+                ExtraMenuItem item = new ExtraMenuItem();
+                item.label = message.getString("name");
+                item.id = message.getInt("id");
+                try { // icon is optional
+                    item.icon = message.getString("icon");
+                } catch (Exception ex) { }
+                sExtraMenuItems.add(item);
+            } else if (event.equals("Menu:Remove")) {
+                // remove it from the menu and from our vector
+                Iterator<ExtraMenuItem> i = sExtraMenuItems.iterator();
+                int id = message.getInt("id");
+                while (i.hasNext()) {
+                    ExtraMenuItem item = i.next();
+                    if (item.id == id) {
+                        sExtraMenuItems.remove(item);
+                        MenuItem menu = sMenu.findItem(id);
+                        if (menu != null)
+                            sMenu.removeItem(id);
+                        return;
+                    }
+                }
+            } else if (event.equals("Toast:Show")) {
+                final String msg = message.getString("message");
+                final String duration = message.getString("duration");
+                handleShowToast(msg, duration);
+            } else if (event.equals("DOMContentLoaded")) {
+                final int tabId = message.getInt("tabID");
+                final String uri = message.getString("uri");
+                final String title = message.getString("title");
+                final CharSequence titleText = title;
+                handleContentLoaded(tabId, uri, title);
+                Log.i(LOGTAG, "URI - " + uri + ", title - " + title);
+            } else if (event.equals("DOMTitleChanged")) {
+                final int tabId = message.getInt("tabID");
+                final String title = message.getString("title");
+                final CharSequence titleText = title;
+                handleTitleChanged(tabId, title);
+                Log.i(LOGTAG, "title - " + title);
+            } else if (event.equals("DOMLinkAdded")) {
+                final int tabId = message.getInt("tabID");
+                final String rel = message.getString("rel");
+                final String href = message.getString("href");
+                Log.i(LOGTAG, "link rel - " + rel + ", href - " + href);
+                handleLinkAdded(tabId, rel, href);
+            } else if (event.equals("log")) {
+                // generic log listener
+                final String msg = message.getString("msg");
+                Log.i(LOGTAG, "Log: " + msg);
+            } else if (event.equals("Content:LocationChange")) {
+                final int tabId = message.getInt("tabID");
+                final String uri = message.getString("uri");
+                Log.i(LOGTAG, "URI - " + uri);
+                handleLocationChange(tabId, uri);
+            } else if (event.equals("Content:SecurityChange")) {
+                final int tabId = message.getInt("tabID");
+                final String mode = message.getString("mode");
+                Log.i(LOGTAG, "Security Mode - " + mode);
+                handleSecurityChange(tabId, mode);
+            } else if (event.equals("Content:StateChange")) {
+                final int tabId = message.getInt("tabID");
+                int state = message.getInt("state");
+                Log.i(LOGTAG, "State - " + state);
+                if ((state & GeckoAppShell.WPL_STATE_IS_DOCUMENT) != 0) {
+                    if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
+                        Log.i(LOGTAG, "Got a document start");
+                        handleDocumentStart(tabId);
+                    } else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
+                        Log.i(LOGTAG, "Got a document stop");
+                        handleDocumentStop(tabId);
+                    }
+                }
+            } else if (event.equals("onCameraCapture")) {
+                //GeckoApp.mAppContext.doCameraCapture(message.getString("path"));
+                doCameraCapture();
+            } else if (event.equals("Tab:Added")) {
+                Log.i(LOGTAG, "Created a new tab");
+                int tabId = message.getInt("tabID");
+                String uri = message.getString("uri");
+                Boolean selected = message.getBoolean("selected");
+                handleAddTab(tabId, uri, selected);
+            } else if (event.equals("Tab:Closed")) {
+                Log.i(LOGTAG, "Destroyed a tab");
+                int tabId = message.getInt("tabID");
+                handleCloseTab(tabId);
+            } else if (event.equals("Tab:Selected")) {
+                int tabId = message.getInt("tabID");
+                Log.i(LOGTAG, "Switched to tab: " + tabId);
+                handleSelectTab(tabId);
+            } else if (event.equals("Doorhanger:Add")) {
+                handleDoorHanger(message);
+            } else if (event.equals("Doorhanger:Remove")) {
+                handleDoorHangerRemove(message);
+            } else if (event.equals("Gecko:Ready")) {
+                sIsGeckoReady = true;
+                mMainHandler.post(new Runnable() {
+                    public void run() {
+                        if (sMenu != null)
+                            sMenu.findItem(R.id.preferences).setEnabled(true);
+                    }
+                });
+                setLaunchState(GeckoApp.LaunchState.GeckoRunning);
+                GeckoAppShell.sendPendingEventsToGecko();
+                connectGeckoLayerClient();
+            } else if (event.equals("ToggleChrome:Hide")) {
+                mMainHandler.post(new Runnable() {
+                    public void run() {
+                        mBrowserToolbar.setVisibility(View.GONE);
+                    }
+                });
+            } else if (event.equals("ToggleChrome:Show")) {
+                mMainHandler.post(new Runnable() {
+                    public void run() {
+                        mBrowserToolbar.setVisibility(View.VISIBLE);
+                    }
+                });
+            } else if (event.equals("AboutHome:Show")) {
+                showAboutHome();
+            } else if (event.equals("AgentMode:Changed")) {
+                Tab.AgentMode agentMode = message.getString("agentMode").equals("mobile") ? Tab.AgentMode.MOBILE : Tab.AgentMode.DESKTOP;
+                int tabId = message.getInt("tabId");
+                Tab tab = Tabs.getInstance().getTab(tabId);
+                if (tab == null)
+                    return;
+
+                tab.setAgentMode(agentMode);
+                if (tab == Tabs.getInstance().getSelectedTab())
+                    updateAgentModeMenuItem(tab, agentMode);
+            }
+        } catch (Exception e) {
+            Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
+        }
+    }
+
+    public void showAboutHome() {
+        Runnable r = new AboutHomeRunnable(true);
+        mMainHandler.postAtFrontOfQueue(r);
+    }
+
+    public void hideAboutHome() {
+        Runnable r = new AboutHomeRunnable(false);
+        mMainHandler.postAtFrontOfQueue(r);
+    }
+
+    public class  AboutHomeRunnable implements Runnable {
+        boolean mShow;
+        AboutHomeRunnable(boolean show) {
+            mShow = show;
+        }
+
+        public void run() {
+            if (mAboutHomeContent == null) {
+                mAboutHomeContent = new AboutHomeContent(GeckoApp.mAppContext, null);
+                mAboutHomeContent.init(GeckoApp.mAppContext);
+                mAboutHomeContent.setUriLoadCallback(new AboutHomeContent.UriLoadCallback() {
+                    public void callback(String url) {
+                        mBrowserToolbar.setProgressVisibility(true);
+                        loadUrl(url, AwesomeBar.Type.EDIT);
+                    }
+                });
+                mGeckoLayout.addView(mAboutHomeContent);
+            }
+            if (mLayerController != null && mLayerController.getView() != null)
+                mLayerController.getView().setVisibility(mShow ? View.GONE : View.VISIBLE);
+            mAboutHomeContent.setVisibility(mShow ? View.VISIBLE : View.GONE);
+        }
+    }
+
+    void updateAgentModeMenuItem(final Tab tab, final Tab.AgentMode agentMode) {
+        if (sMenu == null)
+            return;
+
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                if (Tabs.getInstance().isSelectedTab(tab)) {
+                    int strId = agentMode == Tab.AgentMode.MOBILE ? R.string.agent_request_desktop : R.string.agent_request_mobile;
+                    sMenu.findItem(R.id.agent_mode).setTitle(getString(strId));
+                }
+            }
+        });
+    }
+
+    void handleDoorHanger(JSONObject geckoObject) throws JSONException {
+        final String message = geckoObject.getString("message");
+        final String value = geckoObject.getString("value");
+        final JSONArray buttons = geckoObject.getJSONArray("buttons");
+        final int tabId = geckoObject.getInt("tabID");
+        final JSONObject options = geckoObject.getJSONObject("options");
+
+        Log.i(LOGTAG, "DoorHanger received for tab " + tabId + ", msg:" + message);
+
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                Tab tab = Tabs.getInstance().getTab(tabId);
+                mAppContext.mDoorHangerPopup.addDoorHanger(message, value, buttons,
+                                                           tab, options);
+            }
+        });
+    }
+
+    void handleDoorHangerRemove(JSONObject geckoObject) throws JSONException {
+        final String value = geckoObject.getString("value");
+        final int tabId = geckoObject.getInt("tabID");
+
+        Log.i(LOGTAG, "Doorhanger:Remove received for tab " + tabId);
+
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                Tab tab = Tabs.getInstance().getTab(tabId);
+                if (tab == null)
+                    return;
+                tab.removeDoorHanger(value);
+                mDoorHangerPopup.updatePopup();
+            }
+        });
+    }
+
+    void handleAddTab(final int tabId, final String uri, final boolean selected) {
+        final Tab tab = Tabs.getInstance().addTab(tabId, uri);
+        if (selected) {
+            Tabs.getInstance().selectTab(tabId);
+        }
+
+        mMainHandler.post(new Runnable() { 
+            public void run() {
+                if (selected && Tabs.getInstance().isSelectedTab(tab)) {
+                    onTabsChanged(tab);
+                    mDoorHangerPopup.updatePopup();
+                }
+                mBrowserToolbar.updateTabs(Tabs.getInstance().getCount());
+            }
+        });
+    }
+
+    void handleCloseTab(final int tabId) {
+        final Tab tab = Tabs.getInstance().getTab(tabId);
+        Tabs.getInstance().removeTab(tabId);
+        tab.removeAllDoorHangers();
+
+        mMainHandler.post(new Runnable() { 
+            public void run() {
+                onTabsChanged(tab);
+                mBrowserToolbar.updateTabs(Tabs.getInstance().getCount());
+                mDoorHangerPopup.updatePopup();
+            }
+        });
+    }
+
+    void handleSelectTab(int tabId) {
+        Tab selTab = Tabs.getInstance().getSelectedTab();
+        selTab.updateThumbnail(mSoftwareLayerClient.getBitmap());
+        final Tab tab = Tabs.getInstance().selectTab(tabId);
+        if (tab == null)
+            return;
+
+        if (selTab.getURL().equals("about:home") && !tab.getURL().equals("about:home"))
+            hideAboutHome();
+        else if (tab.getURL().equals("about:home"))
+            showAboutHome();
+
+        updateAgentModeMenuItem(tab, tab.getAgentMode());
+
+        mMainHandler.post(new Runnable() { 
+            public void run() {
+                if (Tabs.getInstance().isSelectedTab(tab)) {
+                    mBrowserToolbar.setTitle(tab.getDisplayTitle());
+                    mBrowserToolbar.setFavicon(tab.getFavicon());
+                    mBrowserToolbar.setSecurityMode(tab.getSecurityMode());
+                    mBrowserToolbar.setProgressVisibility(tab.isLoading());
+                    mDoorHangerPopup.updatePopup();
+                }
+            }
+        });
+    }
+
+    void handleDocumentStart(int tabId) {
+        final Tab tab = Tabs.getInstance().getTab(tabId);
+        if (tab == null)
+            return;
+
+        tab.setLoading(true);
+        tab.updateSecurityMode("unknown");
+
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                if (Tabs.getInstance().isSelectedTab(tab)) {
+                    mBrowserToolbar.setSecurityMode(tab.getSecurityMode());
+                    mBrowserToolbar.setProgressVisibility(true);
+                }
+                onTabsChanged(tab);
+            }
+        });
+    }
+
+    void handleDocumentStop(int tabId) {
+        final Tab tab = Tabs.getInstance().getTab(tabId);
+        if (tab == null)
+            return;
+
+        tab.setLoading(false);
+
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                if (Tabs.getInstance().isSelectedTab(tab))
+                    mBrowserToolbar.setProgressVisibility(false);
+                onTabsChanged(tab);
+            }
+        });
+    }
+
+    void handleShowToast(final String message, final String duration) {
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                Toast toast;
+                if (duration.equals("long"))
+                    toast = Toast.makeText(mAppContext, message, Toast.LENGTH_LONG);
+                else
+                    toast = Toast.makeText(mAppContext, message, Toast.LENGTH_SHORT);
+                toast.show();
+            }
+        });
+    }
+
+    void handleContentLoaded(int tabId, String uri, String title) {
+        final Tab tab = Tabs.getInstance().getTab(tabId);
+        if (tab == null)
+            return;
+
+        tab.updateTitle(title);
+
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                loadFavicon(tab);
+
+                if (Tabs.getInstance().isSelectedTab(tab)) {
+                    mBrowserToolbar.setTitle(tab.getDisplayTitle());
+                    tab.updateThumbnail(mSoftwareLayerClient.getBitmap());
+                }
+                onTabsChanged(tab);
+            }
+        });
+        GeckoAppShell.getHandler().postDelayed(mRememberLastScreenRunnable, 500);
+    }
+
+    void handleTitleChanged(int tabId, String title) {
+        final Tab tab = Tabs.getInstance().getTab(tabId);
+        if (tab == null)
+            return;
+
+        tab.updateTitle(title);
+
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                if (Tabs.getInstance().isSelectedTab(tab))
+                    mBrowserToolbar.setTitle(tab.getDisplayTitle());
+                onTabsChanged(tab);
+            }
+        });
+    }
+
+    void handleLinkAdded(final int tabId, String rel, final String href) {
+        if (rel.indexOf("icon") != -1) {
+            final Tab tab = Tabs.getInstance().getTab(tabId);
+            if (tab != null) {
+                tab.updateFaviconURL(href);
+
+                // If tab is not loading and the favicon is updated, we
+                // want to load the image straight away. If tab is still
+                // loading, we only load the favicon once the page's content
+                // is fully loaded (see handleContentLoaded()).
+                if (!tab.isLoading()) {
+                    mMainHandler.post(new Runnable() {
+                        public void run() {
+                            loadFavicon(tab);
+                        }
+                    });
+                }
+            }
+        }
+    }
+
+    void addPluginView(final View view,
+                       final double x, final double y,
+                       final double w, final double h) {
+        mMainHandler.post(new Runnable() { 
+            public void run() {
+                PluginLayoutParams lp;
+
+                ViewportMetrics geckoViewport = mSoftwareLayerClient.getGeckoViewportMetrics();
+
+                if (mGeckoLayout.indexOfChild(view) == -1) {
+                    lp = PluginLayoutParams.create((int)x, (int)y, (int)w, (int)h, geckoViewport.getZoomFactor());
+
+                    view.setWillNotDraw(false);
+                    if (view instanceof SurfaceView) {
+                        SurfaceView sview = (SurfaceView)view;
+
+                        sview.setZOrderOnTop(false);
+                        sview.setZOrderMediaOverlay(true);
+                    }
+
+                    mGeckoLayout.addView(view, lp);
+                    mPluginViews.add(view);
+                } else {
+                    lp = (PluginLayoutParams)view.getLayoutParams();
+                    lp.reset((int)x, (int)y, (int)w, (int)h, geckoViewport.getZoomFactor());
+                    try {
+                        mGeckoLayout.updateViewLayout(view, lp);
+                    } catch (IllegalArgumentException e) {
+                        Log.i(LOGTAG, "e:" + e);
+                        // it can be the case where we
+                        // get an update before the view
+                        // is actually attached.
+                    }
+                }
+            }
+        });
+    }
+
+    void removePluginView(final View view) {
+        mMainHandler.post(new Runnable() { 
             public void run() {
                 try {
-                    if (mLibLoadThread != null)
-                        mLibLoadThread.join();
-                } catch (InterruptedException ie) {}
+                    mGeckoLayout.removeView(view);
+                    mPluginViews.remove(view);
+                } catch (Exception e) {}
+            }
+        });
+    }
 
-                // 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();
+    public void hidePluginViews() {
+        for (View view : mPluginViews) {
+            view.setVisibility(View.GONE);
+        }
+    }
+
+    public void showPluginViews() {
+        repositionPluginViews(true);
+    }
+
+    public void repositionPluginViews(boolean setVisible) {
+        ViewportMetrics hostViewport = mSoftwareLayerClient.getGeckoViewportMetrics();
+        ViewportMetrics targetViewport = mLayerController.getViewportMetrics();
 
-                // 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;
-                }
+        if (hostViewport == null || targetViewport == null)
+            return;
+
+        for (View view : mPluginViews) {
+            PluginLayoutParams lp = (PluginLayoutParams)view.getLayoutParams();
+            lp.reposition(hostViewport, targetViewport);
+
+            if (setVisible) {
+                view.setVisibility(View.VISIBLE);
+            }
 
-                // and then fire us up
-                try {
-                    String env = i.getStringExtra("env0");
-                    GeckoAppShell.runGecko(getApplication().getPackageResourcePath(),
-                                           i.getStringExtra("args"),
-                                           i.getDataString());
-                } catch (Exception e) {
-                    Log.e(LOG_FILE_NAME, "top level exception", e);
-                    StringWriter sw = new StringWriter();
-                    PrintWriter pw = new PrintWriter(sw);
-                    e.printStackTrace(pw);
-                    pw.flush();
-                    GeckoAppShell.reportJavaCrash(sw.toString());
-                }
+            mGeckoLayout.updateViewLayout(view, lp);
+        }
+    }
+
+    public void setFullScreen(final boolean fullscreen) {
+        mFullScreen = fullscreen;
+        mMainHandler.post(new Runnable() { 
+            public void run() {
+                // Hide/show the system notification bar
+                getWindow().setFlags(fullscreen ?
+                                     WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
+                                     WindowManager.LayoutParams.FLAG_FULLSCREEN);
             }
-        }.start();
-        return true;
+        });
     }
 
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState)
     {
+        System.loadLibrary("mozutils");
+        Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - onCreate");
+        if (savedInstanceState != null) {
+            mLastUri = savedInstanceState.getString(SAVED_STATE_URI);
+            mLastTitle = savedInstanceState.getString(SAVED_STATE_TITLE);
+            mLastViewport = savedInstanceState.getString(SAVED_STATE_VIEWPORT);
+            mLastScreen = savedInstanceState.getByteArray(SAVED_STATE_SCREEN);
+        }
+        if (Build.VERSION.SDK_INT >= 9) {
+            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+                                       .detectDiskReads().detectDiskWrites().detectNetwork()
+                                       .penaltyLog().build());
+            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().penaltyLog().build());
+        }
+
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.gecko_app);
         mAppContext = this;
+
+        if (Build.VERSION.SDK_INT >= 11) {
+            ActionBar actionBar = getActionBar();
+            mBrowserToolbar = (BrowserToolbar) getLayoutInflater().inflate(R.layout.gecko_app_actionbar, null);
+
+            actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM |
+                                                                       ActionBar.DISPLAY_SHOW_HOME |
+                                                                       ActionBar.DISPLAY_SHOW_TITLE |
+                                                                       ActionBar.DISPLAY_USE_LOGO);
+            actionBar.setCustomView(mBrowserToolbar, new ActionBar.LayoutParams(ActionBar.LayoutParams.FILL_PARENT,
+                                                                                ActionBar.LayoutParams.WRAP_CONTENT));
+        } else {
+            mBrowserToolbar = (BrowserToolbar) findViewById(R.id.browser_toolbar);
+        }
+
+        mFavicons = new Favicons(this);
+
+        // setup gecko layout
+        mGeckoLayout = (AbsoluteLayout) findViewById(R.id.gecko_layout);
+        mMainLayout = (LinearLayout) findViewById(R.id.main_layout);
+
+        mDoorHangerPopup = new DoorHangerPopup(this);
+
+        Tabs tabs = Tabs.getInstance();
+        Tab tab = tabs.getSelectedTab();
+        if (tab != null) {
+            mBrowserToolbar.setTitle(tab.getDisplayTitle());
+            mBrowserToolbar.setFavicon(tab.getFavicon());
+            mBrowserToolbar.setProgressVisibility(tab.isLoading());
+            mBrowserToolbar.updateTabs(Tabs.getInstance().getCount()); 
+        }
+
+        tabs.setContentResolver(getContentResolver()); 
+
+        if (cameraView == null) {
+            cameraView = new SurfaceView(this);
+            cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+        }
+
+        if (mLayerController == null) {
+            /*
+             * Create a layer client so that Gecko will have a buffer to draw into, but don't hook
+             * it up to the layer controller yet.
+             */
+            mSoftwareLayerClient = new GeckoSoftwareLayerClient(this);
+
+            /*
+             * Hook a placeholder layer client up to the layer controller so that the user can pan
+             * and zoom a cached screenshot of the previous page. This call will return null if
+             * there is no cached screenshot; in that case, we have no choice but to display a
+             * checkerboard.
+             *
+             * TODO: Fall back to a built-in screenshot of the Fennec Start page for a nice first-
+             * run experience, perhaps?
+             */
+            mLayerController = new LayerController(this);
+            mPlaceholderLayerClient = mUserDefinedProfile ?  null :
+                PlaceholderLayerClient.createInstance(this);
+            if (mPlaceholderLayerClient != null) {
+                mLayerController.setLayerClient(mPlaceholderLayerClient);
+            }
+
+            mGeckoLayout.addView(mLayerController.getView());
+        }
+
+        Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - UI almost up");
+
+        if (sGREDir == null)
+            sGREDir = new File(this.getApplicationInfo().dataDir);
+
         mMainHandler = new Handler();
 
         if (!sTryCatchAttached) {
             sTryCatchAttached = true;
             mMainHandler.post(new Runnable() {
                 public void run() {
                     try {
                         Looper.loop();
                     } catch (Exception e) {
-                        Log.e(LOG_FILE_NAME, "top level exception", e);
+                        Log.e(LOGTAG, "top level exception", e);
                         StringWriter sw = new StringWriter();
                         PrintWriter pw = new PrintWriter(sw);
                         e.printStackTrace(pw);
                         pw.flush();
                         GeckoAppShell.reportJavaCrash(sw.toString());
                     }
                     // resetting this is kinda pointless, but oh well
                     sTryCatchAttached = false;
                 }
             });
         }
 
-        SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
-        String localeCode = settings.getString(getPackageName() + ".locale", "");
-        if (localeCode != null && localeCode.length() > 0)
-            GeckoAppShell.setSelectedLocale(localeCode);
-
-        Log.i(LOG_FILE_NAME, "create");
-        super.onCreate(savedInstanceState);
-
-        if (sGREDir == null)
-            sGREDir = new File(this.getApplicationInfo().dataDir);
-
-        getWindow().setFlags(mFullscreen ?
-                             WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
-                             WindowManager.LayoutParams.FLAG_FULLSCREEN);
-
-        if (cameraView == null) {
-            cameraView = new SurfaceView(this);
-            cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
-        }
-
-        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));
+        //register for events
+        GeckoAppShell.registerGeckoEventListener("DOMContentLoaded", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("DOMTitleChanged", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("DOMLinkAdded", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("log", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Content:LocationChange", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Content:SecurityChange", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Content:StateChange", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("onCameraCapture", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Tab:Added", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Tab:Closed", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Tab:Selected", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Doorhanger:Add", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Doorhanger:Remove", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Menu:Add", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Menu:Remove", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Gecko:Ready", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Toast:Show", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("ToggleChrome:Hide", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("AgentMode:Changed", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("AboutHome:Show", GeckoApp.mAppContext);
 
         mConnectivityFilter = new IntentFilter();
         mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         mConnectivityReceiver = new GeckoConnectivityReceiver();
 
         IntentFilter batteryFilter = new IntentFilter();
         batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         mBatteryReceiver = new GeckoBatteryManager();
         registerReceiver(mBatteryReceiver, batteryFilter);
-
-        IntentFilter smsFilter = new IntentFilter();
-        smsFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
+                
+        mSmsFilter = new IntentFilter();
+        mSmsFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
         mSmsReceiver = new GeckoSmsManager();
-        registerReceiver(mSmsReceiver, smsFilter);
+        registerReceiver(mSmsReceiver, mSmsFilter);
 
-        if (!checkAndSetLaunchState(LaunchState.PreLaunch,
-                                    LaunchState.Launching))
-            return;
-
-        checkAndLaunchUpdate();
-        mLibLoadThread = new Thread(new Runnable() {
+        final GeckoApp self = this;
+ 
+        mMainHandler.postDelayed(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();
+                
+                Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - pre checkLaunchState");
+
+                /*
+                  XXXX see bug 635342
+                   We want to disable this code if possible.  It is about 145ms in runtime
+                SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
+                String localeCode = settings.getString(getPackageName() + ".locale", "");
+                if (localeCode != null && localeCode.length() > 0)
+                    GeckoAppShell.setSelectedLocale(localeCode);
+                */
+
+                if (!checkLaunchState(LaunchState.Launched)) {
+                    return;
+                }
+
+                // it would be good only to do this if MOZ_UPDATER was defined 
+                long startTime = new Date().getTime();
+                checkAndLaunchUpdate();
+                Log.w(LOGTAG, "checking for an update took " + (new Date().getTime() - startTime) + "ms");
+            }
+        }, 50);
     }
 
     public void enableCameraView() {
         // Some phones (eg. nexus S) need at least a 8x16 preview size
-        mainLayout.addView(cameraView, new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
+        mMainLayout.addView(cameraView, new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
     }
 
     public void disableCameraView() {
-        mainLayout.removeView(cameraView);
+        mMainLayout.removeView(cameraView);
     }
 
     @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
             System.exit(0);
             return;
         }
         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");
+                    Log.i(LOGTAG, "Launching from debug intent after 5s wait");
                     setLaunchState(LaunchState.Launching);
-                    launch(null);
+                    launch(getIntent());
                 }
             }, 1000 * 5 /* 5 seconds */);
-            Log.i(LOG_FILE_NAME, "Intent : ACTION_DEBUG - waiting 5s before launching");
+            Log.i(LOGTAG, "Intent : ACTION_DEBUG - waiting 5s before launching");
             return;
         }
         if (checkLaunchState(LaunchState.WaitForDebugger) || launch(intent))
             return;
 
         if (Intent.ACTION_MAIN.equals(action)) {
-            Log.i(LOG_FILE_NAME, "Intent : ACTION_MAIN");
+            Log.i(LOGTAG, "Intent : ACTION_MAIN");
             GeckoAppShell.sendEventToGecko(new GeckoEvent(""));
         }
         else if (Intent.ACTION_VIEW.equals(action)) {
+            prefetchDNS(intent.getData());
             String uri = intent.getDataString();
             GeckoAppShell.sendEventToGecko(new GeckoEvent(uri));
-            Log.i(LOG_FILE_NAME,"onNewIntent: "+uri);
+            Log.i(LOGTAG,"onNewIntent: " + uri);
         }
         else if (ACTION_WEBAPP.equals(action)) {
             String uri = intent.getStringExtra("args");
             GeckoAppShell.sendEventToGecko(new GeckoEvent(uri));
-            Log.i(LOG_FILE_NAME,"Intent : WEBAPP - " + uri);
+            Log.i(LOGTAG,"Intent : WEBAPP - " + uri);
         }
         else if (ACTION_BOOKMARK.equals(action)) {
             String args = intent.getStringExtra("args");
             GeckoAppShell.sendEventToGecko(new GeckoEvent(args));
-            Log.i(LOG_FILE_NAME,"Intent : BOOKMARK - " + args);
+            Log.i(LOGTAG,"Intent : BOOKMARK - " + args);
         }
     }
 
     @Override
     public void onPause()
     {
-        Log.i(LOG_FILE_NAME, "pause");
+        Log.i(LOGTAG, "pause");
+
+        GeckoAppShell.getHandler().post(mRememberLastScreenRunnable);
+
         GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_PAUSING));
         // The user is navigating away from this activity, but nothing
         // has come to the foreground yet; for Gecko, we may want to
         // stop repainting, for example.
 
         // Whatever we do here should be fast, because we're blocking
         // the next activity from showing up until we finish.
 
         // onPause will be followed by either onResume or onStop.
         super.onPause();
 
+        unregisterReceiver(mSmsReceiver);
         unregisterReceiver(mConnectivityReceiver);
     }
 
     @Override
     public void onResume()
     {
-        Log.i(LOG_FILE_NAME, "resume");
+        Log.i(LOGTAG, "resume");
         if (checkLaunchState(LaunchState.GeckoRunning))
             GeckoAppShell.onResume();
         // After an onPause, the activity is back in the foreground.
         // Undo whatever we did in onPause.
         super.onResume();
 
         // Just in case. Normally we start in onNewIntent
-        if (checkLaunchState(LaunchState.PreLaunch) ||
-            checkLaunchState(LaunchState.Launching))
+        if (checkLaunchState(LaunchState.Launching))
             onNewIntent(getIntent());
 
+        registerReceiver(mSmsReceiver, mSmsFilter);
         registerReceiver(mConnectivityReceiver, mConnectivityFilter);
+        if (mOwnActivityDepth > 0)
+            mOwnActivityDepth--;
     }
 
     @Override
     public void onStop()
     {
-        Log.i(LOG_FILE_NAME, "stop");
+        Log.i(LOGTAG, "stop");
         // We're about to be stopped, potentially in preparation for
         // being destroyed.  We're killable after this point -- as I
         // understand it, in extreme cases the process can be terminated
         // without going through onDestroy.
         //
         // We might also get an onRestart after this; not sure what
         // that would mean for Gecko if we were to kill it here.
         // Instead, what we should do here is save prefs, session,
         // etc., and generally mark the profile as 'clean', and then
         // dirty it again if we get an onResume.
 
         GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_STOPPING));
         super.onStop();
-        GeckoAppShell.putChildInBackground();
     }
 
     @Override
     public void onRestart()
     {
-        Log.i(LOG_FILE_NAME, "restart");
-        GeckoAppShell.putChildInForeground();
+        Log.i(LOGTAG, "restart");
         super.onRestart();
     }
 
     @Override
     public void onStart()
     {
-        Log.i(LOG_FILE_NAME, "start");
+        Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - onStart");
+
+        Log.i(LOGTAG, "start");
         GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_START));
         super.onStart();
     }
 
     @Override
     public void onDestroy()
     {
-        Log.i(LOG_FILE_NAME, "destroy");
+        Log.i(LOGTAG, "destroy");
 
         // Tell Gecko to shutting down; we'll end up calling System.exit()
         // in onXreExit.
         if (isFinishing())
             GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_SHUTDOWN));
+        
+        GeckoAppShell.unregisterGeckoEventListener("DOMContentLoaded", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("DOMTitleChanged", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("DOMLinkAdded", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("log", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Content:LocationChange", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Content:SecurityChange", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Content:StateChange", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("onCameraCapture", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Tab:Added", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Tab:Closed", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Tab:Selected", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Doorhanger:Add", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Menu:Add", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Menu:Remove", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Gecko:Ready", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Toast:Show", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("ToggleChrome:Hide", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("AgentMode:Changed", GeckoApp.mAppContext);
+
+        mFavicons.close();
 
         super.onDestroy();
 
-        unregisterReceiver(mSmsReceiver);
         unregisterReceiver(mBatteryReceiver);
     }
 
     @Override
+    public void onContentChanged() {
+        super.onContentChanged();
+        if (mAboutHomeContent == null)
+            return;
+        mAboutHomeContent = (AboutHomeContent) findViewById(R.id.abouthome_content);
+        mAboutHomeContent.onActivityContentChanged(this);
+    }
+
+
+    @Override
     public void onConfigurationChanged(android.content.res.Configuration newConfig)
     {
-        Log.i(LOG_FILE_NAME, "configuration changed");
+        Log.i(LOGTAG, "configuration changed");
         // nothing, just ignore
         super.onConfigurationChanged(newConfig);
     }
 
     @Override
     public void onLowMemory()
     {
-        Log.e(LOG_FILE_NAME, "low memory");
+        Log.e(LOGTAG, "low memory");
         if (checkLaunchState(LaunchState.GeckoRunning))
             GeckoAppShell.onLowMemory();
         super.onLowMemory();
     }
 
     abstract public String getPackageName();
     abstract public String getContentProcessName();