diff --git a/Makefile.in b/Makefile.in index 0f44bbcf40b..6922057a3b2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -66,7 +66,7 @@ tier_base_dirs = \ ifndef LIBXUL_SDK ifeq (android,$(MOZ_WIDGET_TOOLKIT)) -tier_base_dirs += other-licenses/android +tier_base_dirs += other-licenses/android other-licenses/skia-npapi endif tier_base_dirs += memory diff --git a/configure.in b/configure.in index f6ccc564eaa..01f3c75238f 100644 --- a/configure.in +++ b/configure.in @@ -4721,6 +4721,7 @@ case "${target}" in MOZ_THEME_FASTSTRIPE=1 MOZ_TREE_FREETYPE=1 MOZ_MEMORY=1 + MOZ_SPELLCHECK= MOZ_RAW=1 ;; esac diff --git a/content/base/public/nsIFrameLoader.idl b/content/base/public/nsIFrameLoader.idl index e7ac8e0ce16..e5af67a8617 100644 --- a/content/base/public/nsIFrameLoader.idl +++ b/content/base/public/nsIFrameLoader.idl @@ -141,7 +141,7 @@ interface nsIContentViewManager : nsISupports readonly attribute nsIContentView rootContentView; }; -[scriptable, uuid(12905a29-4246-475a-81d4-fc389197df02)] +[scriptable, uuid(efc0b731-45dc-4189-8ffa-d3eeeb850977)] interface nsIFrameLoader : nsISupports { /** @@ -258,6 +258,13 @@ interface nsIFrameLoader : nsISupports const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001; attribute unsigned long eventMode; + + /** + * If false, then the subdocument is not clipped to its CSS viewport, and the + * subdocument's viewport scrollbar(s) are not rendered. + * Defaults to true. + */ + attribute boolean clipSubdocument; }; native alreadyAddRefed_nsFrameLoader(already_AddRefed); diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index 7b049368447..5199f061129 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -145,6 +145,8 @@ public: static void InvalidateFrame(nsIFrame* aFrame) { + if (!aFrame) + return; nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size()); // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view // semantics the same for both in-process and out-of-process @@ -189,8 +191,7 @@ nsContentView::Update(const ViewConfig& aConfig) // XXX could be clever here and compute a smaller invalidation // rect - nsIFrame* frame = mFrameLoader->GetPrimaryFrameOfOwningContent(); - InvalidateFrame(frame); + InvalidateFrame(mFrameLoader->GetPrimaryFrameOfOwningContent()); return NS_OK; } @@ -328,6 +329,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated) , mDelayRemoteDialogs(false) , mRemoteBrowserShown(false) , mRemoteFrame(false) + , mClipSubdocument(true) , mCurrentRemoteFrame(nsnull) , mRemoteBrowser(nsnull) , mRenderMode(RENDER_MODE_DEFAULT) @@ -1711,6 +1713,38 @@ nsFrameLoader::SetEventMode(PRUint32 aEventMode) return NS_OK; } +NS_IMETHODIMP +nsFrameLoader::GetClipSubdocument(bool* aResult) +{ + *aResult = mClipSubdocument; + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::SetClipSubdocument(bool aClip) +{ + mClipSubdocument = aClip; + nsIFrame* frame = GetPrimaryFrameOfOwningContent(); + if (frame) { + InvalidateFrame(frame); + frame->PresContext()->PresShell()-> + FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); + nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame); + if (subdocFrame) { + nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame(); + if (subdocRootFrame) { + nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()-> + GetRootScrollFrame(); + if (subdocRootScrollFrame) { + frame->PresContext()->PresShell()-> + FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); + } + } + } + } + return NS_OK; +} + nsIntSize nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame) { diff --git a/content/base/src/nsFrameLoader.h b/content/base/src/nsFrameLoader.h index fa9765403fe..e452c2e100b 100644 --- a/content/base/src/nsFrameLoader.h +++ b/content/base/src/nsFrameLoader.h @@ -287,6 +287,8 @@ public: mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; } void SetOwnerContent(mozilla::dom::Element* aContent); + bool ShouldClipSubdocument() { return mClipSubdocument; } + private: bool ShouldUseRemoteProcess(); @@ -338,7 +340,9 @@ private: bool mDelayRemoteDialogs : 1; bool mRemoteBrowserShown : 1; - bool mRemoteFrame; + bool mRemoteFrame : 1; + bool mClipSubdocument : 1; + // XXX leaking nsCOMPtr mChildHost; RenderFrameParent* mCurrentRemoteFrame; diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 91778e69a45..e196b5eb052 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -4580,6 +4580,9 @@ nsGlobalWindow::Dump(const nsAString& aStr) nsMemory::Free(cstr); } +#if defined(ANDROID) && defined(DEBUG) + __android_log_print(ANDROID_LOG_INFO, "GeckoDump", "%s", cstr); +#endif return NS_OK; } diff --git a/dom/plugins/base/Makefile.in b/dom/plugins/base/Makefile.in index 402fe776554..bece2944c40 100644 --- a/dom/plugins/base/Makefile.in +++ b/dom/plugins/base/Makefile.in @@ -133,7 +133,10 @@ endif endif LOCAL_INCLUDES += \ + -DSK_BUILD_FOR_ANDROID_NDK \ -I$(topsrcdir)/xpcom/base/ \ + -I$(topsrcdir)/gfx/skia/include/core \ + -I$(topsrcdir)/gfx/skia/include/config \ $(MOZ_CAIRO_CFLAGS) \ $(NULL) diff --git a/dom/plugins/base/android/ANPBase.h b/dom/plugins/base/android/ANPBase.h index d84aab988ac..729de6a5a34 100644 --- a/dom/plugins/base/android/ANPBase.h +++ b/dom/plugins/base/android/ANPBase.h @@ -39,7 +39,6 @@ #include "android_npapi.h" #include #include "nsAutoPtr.h" -#include "gfxFont.h" #include "nsISupportsImpl.h" #define NOT_IMPLEMENTED_FATAL() do { \ @@ -54,8 +53,6 @@ "!!!!!!!!!!!!!! %s not implemented %s, %d", \ __PRETTY_FUNCTION__, __FILE__, __LINE__); \ -class gfxFont; - void InitAudioTrackInterface(ANPAudioTrackInterfaceV0 *i); void InitBitmapInterface(ANPBitmapInterfaceV0 *i); void InitCanvasInterface(ANPCanvasInterfaceV0 *i); @@ -68,25 +65,3 @@ void InitSurfaceInterface(ANPSurfaceInterfaceV0 *i); void InitSystemInterface(ANPSystemInterfaceV0 *i); void InitTypeFaceInterface(ANPTypefaceInterfaceV0 *i); void InitWindowInterface(ANPWindowInterfaceV0 *i); - -struct ANPTypeface { - gfxFont* mFont; - nsAutoRefCnt mRefCnt; -}; - - -typedef struct { - ANPMatrixFlag flags; - ANPColor color; - ANPPaintStyle style; - float strokeWidth; - float strokeMiter; - ANPPaintCap paintCap; - ANPPaintJoin paintJoin; - ANPTextEncoding textEncoding; - ANPPaintAlign paintAlign; - float textSize; - float textScaleX; - float textSkewX; - ANPTypeface typeface; -} ANPPaintPrivate; diff --git a/dom/plugins/base/android/ANPCanvas.cpp b/dom/plugins/base/android/ANPCanvas.cpp deleted file mode 100644 index 918d4fd60db..00000000000 --- a/dom/plugins/base/android/ANPCanvas.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** 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 Android NPAPI support code - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Doug Turner - * - * 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 ***** */ - -#include "assert.h" -#include "ANPBase.h" -#include - -#include "cairo.h" -#include "gfxPlatform.h" -#include "gfxASurface.h" -#include "gfxImageSurface.h" -#include "gfxUtils.h" -#include "gfxContext.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) -#define ASSIGN(obj, name) (obj)->name = anp_canvas_##name - - -ANPCanvas* -anp_canvas_newCanvas(const ANPBitmap* bitmap) -{ - PRUint32 stride; - gfxASurface::gfxImageFormat format; - - if (bitmap->format == kRGBA_8888_ANPBitmapFormat) { - stride = bitmap->width * 4; - format = gfxImageSurface::ImageFormatARGB32; - } - else if (bitmap->format == kRGB_565_ANPBitmapFormat) { - stride = bitmap->width * 2; - format = gfxImageSurface::ImageFormatRGB16_565; - } - else { - LOG("%s -- Unknown format", __PRETTY_FUNCTION__); - return nsnull; - } - - gfxImageSurface* pluginSurface = new gfxImageSurface(static_cast(bitmap->baseAddr), - gfxIntSize(bitmap->width, bitmap->height), - stride, - format); - if (pluginSurface->CairoStatus()) { - LOG("%s -- %d x %d FAILED to create gfxImageSurface", __PRETTY_FUNCTION__, bitmap->width, bitmap->height); - return nsnull; - } - - gfxContext *pluginContext = new gfxContext(pluginSurface); - NS_ADDREF(pluginContext); - return (ANPCanvas*) pluginContext; -} - -void -anp_canvas_deleteCanvas(ANPCanvas* canvas) -{ - if (!canvas) - return; - gfxContext *ctx = (gfxContext*)canvas; - NS_RELEASE( ctx ); -} - -void -anp_canvas_save(ANPCanvas* canvas) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - ctx->Save(); -} - -void -anp_canvas_restore(ANPCanvas* canvas) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - ctx->Restore(); -} - -void -anp_canvas_translate(ANPCanvas* canvas, float tx, float ty) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - ctx->Translate(gfxPoint(tx,ty)); -} - -void -anp_canvas_scale(ANPCanvas* canvas, float sx, float sy) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - ctx->Scale(sx, sy); -} - -void -anp_canvas_rotate(ANPCanvas* canvas, float degrees) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - ctx->Rotate(degrees); -} - -void -anp_canvas_skew(ANPCanvas* canvas, float kx, float ky) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -void -anp_canvas_concat(ANPCanvas* canvas, const ANPMatrix*) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -void -anp_canvas_clipRect(ANPCanvas* canvas, const ANPRectF* r) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - ctx->Clip(gfxRect(r->left, - r->top, - r->right - r->left, - r->bottom - r->top)); -} - -void -anp_canvas_clipPath(ANPCanvas* canvas, const ANPPath*) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -void -anp_canvas_getTotalMatrix(ANPCanvas* canvas, ANPMatrix*) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -bool -anp_canvas_getLocalClipBounds(ANPCanvas* canvas, ANPRectF* bounds, bool aa) -{ - if (!canvas) - return false; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); - return false; -} - -bool -anp_canvas_getDeviceClipBounds(ANPCanvas* canvas, ANPRectI* bounds) -{ - if (!canvas) - return false; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); - return false; -} - -void -anp_canvas_drawColor(ANPCanvas* canvas, ANPColor c) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - ctx->SetDeviceColor(gfxRGBA(c, gfxRGBA::PACKED_ARGB)); - LOG("returning from %s", __PRETTY_FUNCTION__); -} - -void -anp_canvas_drawPaint(ANPCanvas* canvas, const ANPPaint* paint) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s", " ************** NOT IMPLEMENTED!!!"); -} - -void -anp_canvas_drawLine(ANPCanvas* canvas, float x0, float y0, float x1, float y1, - const ANPPaint* paint) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - ctx->NewPath(); - ctx->SetColor(((ANPPaintPrivate*)paint)->color); - ctx->Line(gfxPoint(x0, y0), gfxPoint(x1, y1)); - ctx->Fill(); -} - -void -anp_canvas_drawRect(ANPCanvas* canvas, const ANPRectF* r, const ANPPaint* paint) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - - ctx->NewPath(); - ctx->SetColor(((ANPPaintPrivate*)paint)->color); - ctx->Rectangle(gfxRect(r->left, - r->top, - r->right - r->left, - r->bottom - r->top)); - ctx->Fill(); -} - -void -anp_canvas_drawOval(ANPCanvas* canvas, const ANPRectF* r, const ANPPaint* paint) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - - ctx->NewPath(); - ctx->SetColor(((ANPPaintPrivate*)paint)->color); - - float sizeX = (r->right - r->left); - float sizeY = (r->bottom - r->top); - - ctx->Ellipse(gfxPoint(r->left + ( sizeX / 2), r->top + ( sizeY / 2)), - gfxSize(sizeX, sizeY)); - ctx->Fill(); -} - -void -anp_canvas_drawPath(ANPCanvas* canvas, const ANPPath*, const ANPPaint* paint) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -void -anp_canvas_drawText(ANPCanvas* canvas, const void* text, uint32_t byteLength, - float x, float y, const ANPPaint* paint) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -void -anp_canvas_drawPosText(ANPCanvas* canvas, const void* text, uint32_t byteLength, - const float xy[], const ANPPaint* paint) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -void -anp_canvas_drawBitmap(ANPCanvas* canvas, const ANPBitmap*, float x, float y, - const ANPPaint* paint) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -void -anp_canvas_drawBitmapRect(ANPCanvas* canvas, const ANPBitmap*, - const ANPRectI* src, const ANPRectF* dst, - const ANPPaint* paint) -{ - if (!canvas) - return; - - gfxContext* ctx = (gfxContext*)canvas; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -void InitCanvasInterface(ANPCanvasInterfaceV0 *i) { - _assert(i->inSize == sizeof(*i)); - ASSIGN(i, newCanvas); - ASSIGN(i, deleteCanvas); - ASSIGN(i, save); - ASSIGN(i, restore); - ASSIGN(i, translate); - ASSIGN(i, scale); - ASSIGN(i, rotate); - ASSIGN(i, skew); - ASSIGN(i, concat); - ASSIGN(i, clipRect); - ASSIGN(i, clipPath); - ASSIGN(i, getTotalMatrix); - ASSIGN(i, getLocalClipBounds); - ASSIGN(i, getDeviceClipBounds); - ASSIGN(i, drawColor); - ASSIGN(i, drawPaint); - ASSIGN(i, drawLine); - ASSIGN(i, drawRect); - ASSIGN(i, drawOval); - ASSIGN(i, drawPath); - ASSIGN(i, drawText); - ASSIGN(i, drawPosText); - ASSIGN(i, drawBitmap); - ASSIGN(i, drawBitmapRect); -} diff --git a/dom/plugins/base/android/ANPPaint.cpp b/dom/plugins/base/android/ANPPaint.cpp deleted file mode 100644 index 9dc5d4c271b..00000000000 --- a/dom/plugins/base/android/ANPPaint.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** 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 Android NPAPI support code - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Doug Turner - * - * 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 ***** */ - -#include -#include -#include -#include "ANPBase.h" - -#define LOG(args...) -//__android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) -#define ASSIGN(obj, name) (obj)->name = anp_paint_##name - -ANPPaint* -anp_paint_newPaint() -{ - LOG("%s", __PRETTY_FUNCTION__); - - ANPPaintPrivate* p = (ANPPaintPrivate*) calloc(1, sizeof(ANPPaintPrivate)); - return (ANPPaint*) p; -} - -void -anp_paint_deletePaint(ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - free((void*)p); -} - - -ANPPaintFlags -anp_paint_getFlags(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return kAntiAlias_ANPPaintFlag; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->flags; -} - -void -anp_paint_setFlags(ANPPaint* paint, ANPPaintFlags flags) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->flags = flags; -} - - -ANPColor -anp_paint_getColor(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return ANP_MAKE_COLOR(1, 255, 255, 255); - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->color; -} - -void -anp_paint_setColor(ANPPaint* paint, ANPColor color) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->color = color; -} - - -ANPPaintStyle -anp_paint_getStyle(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return kFill_ANPPaintStyle; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->style; -} - -void -anp_paint_setStyle(ANPPaint* paint, ANPPaintStyle style) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->style = style; -} - -float -anp_paint_getStrokeWidth(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return 0; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->strokeWidth; -} - -float -anp_paint_getStrokeMiter(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return 0; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->strokeMiter; -} - -ANPPaintCap -anp_paint_getStrokeCap(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return kButt_ANPPaintCap; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->paintCap; -} - -ANPPaintJoin -anp_paint_getStrokeJoin(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return kMiter_ANPPaintJoin; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->paintJoin; -} - -void -anp_paint_setStrokeWidth(ANPPaint* paint, float width) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->strokeWidth = width; -} - -void -anp_paint_setStrokeMiter(ANPPaint* paint, float miter) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->strokeMiter = miter; -} - -void -anp_paint_setStrokeCap(ANPPaint* paint, ANPPaintCap cap) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->paintCap = cap; -} - -void -anp_paint_setStrokeJoin(ANPPaint* paint, ANPPaintJoin join) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->paintJoin = join; -} - - -ANPTextEncoding -anp_paint_getTextEncoding(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return kUTF8_ANPTextEncoding; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->textEncoding; -} - -ANPPaintAlign -anp_paint_getTextAlign(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return kLeft_ANPPaintAlign; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->paintAlign; -} - -float -anp_paint_getTextSize(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return 0; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->textSize; -} - -float -anp_paint_getTextScaleX(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return 0; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->textScaleX; -} - -float -anp_paint_getTextSkewX(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return 0; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return p->textSkewX; -} - -void -anp_paint_setTextEncoding(ANPPaint* paint, ANPTextEncoding encoding) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->textEncoding = encoding; -} - -void -anp_paint_setTextAlign(ANPPaint* paint, ANPPaintAlign align) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->paintAlign = align; -} - -void -anp_paint_setTextSize(ANPPaint* paint, float size) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->textSize = size; -} - -void -anp_paint_setTextScaleX(ANPPaint* paint, float scale) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->textScaleX = scale; -} - -void -anp_paint_setTextSkewX(ANPPaint* paint, float skew) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - p->textSkewX = skew; -} - - -/** Return the typeface in paint, or null if there is none. This does not - modify the owner count of the returned typeface. -*/ -ANPTypeface* -anp_paint_getTypeface(const ANPPaint* paint) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return NULL; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - return &p->typeface; -} - - -/** Set the paint's typeface. If the paint already had a non-null typeface, - its owner count is decremented. If the new typeface is non-null, its - owner count is incremented. -*/ -void -anp_paint_setTypeface(ANPPaint* paint, ANPTypeface* typeface) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - LOG("%s is not impl.", __PRETTY_FUNCTION__); -} - -/** Return the width of the text. If bounds is not null, return the bounds - of the text in that rectangle. -*/ -float -anp_paint_measureText(ANPPaint* paint, const void* text, uint32_t byteLength, - ANPRectF* bounds) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return 0; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - - LOG("%s is not impl.", __PRETTY_FUNCTION__); - return 0; -} - - -/** Return the number of unichars specifed by the text. - If widths is not null, returns the array of advance widths for each - unichar. - If bounds is not null, returns the array of bounds for each unichar. -*/ -int -anp_paint_getTextWidths(ANPPaint* paint, const void* text, uint32_t byteLength, - float widths[], ANPRectF bounds[]) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return 0; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - LOG("%s is not impl.", __PRETTY_FUNCTION__); - return 0; -} - - -/** Return in metrics the spacing values for text, respecting the paint's - typeface and pointsize, and return the spacing between lines - (descent - ascent + leading). If metrics is NULL, it will be ignored. -*/ -float -anp_paint_getFontMetrics(ANPPaint* paint, ANPFontMetrics* metrics) -{ - LOG("%s", __PRETTY_FUNCTION__); - if (!paint) - return 0; - - ANPPaintPrivate* p = (ANPPaintPrivate*) paint; - LOG("%s is not impl.", __PRETTY_FUNCTION__); - return 0; -} - - -void InitPaintInterface(ANPPaintInterfaceV0 *i) { - _assert(i->inSize == sizeof(*i)); - ASSIGN(i, newPaint); - ASSIGN(i, deletePaint); - ASSIGN(i, getFlags); - ASSIGN(i, setFlags); - ASSIGN(i, getColor); - ASSIGN(i, setColor); - ASSIGN(i, getStyle); - ASSIGN(i, setStyle); - ASSIGN(i, getStrokeWidth); - ASSIGN(i, getStrokeMiter); - ASSIGN(i, getStrokeCap); - ASSIGN(i, getStrokeJoin); - ASSIGN(i, setStrokeWidth); - ASSIGN(i, setStrokeMiter); - ASSIGN(i, setStrokeCap); - ASSIGN(i, setStrokeJoin); - ASSIGN(i, getTextEncoding); - ASSIGN(i, getTextAlign); - ASSIGN(i, getTextSize); - ASSIGN(i, getTextScaleX); - ASSIGN(i, getTextSkewX); - ASSIGN(i, setTextEncoding); - ASSIGN(i, setTextAlign); - ASSIGN(i, setTextSize); - ASSIGN(i, setTextScaleX); - ASSIGN(i, setTextSkewX); - ASSIGN(i, getTypeface); - ASSIGN(i, setTypeface); - ASSIGN(i, measureText); - ASSIGN(i, getTextWidths); - ASSIGN(i, getFontMetrics); -} diff --git a/dom/plugins/base/android/ANPPath.cpp b/dom/plugins/base/android/ANPPath.cpp deleted file mode 100644 index ca1dbe9d48d..00000000000 --- a/dom/plugins/base/android/ANPPath.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** 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 Android NPAPI support code - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Doug Turner - * - * 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 ***** */ - -#include "assert.h" -#include "ANPBase.h" -#include - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) -#define ASSIGN(obj, name) (obj)->name = anp_path_##name - - -// maybe this should store a list of actions (lineTo, -// moveTo), and when canvas_drawPath() we apply all of these -// actions to the gfxContext. - -ANPPath* -anp_path_newPath() -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); - return 0; -} - - -void -anp_path_deletePath(ANPPath* p) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - - -void -anp_path_copy(ANPPath* dst, const ANPPath* src) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - - -bool -anp_path_equal(const ANPPath* path0, const ANPPath* path1) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); - return false; -} - - -void -anp_path_reset(ANPPath* p) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - - -bool -anp_path_isEmpty(const ANPPath* p) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); - return false; -} - - -void -anp_path_getBounds(const ANPPath* p, ANPRectF* bounds) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); - - bounds->left = 0; - bounds->top = 0; - bounds->right = 1000; - bounds->left = 1000; -} - - -void -anp_path_moveTo(ANPPath* p, float x, float y) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - -void -anp_path_lineTo(ANPPath* p, float x, float y) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - -void -anp_path_quadTo(ANPPath* p, float x0, float y0, float x1, float y1) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - -void -anp_path_cubicTo(ANPPath* p, float x0, float y0, float x1, float y1, - float x2, float y2) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - -void -anp_path_close(ANPPath* p) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - - -void -anp_path_offset(ANPPath* src, float dx, float dy, ANPPath* dst) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - - -void -anp_path_transform(ANPPath* src, const ANPMatrix*, ANPPath* dst) -{ - LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__); -} - - - -void InitPathInterface(ANPPathInterfaceV0 *i) { - _assert(i->inSize == sizeof(*i)); - ASSIGN(i, newPath); - ASSIGN(i, deletePath); - ASSIGN(i, copy); - ASSIGN(i, equal); - ASSIGN(i, reset); - ASSIGN(i, isEmpty); - ASSIGN(i, getBounds); - ASSIGN(i, moveTo); - ASSIGN(i, lineTo); - ASSIGN(i, quadTo); - ASSIGN(i, cubicTo); - ASSIGN(i, close); - ASSIGN(i, offset); - ASSIGN(i, transform); -} diff --git a/dom/plugins/base/android/ANPSurface.cpp b/dom/plugins/base/android/ANPSurface.cpp index 54f327d63d1..de93834e9b9 100644 --- a/dom/plugins/base/android/ANPSurface.cpp +++ b/dom/plugins/base/android/ANPSurface.cpp @@ -36,151 +36,256 @@ * * ***** END LICENSE BLOCK ***** */ -#include "assert.h" -#include "ANPBase.h" +#include #include -#include "AndroidBridge.h" -#include "gfxImageSurface.h" -#include "gfxContext.h" -#include "nsNPAPIPluginInstance.h" +#include "ANPBase.h" #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #define ASSIGN(obj, name) (obj)->name = anp_surface_##name +#define CLEAR_EXCEPTION(env) if (env->ExceptionOccurred()) env->ExceptionClear(); + +#define ANDROID_REGION_SIZE 512 + +// Copied from Android headers +enum { + PIXEL_FORMAT_RGBA_8888 = 1, + PIXEL_FORMAT_RGB_565 = 4, +}; + +struct SurfaceInfo { + uint32_t w; + uint32_t h; + uint32_t s; + uint32_t usage; + uint32_t format; + unsigned char* bits; + uint32_t reserved[2]; +}; + +typedef struct ARect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} ARect; + // used to cache JNI method and field IDs for Surface Objects static struct ANPSurfaceInterfaceJavaGlue { - bool initialized; - jclass geckoAppShellClass; - jclass surfaceInfoCls; - jmethodID getSurfaceInfo; - jfieldID jFormat; - jfieldID jWidth ; - jfieldID jHeight; + bool initialized; + jmethodID getSurfaceHolder; + jmethodID getSurface; + jfieldID surfacePointer; } gSurfaceJavaGlue; -#define getClassGlobalRef(env, cname) \ - (jClass = jclass(env->NewGlobalRef(env->FindClass(cname)))) +static struct ANPSurfaceFunctions { + bool initialized; -static void init(JNIEnv* env) { - if (gSurfaceJavaGlue.initialized) - return; - - gSurfaceJavaGlue.geckoAppShellClass = mozilla::AndroidBridge::GetGeckoAppShellClass(); - - jmethodID getClass = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, - "getSurfaceInfoClass", - "()Ljava/lang/Class;"); + int (* lock)(void*, SurfaceInfo*, void*); + int (* unlockAndPost)(void*); - gSurfaceJavaGlue.surfaceInfoCls = (jclass) env->NewGlobalRef(env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, getClass)); + void* (* regionConstructor)(void*); + void (* setRegion)(void*, ARect const&); +} gSurfaceFunctions; - gSurfaceJavaGlue.jFormat = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "format", "I"); - gSurfaceJavaGlue.jWidth = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "width", "I"); - gSurfaceJavaGlue.jHeight = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "height", "I"); - gSurfaceJavaGlue.getSurfaceInfo = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "getSurfaceInfo", "(Landroid/view/SurfaceView;)Lorg/mozilla/gecko/SurfaceInfo;"); - gSurfaceJavaGlue.initialized = true; +static inline void* getSurface(JNIEnv* env, jobject view) { + if (!env || !view) { + return NULL; + } + + if (!gSurfaceJavaGlue.initialized) { + + jclass surfaceViewClass = env->FindClass("android/view/SurfaceView"); + gSurfaceJavaGlue.getSurfaceHolder = env->GetMethodID(surfaceViewClass, "getHolder", "()Landroid/view/SurfaceHolder;"); + + jclass surfaceHolderClass = env->FindClass("android/view/SurfaceHolder"); + gSurfaceJavaGlue.getSurface = env->GetMethodID(surfaceHolderClass, "getSurface", "()Landroid/view/Surface;"); + + jclass surfaceClass = env->FindClass("android/view/Surface"); + gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass, + "mSurfacePointer", "I"); + + if (!gSurfaceJavaGlue.surfacePointer) { + CLEAR_EXCEPTION(env); + + // It was something else in 2.2. + gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass, + "mSurface", "I"); + + if (!gSurfaceJavaGlue.surfacePointer) { + CLEAR_EXCEPTION(env); + + // And something else in 2.3+ + gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass, + "mNativeSurface", "I"); + + CLEAR_EXCEPTION(env); + } + } + + if (!gSurfaceJavaGlue.surfacePointer) { + LOG("Failed to acquire surface pointer"); + return NULL; + } + + env->DeleteLocalRef(surfaceClass); + env->DeleteLocalRef(surfaceViewClass); + env->DeleteLocalRef(surfaceHolderClass); + + gSurfaceJavaGlue.initialized = (gSurfaceJavaGlue.surfacePointer != NULL); + } + + jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder); + jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface); + jint surfacePointer = env->GetIntField(surface, gSurfaceJavaGlue.surfacePointer); + + env->DeleteLocalRef(holder); + env->DeleteLocalRef(surface); + + return (void*)surfacePointer; } -static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) { - LOG("%s", __PRETTY_FUNCTION__); +static ANPBitmapFormat convertPixelFormat(int32_t format) { + switch (format) { + case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_ANPBitmapFormat; + case PIXEL_FORMAT_RGB_565: return kRGB_565_ANPBitmapFormat; + default: return kUnknown_ANPBitmapFormat; + } +} + +static int bytesPerPixel(int32_t format) { + switch (format) { + case PIXEL_FORMAT_RGBA_8888: return 4; + case PIXEL_FORMAT_RGB_565: return 2; + default: return -1; + } +} + +static bool init() { + if (gSurfaceFunctions.initialized) + return true; + + void* handle = dlopen("/system/lib/libsurfaceflinger_client.so", RTLD_LAZY); + + if (!handle) { + LOG("Failed to open libsurfaceflinger_client.so"); + return false; + } + + gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb"); + gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv"); + + handle = dlopen("/system/lib/libui.so", RTLD_LAZY); + if (!handle) { + LOG("Failed to open libui.so"); + return false; + } + + gSurfaceFunctions.regionConstructor = (void* (*)(void*))dlsym(handle, "_ZN7android6RegionC1Ev"); + gSurfaceFunctions.setRegion = (void (*)(void*, ARect const&))dlsym(handle, "_ZN7android6Region3setERKNS_4RectE"); + + gSurfaceFunctions.initialized = (gSurfaceFunctions.lock && gSurfaceFunctions.unlockAndPost && + gSurfaceFunctions.regionConstructor && gSurfaceFunctions.setRegion); + LOG("Initialized? %d\n", gSurfaceFunctions.initialized); + return gSurfaceFunctions.initialized; +} + +static bool anp_surface_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) { if (!bitmap || !surfaceView) { - LOG("%s, null bitmap or surface, exiting", __PRETTY_FUNCTION__); return false; } - init(env); + void* surface = getSurface(env, surfaceView); - jobject info = env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, - gSurfaceJavaGlue.getSurfaceInfo, surfaceView); - - LOG("info: %p", info); - if (!info) - return false; - - bitmap->width = env->GetIntField(info, gSurfaceJavaGlue.jWidth); - bitmap->height = env->GetIntField(info, gSurfaceJavaGlue.jHeight); - - if (bitmap->width <= 0 || bitmap->height <= 0) - return false; - - int format = env->GetIntField(info, gSurfaceJavaGlue.jFormat); - gfxImageFormat targetFormat; - - // format is PixelFormat - if (format & 0x00000001) { - /* - bitmap->format = kRGBA_8888_ANPBitmapFormat; - bitmap->rowBytes = bitmap->width * 4; - targetFormat = gfxASurface::ImageFormatARGB32; - */ - - // We actually can't handle this right now because gfxImageSurface - // doesn't support RGBA32. - LOG("Unable to handle 32bit pixel format"); - return false; - } else if (format & 0x00000004) { - bitmap->format = kRGB_565_ANPBitmapFormat; - bitmap->rowBytes = bitmap->width * 2; - targetFormat = gfxASurface::ImageFormatRGB16_565; - } else { - LOG("format from glue is unknown %d\n", format); + if (!bitmap || !surface) { return false; } - nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::FindByJavaSurface((void*)surfaceView); - if (!pinst) { - LOG("Failed to get plugin instance"); + if (!init()) { return false; } - NPRect lockRect; + void* region = NULL; if (dirtyRect) { - lockRect.top = dirtyRect->top; - lockRect.left = dirtyRect->left; - lockRect.right = dirtyRect->right; - lockRect.bottom = dirtyRect->bottom; - } else { - // No dirty rect, use the whole bitmap - lockRect.top = lockRect.left = 0; - lockRect.right = bitmap->width; - lockRect.bottom = bitmap->height; - } - - gfxImageSurface* target = pinst->LockTargetSurface(bitmap->width, bitmap->height, targetFormat, &lockRect); - bitmap->baseAddr = target->Data(); + region = malloc(ANDROID_REGION_SIZE); + gSurfaceFunctions.regionConstructor(region); - env->DeleteLocalRef(info); + ARect rect; + rect.left = dirtyRect->left; + rect.top = dirtyRect->top; + rect.right = dirtyRect->right; + rect.bottom = dirtyRect->bottom; + + gSurfaceFunctions.setRegion(region, rect); + } + + SurfaceInfo info; + int err = gSurfaceFunctions.lock(surface, &info, region); + if (err < 0) { + LOG("Failed to lock surface"); + return false; + } + + // the surface may have expanded the dirty region so we must to pass that + // information back to the plugin. + if (dirtyRect) { + ARect* dirtyBounds = (ARect*)region; // The bounds are the first member, so this should work! + + dirtyRect->left = dirtyBounds->left; + dirtyRect->right = dirtyBounds->right; + dirtyRect->top = dirtyBounds->top; + dirtyRect->bottom = dirtyBounds->bottom; + } + + if (region) + free(region); + + int bpr = info.s * bytesPerPixel(info.format); + + bitmap->format = convertPixelFormat(info.format); + bitmap->width = info.w; + bitmap->height = info.h; + bitmap->rowBytes = bpr; + + if (info.w > 0 && info.h > 0) { + bitmap->baseAddr = info.bits; + } else { + bitmap->baseAddr = NULL; + return false; + } return true; } -static void anp_unlock(JNIEnv* env, jobject surfaceView) { - LOG("%s", __PRETTY_FUNCTION__); - +static void anp_surface_unlock(JNIEnv* env, jobject surfaceView) { if (!surfaceView) { - LOG("null surface, exiting %s", __PRETTY_FUNCTION__); return; } - nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::FindByJavaSurface((void*)surfaceView); - if (!pinst) { - LOG("Could not find plugin instance!"); + if (!init()) { return; } - - pinst->UnlockTargetSurface(true /* invalidate the locked area */); + + void* surface = getSurface(env, surfaceView); + + if (!surface) { + return; + } + + gSurfaceFunctions.unlockAndPost(surface); } /////////////////////////////////////////////////////////////////////////////// -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void InitSurfaceInterface(ANPSurfaceInterfaceV0 *i) { - +void InitSurfaceInterface(ANPSurfaceInterfaceV0* i) { ASSIGN(i, lock); ASSIGN(i, unlock); // setup the java glue struct gSurfaceJavaGlue.initialized = false; + + // setup the function struct + gSurfaceFunctions.initialized = false; } diff --git a/dom/plugins/base/android/ANPSystem.cpp b/dom/plugins/base/android/ANPSystem.cpp index 70085217328..830eb00845b 100644 --- a/dom/plugins/base/android/ANPSystem.cpp +++ b/dom/plugins/base/android/ANPSystem.cpp @@ -52,8 +52,14 @@ const char* anp_system_getApplicationDataDirectory() { - LOG("getApplicationDataDirectory return /data/data/org.mozilla.%s", MOZ_APP_NAME); - return "/data/data/org.mozilla." MOZ_APP_NAME; + static char *dir = NULL; + + if (!dir) { + dir = getenv("ANDROID_PLUGIN_DATADIR"); + } + + LOG("getApplicationDataDirectory return %s", dir); + return dir; } jclass anp_system_loadJavaClass(NPP instance, const char* className) diff --git a/dom/plugins/base/android/ANPTypeface.cpp b/dom/plugins/base/android/ANPTypeface.cpp deleted file mode 100644 index 15ed094d244..00000000000 --- a/dom/plugins/base/android/ANPTypeface.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** 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 Android NPAPI support code - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Doug Turner - * - * 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 ***** */ - -#include "assert.h" -#include "ANPBase.h" -#include -#include "gfxAndroidPlatform.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) -#define ASSIGN(obj, name) (obj)->name = anp_typeface_##name - -ANPTypeface* -anp_typeface_createFromName(const char name[], ANPTypefaceStyle aStyle) -{ - LOG("%s - %s\n", __PRETTY_FUNCTION__, name); - - gfxFontStyle style (aStyle == kItalic_ANPTypefaceStyle ? FONT_STYLE_ITALIC : - FONT_STYLE_NORMAL, - NS_FONT_STRETCH_NORMAL, - aStyle == kBold_ANPTypefaceStyle ? 700 : 400, - 16.0, - NS_NewPermanentAtom(NS_LITERAL_STRING("en")), - 0.0, - false, false, - NS_LITERAL_STRING(""), - NS_LITERAL_STRING("")); - ANPTypeface* tf = new ANPTypeface; - gfxAndroidPlatform * p = (gfxAndroidPlatform*)gfxPlatform::GetPlatform(); - nsRefPtr font = gfxFT2Font::GetOrMakeFont(NS_ConvertASCIItoUTF16(name), &style); - font.forget(&tf->mFont); - if (tf->mFont) { - ++tf->mRefCnt; - } - return tf; -} - -ANPTypeface* -anp_typeface_createFromTypeface(const ANPTypeface* family, - ANPTypefaceStyle) -{ - NOT_IMPLEMENTED(); - return 0; -} - -int32_t -anp_typeface_getRefCount(const ANPTypeface*) -{ - NOT_IMPLEMENTED(); - return 0; -} - -void -anp_typeface_ref(ANPTypeface* tf) -{ - LOG("%s\n", __PRETTY_FUNCTION__); - if (tf->mFont) - ++tf->mRefCnt; - -} - -void -anp_typeface_unref(ANPTypeface* tf) -{ - LOG("%s\n", __PRETTY_FUNCTION__); - if (tf->mFont) - --tf->mRefCnt; - if (tf->mRefCnt.get() == 0) { - NS_IF_RELEASE(tf->mFont); - } -} - -ANPTypefaceStyle -anp_typeface_getStyle(const ANPTypeface* ft) -{ - LOG("%s\n", __PRETTY_FUNCTION__); - return kBold_ANPTypefaceStyle; -} - -int32_t -anp_typeface_getFontPath(const ANPTypeface*, char path[], int32_t length, - int32_t* index) -{ - NOT_IMPLEMENTED(); - return 0; -} - -static const char* gFontDir; -#define FONT_DIR_SUFFIX "/fonts/" - -const char* -anp_typeface_getFontDirectoryPath() -{ - LOG("%s\n", __PRETTY_FUNCTION__); - if (NULL == gFontDir) { - const char* root = getenv("ANDROID_ROOT"); - size_t len = strlen(root); - char* storage = (char*)malloc(len + sizeof(FONT_DIR_SUFFIX)); - if (NULL == storage) { - return NULL; - } - memcpy(storage, root, len); - memcpy(storage + len, FONT_DIR_SUFFIX, sizeof(FONT_DIR_SUFFIX)); - // save this assignment for last, so that if multiple threads call us - // (which should never happen), we never return an incomplete global. - // At worst, we would allocate storage for the path twice. - gFontDir = storage; - } - - return 0; -} - -void InitTypeFaceInterface(ANPTypefaceInterfaceV0 *i) { - _assert(i->inSize == sizeof(*i)); - ASSIGN(i, createFromName); - ASSIGN(i, createFromTypeface); - ASSIGN(i, getRefCount); - ASSIGN(i, ref); - ASSIGN(i, unref); - ASSIGN(i, getStyle); - ASSIGN(i, getFontPath); - ASSIGN(i, getFontDirectoryPath); -} - diff --git a/dom/plugins/base/android/Makefile.in b/dom/plugins/base/android/Makefile.in index 42e5067f3ae..1b987e428de 100644 --- a/dom/plugins/base/android/Makefile.in +++ b/dom/plugins/base/android/Makefile.in @@ -57,21 +57,18 @@ EXPORTS = \ $(NULL) CPPSRCS += ANPAudio.cpp \ - ANPCanvas.cpp \ ANPEvent.cpp \ ANPMatrix.cpp \ - ANPPath.cpp \ ANPSystem.cpp \ ANPWindow.cpp \ ANPBitmap.cpp \ ANPLog.cpp \ - ANPPaint.cpp \ ANPSurface.cpp \ - ANPTypeface.cpp \ $(NULL) LOCAL_INCLUDES += \ -I$(topsrcdir)/dom/plugins/base \ + -I$(topsrcdir)/dom/plugins/base/android/include \ $(MOZ_CAIRO_CFLAGS) \ $(NULL) diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 7aa883ef304..d78dfbaa06c 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -65,6 +65,7 @@ #include "ANPBase.h" #include #include "android_npapi.h" +#include "mozilla/Mutex.h" #include "mozilla/CondVar.h" #include "AndroidBridge.h" #endif @@ -72,11 +73,6 @@ using namespace mozilla; using namespace mozilla::plugins::parent; -#ifdef MOZ_WIDGET_ANDROID -#include -static std::map sSurfaceMap; -#endif - static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID); static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID); @@ -93,7 +89,6 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin) #endif #ifdef MOZ_WIDGET_ANDROID mSurface(nsnull), - mTargetSurface(nsnull), mDrawingModel(0), #endif mRunning(NOT_STARTED), @@ -128,10 +123,6 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin) mUsePluginLayersPref = useLayersPref; } -#ifdef MOZ_WIDGET_ANDROID - mTargetSurfaceLock = new Mutex("nsNPAPIPluginInstance::SurfaceLock"); -#endif - PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this)); } @@ -143,22 +134,6 @@ nsNPAPIPluginInstance::~nsNPAPIPluginInstance() PR_Free((void *)mMIMEType); mMIMEType = nsnull; } - -#ifdef MOZ_WIDGET_ANDROID - if (mSurface) { - sSurfaceMap.erase(mSurface); - } - - if (mTargetSurface) { - delete mTargetSurface; - mTargetSurface = nsnull; - } - - if (mTargetSurfaceLock) { - delete mTargetSurfaceLock; - mTargetSurfaceLock = nsnull; - } -#endif } void @@ -760,40 +735,25 @@ void nsNPAPIPluginInstance::SetDrawingModel(PRUint32 aModel) { mDrawingModel = aModel; } - class SurfaceGetter : public nsRunnable { public: - SurfaceGetter(NPPluginFuncs* aPluginFunctions, NPP_t aNPP) : - mHaveSurface(false), mPluginFunctions(aPluginFunctions), mNPP(aNPP) { - mLock = new Mutex("SurfaceGetter::Lock"); - mCondVar = new CondVar(*mLock, "SurfaceGetter::CondVar"); - + SurfaceGetter(nsNPAPIPluginInstance* aInstance, NPPluginFuncs* aPluginFunctions, NPP_t aNPP) : + mInstance(aInstance), mPluginFunctions(aPluginFunctions), mNPP(aNPP) { } ~SurfaceGetter() { - delete mLock; - delete mCondVar; } nsresult Run() { - MutexAutoLock lock(*mLock); - (*mPluginFunctions->getvalue)(&mNPP, kJavaSurface_ANPGetValue, &mSurface); - mHaveSurface = true; - mCondVar->Notify(); + void* surface; + (*mPluginFunctions->getvalue)(&mNPP, kJavaSurface_ANPGetValue, &surface); + mInstance->SetJavaSurface(surface); return NS_OK; } - void* GetSurface() { - MutexAutoLock lock(*mLock); - mHaveSurface = false; - AndroidBridge::Bridge()->PostToJavaThread(this); - while (!mHaveSurface) - mCondVar->Wait(); - return mSurface; + void RequestSurface() { + mozilla::AndroidBridge::Bridge()->PostToJavaThread(this); } private: + nsNPAPIPluginInstance* mInstance; NPP_t mNPP; - void* mSurface; - Mutex* mLock; - CondVar* mCondVar; - bool mHaveSurface; NPPluginFuncs* mPluginFunctions; }; @@ -803,64 +763,22 @@ void* nsNPAPIPluginInstance::GetJavaSurface() if (mDrawingModel != kSurface_ANPDrawingModel) return nsnull; - if (mSurface) - return mSurface; - - nsCOMPtr sg = new SurfaceGetter(mPlugin->PluginFuncs(), mNPP); - mSurface = sg->GetSurface(); - sSurfaceMap[mSurface] = this; return mSurface; } -gfxImageSurface* -nsNPAPIPluginInstance::LockTargetSurface() +void nsNPAPIPluginInstance::SetJavaSurface(void* aSurface) { - mTargetSurfaceLock->Lock(); - return mTargetSurface; + mSurface = aSurface; } -gfxImageSurface* -nsNPAPIPluginInstance::LockTargetSurface(PRUint32 aWidth, PRUint32 aHeight, gfxImageFormat aFormat, - NPRect* aRect) +void nsNPAPIPluginInstance::RequestJavaSurface() { - mTargetSurfaceLock->Lock(); - if (!mTargetSurface || - mTargetSurface->Width() != aWidth || - mTargetSurface->Height() != aHeight || - mTargetSurface->Format() != aFormat) { + if (mSurfaceGetter.get()) + return; - if (mTargetSurface) { - delete mTargetSurface; - } + mSurfaceGetter = new SurfaceGetter(this, mPlugin->PluginFuncs(), mNPP); - mTargetSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight), aFormat); - } - - mTargetLockRect = *aRect; - - return mTargetSurface; -} - -void -nsNPAPIPluginInstance::InvalidateTargetRect() -{ - InvalidateRect(&mTargetLockRect); -} - -void -nsNPAPIPluginInstance::UnlockTargetSurface(bool aInvalidate) -{ - mTargetSurfaceLock->Unlock(); - - if (aInvalidate) { - NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::InvalidateTargetRect)); - } -} - -nsNPAPIPluginInstance* -nsNPAPIPluginInstance::FindByJavaSurface(void* aJavaSurface) -{ - return sSurfaceMap[aJavaSurface]; + ((SurfaceGetter*)mSurfaceGetter.get())->RequestSurface(); } #endif diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h index 886090bc06a..e171b689a5b 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.h +++ b/dom/plugins/base/nsNPAPIPluginInstance.h @@ -49,17 +49,13 @@ #include "nsIChannel.h" #include "nsInterfaceHashtable.h" #include "nsHashKeys.h" - -#include "gfxASurface.h" -#include "gfxImageSurface.h" +#ifdef MOZ_WIDGET_ANDROID +#include "nsIRunnable.h" +#endif #include "mozilla/TimeStamp.h" #include "mozilla/PluginLibrary.h" -#ifdef ANDROID -#include "mozilla/Mutex.h" -#endif - struct JSObject; class nsPluginStreamListenerPeer; // browser-initiated stream class @@ -156,13 +152,8 @@ public: #ifdef MOZ_WIDGET_ANDROID void SetDrawingModel(PRUint32 aModel); void* GetJavaSurface(); - - gfxImageSurface* LockTargetSurface(); - gfxImageSurface* LockTargetSurface(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat, - NPRect* aRect); - void UnlockTargetSurface(bool aInvalidate); - - static nsNPAPIPluginInstance* FindByJavaSurface(void* aJavaSurface); + void SetJavaSurface(void* aSurface); + void RequestJavaSurface(); #endif nsresult NewStreamListener(const char* aURL, void* notifyData, @@ -239,6 +230,7 @@ protected: #ifdef MOZ_WIDGET_ANDROID PRUint32 mDrawingModel; + nsCOMPtr mSurfaceGetter; #endif enum { @@ -290,12 +282,7 @@ private: bool mUsePluginLayersPref; #ifdef MOZ_WIDGET_ANDROID - void InvalidateTargetRect(); - void* mSurface; - gfxImageSurface *mTargetSurface; - mozilla::Mutex* mTargetSurfaceLock; - NPRect mTargetLockRect; #endif }; diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 0ddfeae7801..d5198e4cac4 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -331,6 +331,11 @@ nsPluginInstanceOwner::nsPluginInstanceOwner() #endif mWaitingForPaint = false; + +#ifdef MOZ_WIDGET_ANDROID + mPluginViewAdded = false; + mLastPluginRect = gfxRect(0, 0, 0, 0); +#endif } nsPluginInstanceOwner::~nsPluginInstanceOwner() @@ -1673,18 +1678,27 @@ void nsPluginInstanceOwner::ScrollPositionDidChange(nscoord aX, nscoord aY) } #ifdef MOZ_WIDGET_ANDROID -void nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect) +bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect) { - void* javaSurface = mInstance->GetJavaSurface(); + AndroidBridge::AutoLocalJNIFrame frame(1); - if (!javaSurface) - return; + void* javaSurface = mInstance->GetJavaSurface(); + if (!javaSurface) { + mInstance->RequestJavaSurface(); + return false; + } + + if (aRect.IsEqualEdges(mLastPluginRect)) { + // Already added and in position, no work to do + return true; + } JNIEnv* env = GetJNIForThread(); jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell"); jmethodID method = env->GetStaticMethodID(cls, "addPluginView", "(Landroid/view/View;DDDD)V"); + env->CallStaticVoidMethod(cls, method, javaSurface, @@ -1692,11 +1706,27 @@ void nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect) aRect.y, aRect.width, aRect.height); + + if (!mPluginViewAdded) { + ANPEvent event; + event.inSize = sizeof(ANPEvent); + event.eventType = kLifecycle_ANPEventType; + event.data.lifecycle.action = kOnScreen_ANPLifecycleAction; + mInstance->HandleEvent(&event, nsnull); + + mPluginViewAdded = true; + } + + return true; } void nsPluginInstanceOwner::RemovePluginView() { - if (mInstance && mObjectFrame) { + AndroidBridge::AutoLocalJNIFrame frame(1); + + if (mInstance && mObjectFrame && mPluginViewAdded) { + mPluginViewAdded = false; + void* surface = mInstance->GetJavaSurface(); if (surface) { JNIEnv* env = GetJNIForThread(); @@ -1706,6 +1736,14 @@ void nsPluginInstanceOwner::RemovePluginView() "removePluginView", "(Landroid/view/View;)V"); env->CallStaticVoidMethod(cls, method, surface); + + { + ANPEvent event; + event.inSize = sizeof(ANPEvent); + event.eventType = kLifecycle_ANPEventType; + event.data.lifecycle.action = kOffScreen_ANPLifecycleAction; + mInstance->HandleEvent(&event, nsnull); + } } } } @@ -2846,20 +2884,13 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext, mInstance->GetDrawingModel(&model); if (model == kSurface_ANPDrawingModel) { - AddPluginView(aFrameRect); - - gfxImageSurface* pluginSurface = mInstance->LockTargetSurface(); - if (!pluginSurface) { - mInstance->UnlockTargetSurface(false); - return; + if (!AddPluginView(aFrameRect)) { + NPRect rect; + rect.left = rect.top = 0; + rect.right = aFrameRect.width; + rect.bottom = aFrameRect.height; + InvalidateRect(&rect); } - - aContext->SetOperator(gfxContext::OPERATOR_SOURCE); - aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y)); - aContext->Clip(aDirtyRect); - aContext->Paint(); - - mInstance->UnlockTargetSurface(false); return; } @@ -3556,26 +3587,10 @@ void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow) if (mPluginWindowVisible && mPluginDocumentActiveState) { mPluginWindow->clipRect.right = mPluginWindow->width; mPluginWindow->clipRect.bottom = mPluginWindow->height; -#ifdef MOZ_WIDGET_ANDROID - if (mInstance) { - ANPEvent event; - event.inSize = sizeof(ANPEvent); - event.eventType = kLifecycle_ANPEventType; - event.data.lifecycle.action = kOnScreen_ANPLifecycleAction; - mInstance->HandleEvent(&event, nsnull); - } -#endif } else { mPluginWindow->clipRect.right = 0; mPluginWindow->clipRect.bottom = 0; #ifdef MOZ_WIDGET_ANDROID - if (mInstance) { - ANPEvent event; - event.inSize = sizeof(ANPEvent); - event.eventType = kLifecycle_ANPEventType; - event.data.lifecycle.action = kOffScreen_ANPLifecycleAction; - mInstance->HandleEvent(&event, nsnull); - } RemovePluginView(); #endif } diff --git a/dom/plugins/base/nsPluginInstanceOwner.h b/dom/plugins/base/nsPluginInstanceOwner.h index 6cef6123284..a6acb483f74 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.h +++ b/dom/plugins/base/nsPluginInstanceOwner.h @@ -310,8 +310,10 @@ private: void FixUpURLS(const nsString &name, nsAString &value); #ifdef ANDROID - void AddPluginView(const gfxRect& aRect); + bool AddPluginView(const gfxRect& aRect); void RemovePluginView(); + bool mPluginViewAdded; + gfxRect mLastPluginRect; #endif nsPluginNativeWindow *mPluginWindow; diff --git a/editor/libeditor/base/Makefile.in b/editor/libeditor/base/Makefile.in index 66b7463345a..01f4108f31a 100644 --- a/editor/libeditor/base/Makefile.in +++ b/editor/libeditor/base/Makefile.in @@ -46,6 +46,10 @@ ifdef ENABLE_TESTS DIRS += tests endif +ifdef MOZ_SPELLCHECK +DEFINES += -DMOZ_SPELLCHECK +endif + MODULE = editor LIBRARY_NAME = editorbase_s LIBXUL_LIBRARY = 1 diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 068169ab85f..bbe340890f8 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -50,9 +50,13 @@ #include "nsReadableUtils.h" #include "nsIObserverService.h" #include "mozilla/Services.h" + +#ifdef MOZ_SPELLCHECK #include "mozISpellCheckingEngine.h" #include "nsIEditorSpellCheck.h" #include "mozInlineSpellChecker.h" +#include "nsIInlineSpellChecker.h" +#endif #include "nsIDOMText.h" #include "nsIDOMElement.h" @@ -107,7 +111,6 @@ #include "nsEditorUtils.h" #include "nsEditorEventListener.h" #include "nsISelectionDisplay.h" -#include "nsIInlineSpellChecker.h" #include "nsINameSpaceManager.h" #include "nsIHTMLDocument.h" #include "nsIParserService.h" @@ -309,12 +312,14 @@ nsEditor::PostCreate() NotifyDocumentListeners(eDocumentCreated); NotifyDocumentListeners(eDocumentStateChanged); +#ifdef MOZ_SPELLCHECK nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { obs->AddObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, false); } +#endif } // update nsTextStateManager and caret if we have focus @@ -427,11 +432,13 @@ nsEditor::PreDestroy(bool aDestroyingFrames) if (mDidPreDestroy) return NS_OK; +#ifdef MOZ_SPELLCHECK nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { obs->RemoveObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION); } +#endif // Let spellchecker clean up its observers etc. It is important not to // actually free the spellchecker here, since the spellchecker could have @@ -1294,6 +1301,7 @@ nsEditor::MarkNodeDirty(nsIDOMNode* aNode) NS_IMETHODIMP nsEditor::GetInlineSpellChecker(bool autoCreate, nsIInlineSpellChecker ** aInlineSpellChecker) { +#ifdef MOZ_SPELLCHECK NS_ENSURE_ARG_POINTER(aInlineSpellChecker); if (mDidPreDestroy) { @@ -1326,11 +1334,15 @@ NS_IMETHODIMP nsEditor::GetInlineSpellChecker(bool autoCreate, NS_IF_ADDREF(*aInlineSpellChecker = mInlineSpellChecker); return NS_OK; +#else + return NS_ERROR_FAILURE; +#endif } NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic, const PRUnichar *aData) { +#ifdef MOZ_SPELLCHECK NS_ASSERTION(!strcmp(aTopic, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION), "Unexpected observer topic"); @@ -1354,6 +1366,9 @@ NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic, } return NS_OK; +#else + return NS_OK; +#endif } NS_IMETHODIMP nsEditor::SyncRealTimeSpell() diff --git a/embedding/android/CrashReporter.java.in b/embedding/android/CrashReporter.java.in deleted file mode 100644 index dd1f6350e70..00000000000 --- a/embedding/android/CrashReporter.java.in +++ /dev/null @@ -1,336 +0,0 @@ -/* -*- Mode: Java; 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): - * Brad Lassey - * - * 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 -package @ANDROID_PACKAGE_NAME@; - - -import android.app.*; -import android.content.*; -import android.os.*; -import android.util.*; -import android.view.*; -import android.view.View.*; -import android.widget.*; - -import org.mozilla.gecko.*; -import java.util.*; -import java.io.*; -import java.net.*; -import java.nio.channels.*; - -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 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(); - - if (transferred > 0) - inFile.delete(); - } catch (Exception e) { - Log.e("GeckoCrashReporter", - "exception while copying minidump file: ", e); - return false; - } - return true; - } - - void doFinish() { - if (mHandler != null) { - mHandler.post(new Runnable(){ - public void run() { - 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(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("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); - - File extrasFile = new File(passedMinidumpPath.replaceAll(".dmp", ".extra")); - mPendingExtrasFile = new File(pendingDir, extrasFile.getName()); - moveFile(extrasFile, mPendingExtrasFile); - - mExtrasStringMap = new HashMap(); - readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap); - } - - void backgroundSendReport() - { - final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report); - if (!sendReportCheckbox.isChecked()) { - doFinish(); - return; - } - - 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; - } - } - - 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 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 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)); - } - } - - // 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 responseMap = new HashMap(); - 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); - } - - doFinish(); - } - - 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); - } - } - - public String unescape(String string) - { - return string.replaceAll("\\\\", "\\").replaceAll("\\n", "\n") - .replaceAll("\\t", "\t"); - } -} - diff --git a/embedding/android/GeckoApp.java b/embedding/android/GeckoApp.java deleted file mode 100644 index b2c58cf051e..00000000000 --- a/embedding/android/GeckoApp.java +++ /dev/null @@ -1,873 +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) 2009-2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Vladimir Vukicevic - * Matt Brubeck - * Vivien Nicolas - * - * 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.zip.*; -import java.nio.*; -import java.nio.channels.FileChannel; -import java.util.concurrent.*; -import java.lang.reflect.*; - -import android.os.*; -import android.app.*; -import android.text.*; -import android.view.*; -import android.view.inputmethod.*; -import android.content.*; -import android.content.res.*; -import android.graphics.*; -import android.widget.*; -import android.hardware.*; - -import android.util.*; -import android.net.*; -import android.database.*; -import android.provider.*; -import android.content.pm.*; -import android.content.pm.PackageManager.*; -import dalvik.system.*; - -abstract public class GeckoApp - extends Activity -{ - private static final String LOG_FILE_NAME = "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 AbsoluteLayout mainLayout; - public static GeckoSurfaceView surfaceView; - public static SurfaceView cameraView; - public static GeckoApp mAppContext; - public static boolean mFullscreen = false; - public static File sGREDir = null; - static Thread mLibLoadThread = null; - public Handler mMainHandler; - private IntentFilter mConnectivityFilter; - private BroadcastReceiver mConnectivityReceiver; - private BroadcastReceiver mBatteryReceiver; - - enum LaunchState {PreLaunch, Launching, WaitForDebugger, - Launched, GeckoRunning, GeckoExiting}; - private static LaunchState sLaunchState = LaunchState.PreLaunch; - private static boolean sTryCatchAttached = false; - - - static boolean checkLaunchState(LaunchState checkState) { - synchronized(sLaunchState) { - return sLaunchState == checkState; - } - } - - static void setLaunchState(LaunchState setState) { - synchronized(sLaunchState) { - sLaunchState = setState; - } - } - - // if mLaunchState is equal to checkState this sets mLaunchState to setState - // and return true. Otherwise we return false. - static boolean checkAndSetLaunchState(LaunchState checkState, LaunchState setState) { - synchronized(sLaunchState) { - if (sLaunchState != checkState) - return false; - sLaunchState = setState; - return true; - } - } - - void showErrorDialog(String message) - { - new AlertDialog.Builder(this) - .setMessage(message) - .setCancelable(false) - .setPositiveButton(R.string.exit_label, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int id) - { - GeckoApp.this.finish(); - System.exit(0); - } - }).show(); - } - - 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 mPackageInfoCache = new ArrayList(); - - String[] getPluginDirectories() { - - ArrayList directories = new ArrayList(); - PackageManager pm = this.mAppContext.getPackageManager(); - List plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION), - PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); - - synchronized(mPackageInfoCache) { - - // clear the list of existing packageInfo objects - mPackageInfoCache.clear(); - - - for (ResolveInfo info : plugins) { - - // retrieve the plugin's service information - ServiceInfo serviceInfo = info.serviceInfo; - if (serviceInfo == null) { - Log.w(LOGTAG, "Ignore bad 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 - | PackageManager.GET_SIGNATURES); - } catch (Exception e) { - Log.w(LOGTAG, "Can't find plugin: " + serviceInfo.packageName); - continue; - } - if (pkgInfo == null) { - Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Could not load package information."); - continue; - } - - /* - * find the location of the plugin's shared library. The default - * is to assume the app is either a user installed app or an - * updated system app. In both of these cases the library is - * stored in the app's data directory. - */ - String directory = pkgInfo.applicationInfo.dataDir + "/lib"; - final int appFlags = pkgInfo.applicationInfo.flags; - final int updatedSystemFlags = ApplicationInfo.FLAG_SYSTEM | - ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - // preloaded system app with no user updates - if ((appFlags & updatedSystemFlags) == ApplicationInfo.FLAG_SYSTEM) { - directory = PLUGIN_SYSTEM_LIB + pkgInfo.packageName; - } - - // check if the plugin has the required permissions - String permissions[] = pkgInfo.requestedPermissions; - if (permissions == null) { - Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Does not have required permission."); - continue; - } - boolean permissionOk = false; - for (String permit : permissions) { - if (PLUGIN_PERMISSION.equals(permit)) { - permissionOk = true; - break; - } - } - if (!permissionOk) { - Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Does not have required permission (2)."); - continue; - } - - // check to ensure the plugin is properly signed - Signature signatures[] = pkgInfo.signatures; - if (signatures == null) { - Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Not signed."); - continue; - } - - // determine the type of plugin from the manifest - if (serviceInfo.metaData == null) { - Log.e(LOGTAG, "The plugin '" + serviceInfo.name + "' has no type defined"); - continue; - } - - String pluginType = serviceInfo.metaData.getString(PLUGIN_TYPE); - if (!TYPE_NATIVE.equals(pluginType)) { - Log.e(LOGTAG, "Unrecognized plugin type: " + pluginType); - continue; - } - - try { - Class cls = getPluginClass(serviceInfo.packageName, serviceInfo.name); - - //TODO implement any requirements of the plugin class here! - boolean classFound = true; - - if (!classFound) { - Log.e(LOGTAG, "The plugin's class' " + serviceInfo.name + "' does not extend the appropriate class."); - continue; - } - - } catch (NameNotFoundException e) { - Log.e(LOGTAG, "Can't find plugin: " + serviceInfo.packageName); - continue; - } catch (ClassNotFoundException e) { - Log.e(LOGTAG, "Can't find plugin's class: " + serviceInfo.name); - continue; - } - - // if all checks have passed then make the plugin available - mPackageInfoCache.add(pkgInfo); - directories.add(directory); - } - } - - return directories.toArray(new String[directories.size()]); - } - - 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) - { - if (!checkAndSetLaunchState(LaunchState.Launching, LaunchState.Launched)) - return false; - - if (intent == null) - intent = getIntent(); - final Intent i = intent; - new Thread() { - public void run() { - try { - if (mLibLoadThread != null) - mLibLoadThread.join(); - } catch (InterruptedException ie) {} - - // 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(); - - // 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; - } - - // 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()); - } - } - }.start(); - return true; - } - - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle savedInstanceState) - { - mAppContext = this; - 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); - 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)); - - 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); - - if (!checkAndSetLaunchState(LaunchState.PreLaunch, - LaunchState.Launching)) - return; - - checkAndLaunchUpdate(); - mLibLoadThread = new Thread(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(); - } - - 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)); - } - - public void disableCameraView() { - mainLayout.removeView(cameraView); - } - - @Override - protected void onNewIntent(Intent intent) { - 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"); - setLaunchState(LaunchState.Launching); - launch(null); - } - }, 1000 * 5 /* 5 seconds */); - Log.i(LOG_FILE_NAME, "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"); - GeckoAppShell.sendEventToGecko(new GeckoEvent("")); - } - else if (Intent.ACTION_VIEW.equals(action)) { - String uri = intent.getDataString(); - GeckoAppShell.sendEventToGecko(new GeckoEvent(uri)); - Log.i(LOG_FILE_NAME,"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); - } - else if (ACTION_BOOKMARK.equals(action)) { - String args = intent.getStringExtra("args"); - GeckoAppShell.sendEventToGecko(new GeckoEvent(args)); - Log.i(LOG_FILE_NAME,"Intent : BOOKMARK - " + args); - } - } - - @Override - public void onPause() - { - Log.i(LOG_FILE_NAME, "pause"); - 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(mConnectivityReceiver); - } - - @Override - public void onResume() - { - Log.i(LOG_FILE_NAME, "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)) - onNewIntent(getIntent()); - - registerReceiver(mConnectivityReceiver, mConnectivityFilter); - } - - @Override - public void onStop() - { - Log.i(LOG_FILE_NAME, "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(); - super.onRestart(); - } - - @Override - public void onStart() - { - Log.i(LOG_FILE_NAME, "start"); - GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_START)); - super.onStart(); - } - - @Override - public void onDestroy() - { - Log.i(LOG_FILE_NAME, "destroy"); - // Tell Gecko to shutting down; we'll end up calling System.exit() - // in onXreExit. - if (isFinishing()) - GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_SHUTDOWN)); - - super.onDestroy(); - - unregisterReceiver(mBatteryReceiver); - } - - @Override - public void onConfigurationChanged(android.content.res.Configuration newConfig) - { - Log.i(LOG_FILE_NAME, "configuration changed"); - // nothing, just ignore - super.onConfigurationChanged(newConfig); - } - - @Override - public void onLowMemory() - { - Log.e(LOG_FILE_NAME, "low memory"); - if (checkLaunchState(LaunchState.GeckoRunning)) - GeckoAppShell.onLowMemory(); - super.onLowMemory(); - } - - abstract public String getPackageName(); - abstract public String getContentProcessName(); - - protected void unpackComponents() - throws IOException, FileNotFoundException - { - File applicationPackage = new File(getApplication().getPackageResourcePath()); - File componentsDir = new File(sGREDir, "components"); - if (componentsDir.lastModified() == applicationPackage.lastModified()) - return; - - componentsDir.mkdir(); - componentsDir.setLastModified(applicationPackage.lastModified()); - - GeckoAppShell.killAnyZombies(); - - ZipFile zip = new ZipFile(applicationPackage); - - byte[] buf = new byte[32768]; - try { - if (unpackFile(zip, buf, null, "removed-files")) - removeFiles(); - } catch (Exception ex) { - // This file may not be there, so just log any errors and move on - Log.w(LOG_FILE_NAME, "error removing files", ex); - } - - // copy any .xpi file into an extensions/ directory - Enumeration zipEntries = zip.entries(); - while (zipEntries.hasMoreElements()) { - ZipEntry entry = zipEntries.nextElement(); - if (entry.getName().startsWith("extensions/") && entry.getName().endsWith(".xpi")) { - Log.i("GeckoAppJava", "installing extension : " + entry.getName()); - unpackFile(zip, buf, entry, entry.getName()); - } - } - } - - void removeFiles() throws IOException { - BufferedReader reader = new BufferedReader( - new FileReader(new File(sGREDir, "removed-files"))); - try { - for (String removedFileName = reader.readLine(); - removedFileName != null; removedFileName = reader.readLine()) { - File removedFile = new File(sGREDir, removedFileName); - if (removedFile.exists()) - removedFile.delete(); - } - } finally { - reader.close(); - } - - } - - private boolean unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry, - String name) - throws IOException, FileNotFoundException - { - if (fileEntry == null) - fileEntry = zip.getEntry(name); - if (fileEntry == null) - throw new FileNotFoundException("Can't find " + name + " in " + - zip.getName()); - - File outFile = new File(sGREDir, name); - if (outFile.lastModified() == fileEntry.getTime() && - outFile.length() == fileEntry.getSize()) - return false; - - File dir = outFile.getParentFile(); - if (!dir.exists()) - dir.mkdirs(); - - InputStream fileStream; - fileStream = zip.getInputStream(fileEntry); - - OutputStream outStream = new FileOutputStream(outFile); - - while (fileStream.available() > 0) { - int read = fileStream.read(buf, 0, buf.length); - outStream.write(buf, 0, read); - } - - fileStream.close(); - outStream.close(); - outFile.setLastModified(fileEntry.getTime()); - return true; - } - - public void addEnvToIntent(Intent intent) { - Map envMap = System.getenv(); - Set> envSet = envMap.entrySet(); - Iterator> envIter = envSet.iterator(); - StringBuffer envstr = new StringBuffer(); - int c = 0; - while (envIter.hasNext()) { - Map.Entry entry = envIter.next(); - intent.putExtra("env" + c, entry.getKey() + "=" - + entry.getValue()); - c++; - } - } - - public void doRestart() { - try { - String action = "org.mozilla.gecko.restart"; - Intent intent = new Intent(action); - intent.setClassName(getPackageName(), - getPackageName() + ".Restarter"); - addEnvToIntent(intent); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | - Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - Log.i(LOG_FILE_NAME, intent.toString()); - GeckoAppShell.killAnyZombies(); - startActivity(intent); - } catch (Exception e) { - Log.i(LOG_FILE_NAME, "error doing restart", e); - } - finish(); - // Give the restart process time to start before we die - GeckoAppShell.waitForAnotherGeckoProc(); - } - - public void handleNotification(String action, String alertName, String alertCookie) { - GeckoAppShell.handleNotification(action, alertName, alertCookie); - } - - private void checkAndLaunchUpdate() { - Log.i(LOG_FILE_NAME, "Checking for an update"); - - int statusCode = 8; // UNEXPECTED_ERROR - File baseUpdateDir = null; - if (Build.VERSION.SDK_INT >= 8) - baseUpdateDir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS); - else - baseUpdateDir = new File(Environment.getExternalStorageDirectory().getPath(), "download"); - - File updateDir = new File(new File(baseUpdateDir, "updates"),"0"); - - File updateFile = new File(updateDir, "update.apk"); - File statusFile = new File(updateDir, "update.status"); - - if (!statusFile.exists() || !readUpdateStatus(statusFile).equals("pending")) - return; - - if (!updateFile.exists()) - return; - - Log.i(LOG_FILE_NAME, "Update is available!"); - - // Launch APK - File updateFileToRun = new File(updateDir, getPackageName() + "-update.apk"); - try { - if (updateFile.renameTo(updateFileToRun)) { - String amCmd = "/system/bin/am start -a android.intent.action.VIEW " + - "-n com.android.packageinstaller/.PackageInstallerActivity -d file://" + - updateFileToRun.getPath(); - Log.i(LOG_FILE_NAME, amCmd); - Runtime.getRuntime().exec(amCmd); - statusCode = 0; // OK - } else { - Log.i(LOG_FILE_NAME, "Cannot rename the update file!"); - statusCode = 7; // WRITE_ERROR - } - } catch (Exception e) { - Log.i(LOG_FILE_NAME, "error launching installer to update", e); - } - - // Update the status file - String status = statusCode == 0 ? "succeeded\n" : "failed: "+ statusCode + "\n"; - - OutputStream outStream; - try { - byte[] buf = status.getBytes("UTF-8"); - outStream = new FileOutputStream(statusFile); - outStream.write(buf, 0, buf.length); - outStream.close(); - } catch (Exception e) { - Log.i(LOG_FILE_NAME, "error writing status file", e); - } - - if (statusCode == 0) - System.exit(0); - } - - private String readUpdateStatus(File statusFile) { - String status = ""; - try { - BufferedReader reader = new BufferedReader(new FileReader(statusFile)); - status = reader.readLine(); - reader.close(); - } catch (Exception e) { - Log.i(LOG_FILE_NAME, "error reading update status", e); - } - return status; - } - - static final int FILE_PICKER_REQUEST = 1; - - private SynchronousQueue mFilePickerResult = new SynchronousQueue(); - public String showFilePicker(String aMimeType) { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType(aMimeType); - GeckoApp.this. - startActivityForResult( - Intent.createChooser(intent, getString(R.string.choose_file)), - FILE_PICKER_REQUEST); - String filePickerResult = ""; - - try { - while (null == (filePickerResult = mFilePickerResult.poll(1, TimeUnit.MILLISECONDS))) { - Log.i("GeckoApp", "processing events from showFilePicker "); - GeckoAppShell.processNextNativeEvent(); - } - } catch (InterruptedException e) { - Log.i(LOG_FILE_NAME, "showing file picker ", e); - } - - return filePickerResult; - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, - Intent data) { - String filePickerResult = ""; - if (data != null && resultCode == RESULT_OK) { - try { - ContentResolver cr = getContentResolver(); - Uri uri = data.getData(); - Cursor cursor = GeckoApp.mAppContext.getContentResolver().query( - uri, - new String[] { OpenableColumns.DISPLAY_NAME }, - null, - null, - null); - String name = null; - if (cursor != null) { - try { - if (cursor.moveToNext()) { - name = cursor.getString(0); - } - } finally { - cursor.close(); - } - } - String fileName = "tmp_"; - String fileExt = null; - int period; - if (name == null || (period = name.lastIndexOf('.')) == -1) { - String mimeType = cr.getType(uri); - fileExt = "." + GeckoAppShell.getExtensionFromMimeType(mimeType); - } else { - fileExt = name.substring(period); - fileName = name.substring(0, period); - } - File file = File.createTempFile(fileName, fileExt, sGREDir); - - FileOutputStream fos = new FileOutputStream(file); - InputStream is = cr.openInputStream(uri); - byte[] buf = new byte[4096]; - int len = is.read(buf); - while (len != -1) { - fos.write(buf, 0, len); - len = is.read(buf); - } - fos.close(); - filePickerResult = file.getAbsolutePath(); - }catch (Exception e) { - Log.e(LOG_FILE_NAME, "showing file picker", e); - } - } - try { - mFilePickerResult.put(filePickerResult); - } catch (InterruptedException e) { - Log.i(LOG_FILE_NAME, "error returning file picker result", e); - } - } -} diff --git a/embedding/android/GeckoSurfaceView.java b/embedding/android/GeckoSurfaceView.java deleted file mode 100644 index 385c8d1e29e..00000000000 --- 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 - * - * 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 { - protected Void doInBackground(Location... location) { - try { - List
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 mSyncDraws = new SynchronousQueue(); -} - diff --git a/embedding/android/Makefile.in b/embedding/android/Makefile.in deleted file mode 100644 index db1693f2669..00000000000 --- a/embedding/android/Makefile.in +++ /dev/null @@ -1,219 +0,0 @@ -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is the Mozilla browser. -# -# 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 -# -# 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 -include $(topsrcdir)/ipc/app/defs.mk - -DIRS = locales - -JAVAFILES = \ - GeckoApp.java \ - GeckoAppShell.java \ - GeckoConnectivityReceiver.java \ - GeckoEvent.java \ - GeckoSurfaceView.java \ - GeckoInputConnection.java \ - AlertNotification.java \ - SurfaceInfo.java \ - GeckoBatteryManager.java \ - $(NULL) - -PROCESSEDJAVAFILES = \ - App.java \ - Restarter.java \ - NotificationHandler.java \ - LauncherShortcuts.java \ - $(NULL) - - -ifneq (,$(findstring -march=armv7,$(OS_CFLAGS))) -MIN_CPU_VERSION=7 -else -MIN_CPU_VERSION=5 -endif - -ifeq (,$(ANDROID_VERSION_CODE)) -ANDROID_VERSION_CODE=$(shell $(PYTHON) $(topsrcdir)/toolkit/xre/make-platformini.py --print-buildid | cut -c1-10) -endif - -DEFINES += \ - -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \ - -DMOZ_APP_DISPLAYNAME="$(MOZ_APP_DISPLAYNAME)" \ - -DMOZ_APP_NAME=$(MOZ_APP_NAME) \ - -DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \ - -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME) \ - -DMOZ_MIN_CPU_VERSION=$(MIN_CPU_VERSION) \ - -DMOZ_CRASHREPORTER=$(MOZ_CRASHREPORTER) \ - -DANDROID_VERSION_CODE=$(ANDROID_VERSION_CODE) \ - -DMOZILLA_OFFICIAL=$(MOZILLA_OFFICIAL) \ - $(NULL) - -GARBAGE += \ - AndroidManifest.xml \ - classes.dex \ - $(PROCESSEDJAVAFILES) \ - gecko.ap_ \ - res/values/strings.xml \ - R.java \ - $(NULL) - -GARBAGE_DIRS += classes res - -# Bug 567884 - Need a way to find appropriate icons during packaging -ifeq ($(MOZ_APP_NAME),fennec) -ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_48x48.png -ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png - -# we released these builds to the public with shared IDs and need to keep them -ifeq (org.mozilla.firefox,$(ANDROID_PACKAGE_NAME)) -DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.firefox.sharedID" -else ifeq (org.mozilla.firefox_beta,$(ANDROID_PACKAGE_NAME)) -DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.firefox.sharedID" -else ifeq (org.mozilla.fennec_aurora,$(ANDROID_PACKAGE_NAME)) -DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.fennec.sharedID" -else ifeq (org.mozilla.fennec,$(ANDROID_PACKAGE_NAME)) -DEFINES += -DMOZ_ANDROID_SHARED_ID="org.mozilla.fennec.sharedID" -endif - -else -ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon48.png -ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon64.png -DEFINES += -DMOZ_ANDROID_SHARED_ID="$(ANDROID_PACKAGE_NAME).sharedID" -endif - -RES_LAYOUT = \ - res/layout/notification_progress.xml \ - res/layout/notification_progress_text.xml \ - res/layout/notification_icon_text.xml \ - res/layout/launch_app_list.xml \ - res/layout/launch_app_listitem.xml \ - $(NULL) - -RES_VALUES = res/values/colors.xml res/values/themes.xml - -AB_rCD = $(shell echo $(AB_CD) | sed -e s/-/-r/) - -JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar - -DEFAULT_BRANDPATH = $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales/en-US/brand.dtd -DEFAULT_STRINGSPATH = locales/en-US/android_strings.dtd -LOCALIZED_BRANDPATH = $(DEPTH)/dist/bin/chrome/$(AB_CD)/locale/branding/brand.dtd -LOCALIZED_STRINGSPATH = $(DEPTH)/dist/bin/chrome/android-res/res/values-$(AB_CD)/android_strings.dtd - -ifdef MOZ_CRASHREPORTER -PROCESSEDJAVAFILES += CrashReporter.java -MOZ_ANDROID_DRAWABLES += embedding/android/resources/drawable/crash_reporter.png -RES_LAYOUT += res/layout/crash_reporter.xml -endif - -MOZ_ANDROID_DRAWABLES += embedding/android/resources/drawable/desktop_notification.png - -MOZ_ANDROID_DRAWABLES += $(shell if test -e $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn; then cat $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn | tr '\n' ' '; fi) - -include $(topsrcdir)/config/rules.mk - -ifneq ($(AB_CD),en-US) -LOCALIZED_STRINGS_XML = res/values-$(AB_rCD)/strings.xml -endif - -# Override the Java settings with some specific android settings -include $(topsrcdir)/config/android-common.mk - -# Note that we're going to set up a dependency directly between embed_android.dex and the java files -# Instead of on the .class files, since more than one .class file might be produced per .java file -classes.dex: $(JAVAFILES) $(PROCESSEDJAVAFILES) R.java - $(NSINSTALL) -D classes - $(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(PROCESSEDJAVAFILES) R.java - $(DX) --dex --output=$@ classes - -AndroidManifest.xml $(PROCESSEDJAVAFILES): % : %.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ - $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@ - -res/drawable/icon.png: $(MOZ_APP_ICON) - $(NSINSTALL) -D res/drawable - cp $(ICON_PATH) $@ - -res/drawable-hdpi/icon.png: $(MOZ_APP_ICON) - $(NSINSTALL) -D res/drawable-hdpi - cp $(ICON_PATH_HDPI) $@ - -RES_DRAWABLE = $(addprefix res/drawable/,$(notdir $(MOZ_ANDROID_DRAWABLES))) - -$(RES_DRAWABLE): $(addprefix $(topsrcdir)/,$(MOZ_ANDROID_DRAWABLES)) - $(NSINSTALL) -D res/drawable - $(NSINSTALL) $^ res/drawable/ - -$(RES_LAYOUT): $(subst res/,$(srcdir)/resources/,$(RES_LAYOUT)) - $(NSINSTALL) -D res/layout - $(NSINSTALL) $(srcdir)/resources/layout/* res/layout/ - -$(RES_VALUES): $(subst res/,$(srcdir)/resources/,$(RES_VALUES)) - $(NSINSTALL) -D res/values - $(NSINSTALL) $(srcdir)/resources/values/* res/values/ - -R.java: $(MOZ_APP_ICON) $(RES_LAYOUT) $(RES_DRAWABLE) $(RES_VALUES) res/drawable/icon.png res/drawable-hdpi/icon.png res/values/strings.xml AndroidManifest.xml - $(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -J . --custom-package org.mozilla.gecko - -gecko.ap_: AndroidManifest.xml res/drawable/icon.png res/drawable-hdpi/icon.png $(RES_LAYOUT) $(RES_DRAWABLE) $(RES_VALUES) res/values/strings.xml FORCE - $(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@ - -res/values/strings.xml: $(DEFAULT_BRANDPATH) $(DEFAULT_STRINGSPATH) - mkdir -p res/values - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \ - -DBRANDPATH="$(DEFAULT_BRANDPATH)" \ - -DSTRINGSPATH="$(DEFAULT_STRINGSPATH)" \ - $(srcdir)/strings.xml.in \ - > $@ - -res/values-$(AB_rCD)/strings.xml: $(LOCALIZED_BRANDPATH) $(LOCALIZED_STRINGSPATH) - mkdir -p res/values-$(AB_rCD) - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \ - -DBRANDPATH="$(call core_abspath,$(LOCALIZED_BRANDPATH))" \ - -DSTRINGSPATH="$(call core_abspath,$(LOCALIZED_STRINGSPATH))" \ - $(srcdir)/strings.xml.in \ - > $@ - -chrome:: $(LOCALIZED_STRINGS_XML) - -libs:: classes.dex - $(INSTALL) classes.dex $(FINAL_TARGET) diff --git a/embedding/android/SurfaceInfo.java b/embedding/android/SurfaceInfo.java deleted file mode 100644 index f823926a282..00000000000 --- 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; -} diff --git a/embedding/android/locales/en-US/android_strings.dtd b/embedding/android/locales/en-US/android_strings.dtd deleted file mode 100644 index 854f67d826a..00000000000 --- a/embedding/android/locales/en-US/android_strings.dtd +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/embedding/android/resources/layout/crash_reporter.xml b/embedding/android/resources/layout/crash_reporter.xml deleted file mode 100644 index f9178668536..00000000000 --- a/embedding/android/resources/layout/crash_reporter.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - +
click here
+ + +
+ + + dumb type + + +
div
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/chrome/tests/browser_forms.js b/mobile/android/chrome/tests/browser_forms.js new file mode 100644 index 00000000000..37589eb19b0 --- /dev/null +++ b/mobile/android/chrome/tests/browser_forms.js @@ -0,0 +1,242 @@ +let testURL = chromeRoot + "browser_forms.html"; +messageManager.loadFrameScript(chromeRoot + "remote_forms.js", true); + +let newTab = null; + +function test() { + // This test is async + waitForExplicitFinish(); + + // Need to wait until the page is loaded + messageManager.addMessageListener("pageshow", function(aMessage) { + if (newTab && newTab.browser.currentURI.spec != "about:blank") { + messageManager.removeMessageListener(aMessage.name, arguments.callee); + setTimeout(onTabLoaded, 0); + } + }); + + // Add new tab to hold the page + newTab = Browser.addTab(testURL, true); +} + +function onTabLoaded() { + BrowserUI.closeAutoComplete(true); + testMouseEvents(); +} + +function testMouseEvents() { + // Sending a synthesized event directly on content should not work - we + // don't want web content to be able to open the form helper without the + // user consent, so we have to pass through the canvas tile-container + AsyncTests.waitFor("Test:Click", {}, function(json) { + is(json.result, false, "Form Assistant should stay closed"); + }); + + AsyncTests.waitFor("Test:Focus", { value: "#root" }, function(json) { + is(json.result, false, "Form Assistant should stay closed"); + }); + + AsyncTests.waitFor("Test:FocusRedirect", { value: "*[tabindex='0']" }, function(json) { + is(json.result, false, "Form Assistant should stay closed"); + testOpenUIWithSyncFocus(); + }); +}; + +function waitForFormAssist(aCallback) { + messageManager.addMessageListener("FormAssist:Show", function(aMessage) { + messageManager.removeMessageListener(aMessage.name, arguments.callee); + setTimeout(function() { + ok(FormHelperUI._open, "Form Assistant should be open"); + setTimeout(aCallback, 0); + }); + }); +}; + +function testOpenUIWithSyncFocus() { + AsyncTests.waitFor("Test:Open", { value: "*[tabindex='0']" }, function(json) {}); + waitForFormAssist(testOpenUI); +}; + +function testOpenUI() { + AsyncTests.waitFor("Test:Open", { value: "*[tabindex='0']" }, function(json) {}); + waitForFormAssist(testOpenUIWithFocusRedirect); +}; + +function testOpenUIWithFocusRedirect() { + AsyncTests.waitFor("Test:OpenWithFocusRedirect", { value: "*[tabindex='0']" }, function(json) {}); + waitForFormAssist(testShowUIForSelect); +}; + +function testShowUIForSelect() { + AsyncTests.waitFor("Test:CanShowUI", { value: "#select"}, function(json) { + ok(json.result, "canShowUI for select element'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "#select", disabled: true }, function(json) { + is(json.result, false, "!canShowUI for disabled select element'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "#option"}, function(json) { + ok(json.result, "canShowUI for option element'"); + }); + + AsyncTests.waitFor("Test:CanShowUISelect", { value: "#option", disabled: true }, function(json) { + is(json.result, false, "!canShowUI for option element with a disabled parent select element'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "#option", disabled: true }, function(json) { + is(json.result, false, "!canShowUI for disabled option element'"); + testShowUIForElements(); + }); +} + +function testShowUIForElements() { + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='1']" }, function(json) { + ok(json.result, "canShowUI for input type='text'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='1']", disabled: true }, function(json) { + is(json.result, false, "!canShowUI for disabled input type='text'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='2']" }, function(json) { + ok(json.result, "canShowUI for input type='password'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='2']", disabled: true }, function(json) { + is(json.result, false, "!canShowUI for disabled input type='password'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='8']" }, function(json) { + ok(json.result, "canShowUI for contenteditable div"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='8']", disabled: true }, function(json) { + is(json.result, false, "!canShowUI for disabled contenteditable div"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='3']" }, function(json) { + is(json.result, false, "!canShowUI for input type='submit'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='4']" }, function(json) { + is(json.result, false, "!canShowUI for input type='file'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='5']" }, function(json) { + is(json.result, false, "!canShowUI for input button type='submit'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='6']" }, function(json) { + is(json.result, false, "!canShowUI for input div@role='button'"); + }); + + AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='6']" }, function(json) { + is(json.result, false, "!canShowUI for input type='image'"); + }); + + // Open the Form Helper + AsyncTests.waitFor("Test:Open", { value: "*[tabindex='1']" }, function(json) { + ok(json.result, "Form Assistant should be open"); + testTabIndexNavigation(); + }); +}; + +function testTabIndexNavigation() { + AsyncTests.waitFor("Test:Previous", { value: "*[tabindex='0']" }, function(json) { + is(json.result, false, "Focus should not have changed"); + }); + + AsyncTests.waitFor("Test:Next", { value: "*[tabindex='2']" }, function(json) { + is(json.result, true, "Focus should be on element with tab-index : 2"); + }); + + AsyncTests.waitFor("Test:Previous", { value: "*[tabindex='1']" }, function(json) { + is(json.result, true, "Focus should be on element with tab-index : 1"); + }); + + AsyncTests.waitFor("Test:Next"); + AsyncTests.waitFor("Test:Next"); + AsyncTests.waitFor("Test:Next"); + AsyncTests.waitFor("Test:Next"); + AsyncTests.waitFor("Test:Next"); + + AsyncTests.waitFor("Test:Next", { value: "*[tabindex='7']" }, function(json) { + is(json.result, true, "Focus should be on element with tab-index : 7"); + }); + + AsyncTests.waitFor("Test:Next", { value: "*[tabindex='8']" }, function(json) { + is(json.result, true, "Focus should be on element with tab-index : 8"); + }); + + AsyncTests.waitFor("Test:Next", { value: "*[tabindex='0']" }, function(json) { + is(json.result, true, "Focus should be on element with tab-index : 0"); + }); + + let ids = ["next", "select", "dumb", "reset", "checkbox", "radio0", "radio4", "last", "last"]; + for (let i = 0; i < ids.length; i++) { + let id = ids[i]; + AsyncTests.waitFor("Test:Next", { value: "#" + id }, function(json) { + is(json.result, true, "Focus should be on element with #id: " + id + ""); + }); + }; + + FormHelperUI.hide(); + let container = document.getElementById("content-navigator"); + is(container.hidden, true, "Form Assistant should be close"); + + AsyncTests.waitFor("Test:Open", { value: "*[tabindex='0']" }, function(json) { + ok(FormHelperUI._open, "Form Assistant should be open"); + testFocusChanges(); + }); +}; + +function testFocusChanges() { + AsyncTests.waitFor("Test:Focus", { value: "*[tabindex='1']" }, function(json) { + ok(json.result, "Form Assistant should be open"); + }); + + AsyncTests.waitFor("Test:Focus", { value: "#select" }, function(json) { + ok(json.result, "Form Assistant should stay open"); + }); + + AsyncTests.waitFor("Test:Focus", { value: "*[type='hidden']" }, function(json) { + ok(json.result, "Form Assistant should stay open"); + loadNestedIFrames(); + }); +} + +function loadNestedIFrames() { + AsyncTests.waitFor("Test:Iframe", { }, function(json) { + is(json.result, true, "Iframe should have loaded"); + navigateIntoNestedIFrames(); + }); +} + +function navigateIntoNestedIFrames() { + AsyncTests.waitFor("Test:IframeOpen", { }, function(json) { + is(json.result, true, "Form Assistant should have been opened"); + }); + + AsyncTests.waitFor("Test:IframePrevious", { value: 0 }, function(json) { + is(json.result, true, "Focus should not have move"); + }); + + AsyncTests.waitFor("Test:IframeNext", { value: 1 }, function(json) { + is(json.result, true, "Focus should have move"); + }); + + AsyncTests.waitFor("Test:IframeNext", { value: 1 }, function(json) { + is(json.result, true, "Focus should not have move"); + + // Close the form assistant + FormHelperUI.hide(); + + // Close our tab when finished + Browser.closeTab(newTab); + + // We must finalize the tests + finish(); + }); +}; + diff --git a/mobile/android/chrome/tests/browser_formsZoom.html b/mobile/android/chrome/tests/browser_formsZoom.html new file mode 100644 index 00000000000..36f641d0d0d --- /dev/null +++ b/mobile/android/chrome/tests/browser_formsZoom.html @@ -0,0 +1,66 @@ + + + Browser Zoom Test + + +















+
+
+
+ +
+ + diff --git a/mobile/android/chrome/tests/browser_formsZoom.js b/mobile/android/chrome/tests/browser_formsZoom.js new file mode 100644 index 00000000000..d78a2677169 --- /dev/null +++ b/mobile/android/chrome/tests/browser_formsZoom.js @@ -0,0 +1,214 @@ +let testURL_01 = chromeRoot + "browser_formsZoom.html"; +let testURL_02 = baseURI + "browser_formsZoom.html"; +messageManager.loadFrameScript(baseURI + "remote_formsZoom.js", true); + +// A queue to order the tests and a handle for each test +var gTests = []; +var gCurrentTest = null; + +//------------------------------------------------------------------------------ +// Entry point (must be named "test") +function test() { + // The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()" + // We call "finish()" when the tests are finished + waitForExplicitFinish(); + // Start the tests + runNextTest(); +} + +function waitForPageShow(aPageURL, aCallback) { + messageManager.addMessageListener("pageshow", function(aMessage) { + if (aMessage.target.currentURI.spec == aPageURL) { + messageManager.removeMessageListener("pageshow", arguments.callee); + setTimeout(function() { aCallback(); }, 0); + } + }); +}; + +//------------------------------------------------------------------------------ +// Iterating tests by shifting test out one by one as runNextTest is called. +function runNextTest() { + // Run the next test until all tests completed + if (gTests.length > 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + setTimeout(gCurrentTest.run, 0); + } + else { + // Cleanup. All tests are completed at this point + try { + // Add any cleanup code here + } + finally { + // We must finialize the tests + finish(); + } + } +} + +function waitForZoom(aCallback) { + if (AnimatedZoom.isZooming()) { + let self = this; + window.addEventListener("AnimatedZoomEnd", function() { + window.removeEventListener("AnimatedZoomEnd", arguments.callee, false); + setTimeout(aCallback, 0); + }, false); + } + else setTimeout(aCallback, 0); +} + +function isElementVisible(aElement) { + let elementRect = Rect.fromRect(aElement.rect); + let caretRect = Rect.fromRect(aElement.caretRect); + + let browser = getBrowser(); + let zoomRect = Rect.fromRect(browser.getBoundingClientRect()); + let scroll = browser.getRootView().getPosition(); + let browserRect = new Rect(scroll.x, scroll.y, zoomRect.width, zoomRect.height); + + info("CanZoom: " +Browser.selectedTab.allowZoom); + + info("Browser rect: " + browserRect + " - scale: " + browser.scale); + info("Element rect: " + elementRect + " - caret rect: " + caretRect); + info("Scale element rect: " + elementRect.clone().scale(browser.scale, browser.scale) + " - scale caretRect: " + caretRect.clone().scale(browser.scale, browser.scale)); + info("Resulting zoom rect: " + Browser._getZoomRectForPoint(elementRect.center().x, elementRect.y, browser.scale)); + + let isCaretSyncEnabled = Services.prefs.getBoolPref("formhelper.autozoom.caret"); + if (isCaretSyncEnabled) { + ok(browserRect.contains(caretRect.clone().scale(browser.scale, browser.scale)), "Caret rect should be completely visible"); + } + else { + elementRect = elementRect.clone().scale(browser.scale, browser.scale); + let resultRect = browserRect.intersect(elementRect); + ok(!resultRect.isEmpty() && elementRect.x > browserRect.x && elementRect.y > browserRect.y, "Element should be partially visible"); + } +} + + +//------------------------------------------------------------------------------ +// Case: Loading a page and Zoom into textarea field with caret sync disabled +gTests.push({ + desc: "Loading a page and Zoom into textarea field with caret sync enabled", + elements: ["textarea-1", "textarea-2", "textarea-3", "textarea-4"], + _currentTab: null, + + run: function() { + Services.prefs.setBoolPref("formhelper.autozoom.caret", false); + gCurrentTest._currentTab = BrowserUI.newTab(testURL_01); + + waitForPageShow(testURL_01, function() { gCurrentTest.zoomNext(); }); + }, + + zoomNext: function() { + let id = this.elements.shift(); + if (!id) { + BrowserUI.closeTab(); + runNextTest(); + return; + } + + info("Zooming to " + id); + AsyncTests.waitFor("FormAssist:Show", { id: id }, function(json) { + waitForZoom(function() { + isElementVisible(json.current); + gCurrentTest.zoomNext(); + }); + }); + } +}); + +//------------------------------------------------------------------------------ +// Case: Loading a page and Zoom into textarea field with caret sync enabled +gTests.push({ + desc: "Loading a page and Zoom into textarea field with caret sync enabled", + elements: ["textarea-1", "textarea-2", "textarea-3", "textarea-4"], + _currentTab: null, + + run: function() { + Services.prefs.setBoolPref("formhelper.autozoom.caret", true); + gCurrentTest._currentTab = BrowserUI.newTab(testURL_01); + + waitForPageShow(testURL_01, function() { gCurrentTest.zoomNext(); }); + }, + + zoomNext: function() { + let id = this.elements.shift(); + if (!id) { + BrowserUI.closeTab(); + runNextTest(); + return; + } + + AsyncTests.waitFor("FormAssist:Show", { id: id }, function(json) { + waitForZoom(function() { + isElementVisible(json.current); + gCurrentTest.zoomNext(); + }); + }); + } +}); + +//------------------------------------------------------------------------------ +// Case: Loading a remote page and Zoom into textarea field with caret sync disabled +gTests.push({ + desc: "Loading a remote page and Zoom into textarea field with caret sync disabled", + elements: ["textarea-1", "textarea-2", "textarea-3", "textarea-4"], + _currentTab: null, + + run: function() { + Services.prefs.setBoolPref("formhelper.autozoom.caret", false); + gCurrentTest._currentTab = BrowserUI.newTab(testURL_02); + + waitForPageShow(testURL_02, function() { gCurrentTest.zoomNext(); }); + }, + + zoomNext: function() { + let id = this.elements.shift(); + if (!id) { + BrowserUI.closeTab(); + runNextTest(); + return; + } + + AsyncTests.waitFor("FormAssist:Show", { id: id }, function(json) { + waitForZoom(function() { + isElementVisible(json.current); + gCurrentTest.zoomNext(); + }); + }); + } +}); + +//------------------------------------------------------------------------------ +// Case: Loading a remote page and Zoom into textarea field with caret sync enabled +gTests.push({ + desc: "Loading a remote page and Zoom into textarea field with caret sync enabled", + elements: ["textarea-1", "textarea-2"], + _currentTab: null, + + run: function() { + Services.prefs.setBoolPref("formhelper.autozoom.caret", true); + gCurrentTest._currentTab = BrowserUI.newTab(testURL_02); + + waitForPageShow(testURL_02, function() { gCurrentTest.zoomNext(); }); + }, + + zoomNext: function() { + let id = this.elements.shift(); + if (!id) { + todo(false, "textarea-3 caret should be synced, but for some reason it is not"); + todo(false, "textarea-4 caret should be synced, but for some reason it is not"); + BrowserUI.closeTab(); + runNextTest(); + return; + } + + AsyncTests.waitFor("FormAssist:Show", { id: id }, function(json) { + waitForZoom(function() { + isElementVisible(json.current); + gCurrentTest.zoomNext(); + }); + }); + } +}); + diff --git a/mobile/android/chrome/tests/browser_history.js b/mobile/android/chrome/tests/browser_history.js new file mode 100644 index 00000000000..dd4ad8061ce --- /dev/null +++ b/mobile/android/chrome/tests/browser_history.js @@ -0,0 +1,75 @@ +/* + * Make sure history is being recorded when we visit websites. + */ + +var testURL_01 = baseURI + "browser_blank_01.html"; + +// A queue to order the tests and a handle for each test +var gTests = []; +var gCurrentTest = null; + +//------------------------------------------------------------------------------ +// Entry point (must be named "test") +function test() { + // The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()" + // We call "finish()" when the tests are finished + waitForExplicitFinish(); + + // Start the tests + runNextTest(); +} + +//------------------------------------------------------------------------------ +// Iterating tests by shifting test out one by one as runNextTest is called. +function runNextTest() { + // Run the next test until all tests completed + if (gTests.length > 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + gCurrentTest.run(); + } + else { + // Cleanup. All tests are completed at this point + try { + } + finally { + // We must finialize the tests + finish(); + } + } +} + +/** + * One-time observer callback. + */ +function waitForObserve(name, callback) { + var observerService = Cc["@mozilla.org/observer-service;1"] + .getService(Ci.nsIObserverService); + var observer = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), + observe: function(subject, topic, data) { + observerService.removeObserver(observer, name); + observer = null; + callback(subject, topic, data); + } + }; + + observerService.addObserver(observer, name, false); +} + +//------------------------------------------------------------------------------ + +gTests.push({ + desc: "Test history being added with page visit", + _currentTab: null, + + run: function() { + this._currentTab = Browser.addTab(testURL_01, true); + waitForObserve("uri-visit-saved", function(subject, topic, data) { + let uri = subject.QueryInterface(Ci.nsIURI); + ok(uri.spec == testURL_01, "URI was saved to history"); + Browser.closeTab(gCurrentTest._currentTab); + runNextTest(); + }); + } +}); diff --git a/mobile/android/chrome/tests/browser_install.xml b/mobile/android/chrome/tests/browser_install.xml new file mode 100644 index 00000000000..3e96873c2af --- /dev/null +++ b/mobile/android/chrome/tests/browser_install.xml @@ -0,0 +1,58 @@ + + + + Install Tests + Extension + addon1@tests.mozilla.org + 1.0 + http://example.com/icon.png + http://example.com/ + + + Test Creator + http://example.com/creator.html + + + Public + Test add-on + Test add-on + + + Fennec + {a23983c0-fd0e-11dc-95ff-0800200c9a66} + 0 + * + + + ALL + http://example.com/browser/mobile/chrome/tests/addons/browser_install1_1.xpi + + + + Install Tests 2 + Extension + addon2@tests.mozilla.org + 1.0 + http://example.com/icon.png + http://example.com/ + + + Test Creator + http://example.com/creator.html + + + Public + Test add-on 2 + Test add-on 2 + + + Fennec + {a23983c0-fd0e-11dc-95ff-0800200c9a66} + 0 + * + + + ALL + http://example.com/browser/mobile/chrome/tests/addons/browser_install1_2.xpi + + diff --git a/mobile/android/chrome/tests/browser_localepicker.js b/mobile/android/chrome/tests/browser_localepicker.js new file mode 100644 index 00000000000..1acef76c559 --- /dev/null +++ b/mobile/android/chrome/tests/browser_localepicker.js @@ -0,0 +1,282 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +Components.utils.import("resource://gre/modules/Services.jsm"); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +const RELATIVE_DIR = "browser/mobile/chrome/tests/"; +const TESTROOT = "http://example.com/" + RELATIVE_DIR; +const PREF_GET_LOCALES = "extensions.getLocales.get.url"; + +var gAvailable = []; + +var restartObserver = { + observe: function(aSubject, aTopic, aData) { + // cancel restart requests + aSubject.QueryInterface(Ci.nsISupportsPRBool); + aSubject.data = true; + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) +} + +function test() { + Services.obs.addObserver(restartObserver, "quit-application-requested", false); + waitForExplicitFinish(); + Services.prefs.setCharPref(PREF_GET_LOCALES, TESTROOT + "locales_list.sjs?numvalid=2"); + + let chromeReg = Components.classes["@mozilla.org/chrome/chrome-registry;1"].getService(Components.interfaces.nsIXULChromeRegistry); + chromeReg.QueryInterface(Ci.nsIToolkitChromeRegistry); + let availableLocales = chromeReg.getLocalesForPackage("browser"); + while (availableLocales.hasMore()) + gAvailable.push( availableLocales.getNext() ); + + + // in order to test restart notifications being shown, we much open the settings panel once + let settingsButton = document.getElementById("tool-panel-open"); + settingsButton.click(); + waitForAndContinue(runNextTest, function() { + return !document.getElementById("panel-container").hidden; + }); +} + +function end_test() { + BrowserUI.hidePanel(); + Services.prefs.clearUserPref(PREF_GET_LOCALES); + Services.obs.removeObserver(restartObserver, "quit-application-requested"); +} + +registerCleanupFunction(end_test); + +function CheckListLoad(aList, aLength) { + return function() { + return aList.childNodes.length == aLength; + } +} + +function CheckDeck(aDeck, aPanel) { + return function() { + return aDeck.selectedPanel == aPanel; + } +} + +function LocaleTest(aName, aOptions) { + var install = null; + return { + desc: aName, + win: null, + run: function lt_run() { + this.loadedWindow = this.loadedWindow.bind(this); + this.windowClosed = this.windowClosed.bind(this); + this.win = Services.ww.openWindow(aOptions.opener, "chrome://browser/content/localePicker.xul", "_browser", "chrome,dialog=no,all", null); + this.win.addEventListener("load", this.loadedWindow, false); + }, + + loadedWindow: function lt_loadedWindow() { + this.win.removeEventListener("load", this.loadedWindow, false); + if (aOptions.opener) + setTimeout(this.delayedLoadPicker.bind(this), 0); + else + setTimeout(this.delayedLoadMain.bind(this), 0); + }, + + delayedLoadMain: function lt_delayedLoadMain() { + let deck = this.win.document.getElementById("language-deck"); + let mainPage = this.win.document.getElementById("main-page"); + is(deck.selectedPanel, mainPage, "Deck is showing the main page"); + + if (aOptions.loadLocalesList) { + // load the locales list + let changeButton = this.win.document.getElementById("change-language"); + changeButton.click(); + this.delayedLoadPicker(); + } else { + // click the "Continue in English" button + let continueButton = this.win.document.getElementById("continue-in-button"); + ok(/english/i.test(continueButton.textContent), "Continue button says English"); + this.win.addEventListener("unload", this.windowClosed, false); + continueButton.click(); + } + }, + + delayedLoadPicker: function lt_delayedLoadPicker() { + let deck = this.win.document.getElementById("language-deck"); + let pickerPage = this.win.document.getElementById("picker-page"); + is(deck.selectedPanel, pickerPage, "Deck is showing the picker page"); + + let list = this.win.document.getElementById("language-list"); + // wait till the list shows the number of locales bundled with this build + the 2 from the downloaded list + waitForAndContinue(this.listLoaded.bind(this), CheckListLoad(list, gAvailable.length + 2)); + }, + + listLoaded: function() { + let continueButton = this.win.document.getElementById("continue-button"); + let cancelButton = this.win.document.getElementById("cancel-button"); + ok(/continue/i.test(continueButton.textContent), "Continue button has correct text"); + ok(/cancel/i.test(cancelButton.textContent), "Cancel button has correct text"); + + let list = this.win.document.getElementById("language-list"); + is(list.childNodes.length, gAvailable.length + 2, "List has correct number of children"); + + let nextSelected = null; + let selectedItem = null; + for(var i = 0; i < list.childNodes.length; i++) { + let child = list.childNodes[i]; + if (/english/i.test(child.textContent)) { + ok(child.hasAttribute("selected"), "English is initially selected"); + selectedItem = child; + } else { + ok(!child.hasAttribute("selected"), "Language is not selected"); + if (aOptions.selectAddon && child.textContent == aOptions.selectAddon.name) + nextSelected = child; + } + } + this.testInstallingItem(nextSelected); + }, + + testInstallingItem: function lt_testInstallingItem(aSelect) { + let continueButton = this.win.document.getElementById("continue-button"); + let cancelButton = this.win.document.getElementById("cancel-button"); + + if (aSelect) { + aSelect.click(); + is(continueButton.textContent, aOptions.selectAddon.continueButton, "Continue button says " + aOptions.selectAddon.continueButton); + is(cancelButton.textContent, aOptions.selectAddon.cancelButton, "Cancel button says " + aOptions.selectAddon.cancelButton); + let title = this.win.document.getElementById("picker-title"); + is(title.textContent, aOptions.selectAddon.title, "Title says " + aOptions.selectAddon.title); + continueButton.click(); + + let deck = this.win.document.getElementById("language-deck"); + let installerPage = this.win.document.getElementById("installer-page"); + is(deck.selectedPanel, installerPage, "Deck is showing the installer page"); + + let installingPage = this.win.document.getElementById("installer-page-installing"); + is(installerPage.selectedPanel, installingPage, "Installer is showing installing page"); + let installMsg = this.win.document.getElementById("installing-message"); + is(installMsg.textContent, aOptions.selectAddon.installMessage, "Installer is showing correct message"); + + if (aOptions.selectAddon.willFail) { + let failedPage = this.win.document.getElementById("installer-page-error"); + waitForAndContinue(this.installFailed.bind(this), CheckDeck(installerPage, failedPage)); + } else { + let install = aSelect.locale; + this.win.addEventListener("unload", this.windowClosed, false); + } + } else { + this.cancelList(); + } + }, + + installFailed: function lt_installFailed() { + let continueButton = this.win.document.getElementById("install-continue"); + is(continueButton.textContent, aOptions.selectAddon.installFailed, "Install failed button has correct label"); + continueButton.click(); + + let deck = this.win.document.getElementById("language-deck"); + let pickerPage = this.win.document.getElementById("picker-page"); + is(deck.selectedPanel, pickerPage, "Deck is showing the picker page"); + this.cancelList(); + }, + + cancelList: function lt_cancelList() { + this.win.addEventListener("unload", this.windowClosed, false); + + let cancelButton = this.win.document.getElementById("cancel-button"); + cancelButton.click(); + if (!aOptions.opener) { + // canceling out of the list, should revert back to english ui + let deck = this.win.document.getElementById("language-deck"); + let mainPage = this.win.document.getElementById("main-page"); + is(deck.selectedPanel, mainPage, "Deck is showing the main page again"); + let continueButton = this.win.document.getElementById("continue-in-button"); + ok(/english/i.test(continueButton.textContent), "Cancelling returned the UI to English"); + continueButton.click(); + } + }, + + windowClosed: function lt_windowClosed(aEvent) { + this.checkMainUI(aOptions.selectAddon); + + Services.prefs.clearUserPref("intl.locale.matchOS"); + Services.prefs.clearUserPref("general.useragent.locale"); + window.PreferencesView.hideRestart(); + + if (install) + install.uninstall(); + + runNextTest(); + }, + + checkMainUI: function(aAddon) { + let systemPref = ""; + let userAgentPref = ""; + try { + systemPref = Services.prefs.getBoolPref("intl.locale.matchOS"); + userAgentPref = Services.prefs.getCharPref("general.useragent.locale") + } catch(ex) { } + + let notification = document.getElementById("prefs-messages").getNotificationWithValue("restart-app"); + let showRestart = aAddon ? !aAddon.willFail : false; + is(!!notification, showRestart, "Restart message is " + (showRestart ? "" : "not ") + "shown"); + + // check that locale pref has been updated + let localeName = aAddon ? aAddon.locale : "en-US"; + is(systemPref, false, "Match system locale is false"); + is(userAgentPref, localeName, "User agent locale is " + localeName); + let buttonLabel = aAddon ? aAddon.localeName : "English (US)"; + is(document.getElementById("prefs-uilanguage-button").getAttribute("label"), buttonLabel, "Locale button says " + buttonLabel); + } + } +} + +let invalidInstall = { + name: "Test Locale 0", + installMessage: "INSTALLINGTest Locale 0", + continueButton: "CONTINUE", + cancelButton: "CANCEL", + title: "CHOOSELANGUAGE", + installFailed: "CONTINUE", + locale: "en-US", + localeName: "English (US)", + willFail: true +}; +let validInstall = { + name: "Test Locale 1", + installMessage: "INSTALLINGTest Locale 1", + continueButton: "CONTINUE", + cancelButton: "CANCEL", + title: "CHOOSELANGUAGE", + locale: "test1", + localeName: "test1", + willFail: false +} + +gTests.push(new LocaleTest("Load locale picker with no opener and continue", + { opener: null, + loadLocalesList: false, + selectAddon: null + })); + +gTests.push(new LocaleTest("Load locale picker with no opener and try to install an invalid language", + { opener: null, + loadLocalesList: true, + selectAddon: invalidInstall + })); + +gTests.push(new LocaleTest("Load locale picker with no opener and try to install a valid language", + { opener: null, + loadLocalesList: true, + selectAddon: validInstall + })); + +gTests.push(new LocaleTest("Load locale picker with opener and try to install an invalid language", + { opener: this.window, + loadLocalesList: true, + selectAddon: invalidInstall + })); + +gTests.push(new LocaleTest("Load locale picker with opener and try to install a valid language", + { opener: this.window, + loadLocalesList: true, + selectAddon: validInstall + })); diff --git a/mobile/android/chrome/tests/browser_localepicker_escape.js b/mobile/android/chrome/tests/browser_localepicker_escape.js new file mode 100644 index 00000000000..4968d48c050 --- /dev/null +++ b/mobile/android/chrome/tests/browser_localepicker_escape.js @@ -0,0 +1,44 @@ +Components.utils.import("resource://gre/modules/Services.jsm"); + +var gWin; + +function test() { + waitForExplicitFinish(); + gWin = Services.ww.openWindow(window, "chrome://browser/content/localePicker.xul", "_browser", "chrome,dialog=no,all", null); + gWin.addEventListener("load", onload, false); +} + +function onload(aEvent) { + gWin.removeEventListener("load", onload, false); + ok(true, "Locale picker is opened."); + setTimeout(afterLoad, 0); +} + +function afterLoad() { + let ui = gWin.LocaleUI; + is(ui.selectedPanel, ui.pickerpage, "Picker page is selected."); + + ui.selectedPanel = ui.mainPage; + is(ui.selectedPanel, ui.mainPage, "Select the main page."); + sendEscape(); + is(ui.selectedPanel, ui.mainPage, "Main page is still selected (escape key does nothing)."); + + ui.selectedPanel = ui.installerPage; + is(ui.selectedPanel, ui.installerPage, "Select the installer page."); + sendEscape(); + is(ui.selectedPanel, ui.pickerpage, "Escape key goes back to the picker page."); + + gWin.addEventListener("unload", windowClosed, false); + sendEscape(); +} + +function windowClosed() { + gWin.removeEventListener("unload", windowClosed, false); + ok(true, "Locale picker is closed."); + finish(); +} + +function sendEscape() { + info("Sending escape key."); + EventUtils.synthesizeKey("VK_ESCAPE", { type: "keypress" }, gWin); +} diff --git a/mobile/android/chrome/tests/browser_localerepository.js b/mobile/android/chrome/tests/browser_localerepository.js new file mode 100644 index 00000000000..63de102580b --- /dev/null +++ b/mobile/android/chrome/tests/browser_localerepository.js @@ -0,0 +1,39 @@ +var localeList = serverRoot + "locales_list.sjs"; +var PREF_LOCALE_LIST = "extensions.getLocales.get.url"; + +Components.utils.import("resource://gre/modules/Services.jsm"); +Components.utils.import("resource://gre/modules/LocaleRepository.jsm"); + +function test() { + waitForExplicitFinish(); + runNextTest(); +} + +function end_test() { + Services.prefs.clearUserPref(PREF_LOCALE_LIST); +} + +registerCleanupFunction(end_test); + +gTests.push({ + desc: "Test getting a list of compatable locales", + run: function() { + Services.prefs.setCharPref(PREF_LOCALE_LIST, localeList); + LocaleRepository.getLocales(this.listLoaded); + }, + + listLoaded: function(aLocales) { + is(aLocales.length, 1, "Correct number of locales were found"); + isnot(aLocales[0].addon, null, "Locale has an addon"); + is(aLocales[0].xpiURL, "http://www.example.com/browser/mobile/chrome/tests/addons/browser_locale1.xpi", "Locale has correct xpi url"); + is(aLocales[0].xpiHash, null, "Locale has correct hash"); + + is(aLocales[0].addon.id, "langpack-test1@firefox-mobile.mozilla.org", "Locale has correct id"); + is(aLocales[0].addon.name, "Test Locale 1", "Locale has correct name"); + is(aLocales[0].addon.type, "language", "Locale has correct type"); + + is(aLocales[0].addon.targetLocale, "test1", "Locale has correct target locale"); + is(aLocales[0].addon.version, "1.0", "Locale has correct version"); + runNextTest(); + } +}); diff --git a/mobile/android/chrome/tests/browser_localerepository_buildid.js b/mobile/android/chrome/tests/browser_localerepository_buildid.js new file mode 100644 index 00000000000..9a3689c565a --- /dev/null +++ b/mobile/android/chrome/tests/browser_localerepository_buildid.js @@ -0,0 +1,41 @@ +var localeList = serverRoot + "locales_list.sjs"; +var PREF_LOCALE_LIST = "extensions.getLocales.get.url"; + +Components.utils.import("resource://gre/modules/Services.jsm"); +Components.utils.import("resource://gre/modules/LocaleRepository.jsm"); + +function test() { + waitForExplicitFinish(); + runNextTest(); +} + +function end_test() { + Services.prefs.clearUserPref(PREF_LOCALE_LIST); +} + +registerCleanupFunction(end_test); + +gTests.push({ + desc: "Test dynamically changing extensions.getLocales.get.url", + run: function() { + Services.prefs.setCharPref(PREF_LOCALE_LIST, localeList + "?buildid=%BUILDID_EXPANDED%"); + LocaleRepository.getLocales(this.listLoaded.bind(this), {buildID: "00001122334455"}); + }, + + listLoaded: function(aLocales) { + is(aLocales.length, 1, "Correct number of locales were found"); + is(aLocales[0].addon.name, "0000-11-22-33-44-55", "Buildid was correctly replaced"); + + Services.prefs.setCharPref(PREF_LOCALE_LIST, localeList + "?buildid=%BUILDID_EXPANDED%"); + LocaleRepository.getLocales(this.secondListLoaded.bind(this)); + }, + + secondListLoaded: function(aLocales) { + is(aLocales.length, 1, "Correct number of locales were found"); + + let buildID = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).QueryInterface(Ci.nsIXULRuntime).appBuildID; + is(aLocales[0].addon.name.replace(/-/g, ""), buildID, "Buildid was correctly replaced"); + + runNextTest(); + } +}); diff --git a/mobile/android/chrome/tests/browser_localerepository_pref.js b/mobile/android/chrome/tests/browser_localerepository_pref.js new file mode 100644 index 00000000000..bc94c1280fc --- /dev/null +++ b/mobile/android/chrome/tests/browser_localerepository_pref.js @@ -0,0 +1,35 @@ +var localeList = serverRoot + "locales_list.sjs"; +var PREF_LOCALE_LIST = "extensions.getLocales.get.url"; + +Components.utils.import("resource://gre/modules/Services.jsm"); +Components.utils.import("resource://gre/modules/LocaleRepository.jsm"); + +function test() { + waitForExplicitFinish(); + runNextTest(); +} + +function end_test() { + Services.prefs.clearUserPref(PREF_LOCALE_LIST); +} + +registerCleanupFunction(end_test); + +gTests.push({ + desc: "Test dynamically changing extensions.getLocales.get.url", + run: function() { + Services.prefs.setCharPref(PREF_LOCALE_LIST, localeList); + LocaleRepository.getLocales(this.listLoaded.bind(this)); + }, + + listLoaded: function(aLocales) { + is(aLocales.length, 1, "Correct number of locales were found"); + Services.prefs.setCharPref(PREF_LOCALE_LIST, localeList + "?numvalid=2"); + LocaleRepository.getLocales(this.secondListLoaded.bind(this)); + }, + + secondListLoaded: function(aLocales) { + is(aLocales.length, 2, "Correct number of locales were found"); + runNextTest(); + } +}); diff --git a/mobile/android/chrome/tests/browser_mainui.js b/mobile/android/chrome/tests/browser_mainui.js new file mode 100644 index 00000000000..386858ade07 --- /dev/null +++ b/mobile/android/chrome/tests/browser_mainui.js @@ -0,0 +1,27 @@ +// Very basic tests for the main window UI + +const Cc = Components.classes; +const Ci = Components.interfaces; + +//------------------------------------------------------------------------------ +// Entry point (must be named "test") +function test() { + is(window.location.href, "chrome://browser/content/browser.xul", "Main window should be browser.xul"); + + window.focus(); + + let browser = Browser.selectedBrowser; + isnot(browser, null, "Should have a browser"); + + is(browser.currentURI.spec, Browser.selectedTab.browser.currentURI.spec, "selectedBrowser == selectedTab.browser"); + + testContentContainerSize(); +} + +function testContentContainerSize() { + let container = document.getElementById("content-viewport"); + + let rect = container.getBoundingClientRect(); + is(rect.width, window.innerWidth, "Content container is same width as window"); + is(rect.height, window.innerHeight, "Content container is same height as window"); +} diff --git a/mobile/android/chrome/tests/browser_navigation.js b/mobile/android/chrome/tests/browser_navigation.js new file mode 100644 index 00000000000..aa69a0ff761 --- /dev/null +++ b/mobile/android/chrome/tests/browser_navigation.js @@ -0,0 +1,403 @@ +var testURL_01 = chromeRoot + "browser_blank_01.html"; +var testURL_02 = chromeRoot + "browser_blank_02.html"; + +var titleURL = baseURI + "browser_title.sjs?"; +var pngURL = "data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw=="; + +// A queue to order the tests and a handle for each test +var gTests = []; +var gCurrentTest = null; + +var back = document.getElementById("tool-back"); +var forward = document.getElementById("tool-forward"); + +function pageLoaded(aURL) { + return function() { + let tab = gCurrentTest._currentTab; + return !tab.isLoading() && tab.browser.currentURI.spec == aURL; + } +} + +//------------------------------------------------------------------------------ +// Entry point (must be named "test") +function test() { + // The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()" + // We call "finish()" when the tests are finished + waitForExplicitFinish(); + // Start the tests + runNextTest(); +} + +function waitForPageShow(aPageURL, aCallback) { + messageManager.addMessageListener("pageshow", function(aMessage) { + if (aMessage.target.currentURI.spec == aPageURL) { + messageManager.removeMessageListener("pageshow", arguments.callee); + setTimeout(function() { aCallback(); }, 0); + } + }); +}; + +//------------------------------------------------------------------------------ +// Iterating tests by shifting test out one by one as runNextTest is called. +function runNextTest() { + // Run the next test until all tests completed + if (gTests.length > 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + gCurrentTest.run(); + } + else { + // Cleanup. All tests are completed at this point + try { + // Add any cleanup code here + } + finally { + // We must finialize the tests + finish(); + } + } +} + +//------------------------------------------------------------------------------ +// Case: Loading a page into the URLBar with VK_RETURN +gTests.push({ + desc: "Loading a page into the URLBar with VK_RETURN", + _currentTab: null, + + run: function() { + gCurrentTest._currentTab = BrowserUI.newTab(testURL_01); + + // Wait for the tab to load, then do the test + waitFor(gCurrentTest.onPageReady, pageLoaded(testURL_01)); + }, + + onPageReady: function() { + // Test the mode + let urlIcons = document.getElementById("urlbar-icons"); + is(urlIcons.getAttribute("mode"), "view", "URL Mode is set to 'view'"); + + // Test back button state + is(back.disabled, !gCurrentTest._currentTab.browser.canGoBack, "Back button check"); + + // Test forward button state + is(forward.disabled, !gCurrentTest._currentTab.browser.canGoForward, "Forward button check"); + + // Focus the url edit + let urlbarTitle = document.getElementById("urlbar-title"); + + // Wait for the awesomebar to load, then do the test + window.addEventListener("NavigationPanelShown", function() { + window.removeEventListener("NavigationPanelShown", arguments.callee, false); + setTimeout(gCurrentTest.onFocusReady, 0); + }, false); + EventUtils.synthesizeMouse(urlbarTitle, urlbarTitle.width / 2, urlbarTitle.height / 2, {}); + }, + + onFocusReady: function() { + // Test mode + let urlIcons = document.getElementById("urlbar-icons"); + is(urlIcons.getAttribute("mode"), "edit", "URL Mode is set to 'edit'"); + + // Test back button state + is(back.disabled, !gCurrentTest._currentTab.browser.canGoBack, "Back button check"); + + // Test forward button state + is(forward.disabled, !gCurrentTest._currentTab.browser.canGoForward, "Forward button check"); + + // Check button states (url edit is focused) + let search = document.getElementById("tool-search"); + let searchStyle = window.getComputedStyle(search, null); + is(searchStyle.visibility, "visible", "SEARCH is visible"); + + let stop = document.getElementById("tool-stop"); + let stopStyle = window.getComputedStyle(stop, null); + is(stopStyle.visibility, "collapse", "STOP is hidden"); + + let reload = document.getElementById("tool-reload"); + let reloadStyle = window.getComputedStyle(reload, null); + is(reloadStyle.visibility, "collapse", "RELOAD is hidden"); + + // Send the string and press return + EventUtils.synthesizeString(testURL_02, window); + + // It looks like there is a race condition somewhere that result having + // testURL_01 concatenate with testURL_02 as a urlbar value, so to + // workaround that we're waiting for the readonly state to be fully updated + function URLIsReadWrite() { + return BrowserUI._edit.readOnly == false; + } + + waitFor(function() { + // Wait for the tab to load, then do the test + waitFor(gCurrentTest.onPageFinish, pageLoaded(testURL_02)); + + setTimeout(function() { + is(BrowserUI._edit.value, testURL_02, "URL value should be equal to the string sent via synthesizeString"); + EventUtils.synthesizeKey("VK_RETURN", {}, window); + }, 0); + }, URLIsReadWrite); + }, + + onPageFinish: function() { + let urlIcons = document.getElementById("urlbar-icons"); + is(urlIcons.getAttribute("mode"), "view", "URL Mode is set to 'view'"); + + // Check button states (url edit is not focused) + let search = document.getElementById("tool-search"); + let searchStyle = window.getComputedStyle(search, null); + is(searchStyle.visibility, "collapse", "SEARCH is hidden"); + + let stop = document.getElementById("tool-stop"); + let stopStyle = window.getComputedStyle(stop, null); + is(stopStyle.visibility, "collapse", "STOP is hidden"); + + let reload = document.getElementById("tool-reload"); + let reloadStyle = window.getComputedStyle(reload, null); + is(reloadStyle.visibility, "visible", "RELOAD is visible"); + + let uri = gCurrentTest._currentTab.browser.currentURI.spec; + is(uri, testURL_02, "URL Matches newly created Tab"); + + // Go back in session + gCurrentTest._currentTab.browser.goBack(); + + // Wait for the tab to load, then do the test + waitFor(gCurrentTest.onPageBack, pageLoaded(testURL_01)); + }, + + onPageBack: function() { + // Test back button state + is(back.disabled, !gCurrentTest._currentTab.browser.canGoBack, "Back button check"); + + // Test forward button state + is(forward.disabled, !gCurrentTest._currentTab.browser.canGoForward, "Forward button check"); + + BrowserUI.closeTab(gCurrentTest._currentTab); + runNextTest(); + } +}); + +// Bug 611327 ----------------------------------------------------------------- +// Check for urlbar label value +gTests.push({ + desc: "Check for urlbar label value on different cases", + _currentTab: null, + + run: function() { + gCurrentTest._currentTab = BrowserUI.newTab(titleURL + "no_title"); + waitForPageShow(titleURL + "no_title", gCurrentTest.onPageLoadWithoutTitle); + }, + + onPageLoadWithoutTitle: function() { + let urlbarTitle = document.getElementById("urlbar-title"); + is(urlbarTitle.value, titleURL + "no_title", "The title should be equal to the URL"); + + BrowserUI.closeTab(gCurrentTest._currentTab); + + gCurrentTest._currentTab = BrowserUI.newTab(titleURL + "english_title"); + waitForPageShow(titleURL + "english_title", gCurrentTest.onPageLoadWithTitle); + }, + + onPageLoadWithTitle: function() { + let urlbarTitle = document.getElementById("urlbar-title"); + is(urlbarTitle.value, "English Title Page", "The title should be equal to the page title"); + + BrowserUI.closeTab(gCurrentTest._currentTab); + + gCurrentTest._currentTab = BrowserUI.newTab(titleURL + "dynamic_title"); + messageManager.addMessageListener("pageshow", function(aMessage) { + messageManager.removeMessageListener("pageshow", arguments.callee); + gCurrentTest.onBeforePageTitleChanged(); + }); + + messageManager.addMessageListener("DOMTitleChanged", function(aMessage) { + messageManager.removeMessageListener("DOMTitleChanged", arguments.callee); + urlbarTitle.addEventListener("DOMAttrModified", function(aEvent) { + if (aEvent.attrName == "value") { + urlbarTitle.removeEventListener("DOMAttrModified", arguments.callee, false); + setTimeout(gCurrentTest.onPageTitleChanged, 0); + } + }, false); + }); + }, + + onBeforePageTitleChanged: function() { + let urlbarTitle = document.getElementById("urlbar-title"); + isnot(urlbarTitle.value, "This is not a french title", "The title should not be equal to the new page title yet"); + }, + + onPageTitleChanged: function() { + let urlbarTitle = document.getElementById("urlbar-title"); + is(urlbarTitle.value, "This is not a french title", "The title should be equal to the new page title"); + + BrowserUI.closeTab(gCurrentTest._currentTab); + + gCurrentTest._currentTab = BrowserUI.newTab(titleURL + "redirect"); + waitForPageShow(titleURL + "no_title", gCurrentTest.onPageRedirect); + }, + + onPageRedirect: function() { + let urlbarTitle = document.getElementById("urlbar-title"); + is(urlbarTitle.value, gCurrentTest._currentTab.browser.currentURI.spec, "The title should be equal to the redirected page url"); + + BrowserUI.closeTab(gCurrentTest._currentTab); + + gCurrentTest._currentTab = BrowserUI.newTab(titleURL + "location"); + waitForPageShow(titleURL + "no_title", gCurrentTest.onPageLocation); + }, + + onPageLocation: function() { + let urlbarTitle = document.getElementById("urlbar-title"); + is(urlbarTitle.value, gCurrentTest._currentTab.browser.currentURI.spec, "The title should be equal to the relocate page url"); + + BrowserUI.closeTab(gCurrentTest._currentTab); + + // Wait for the awesomebar to load, then do the test + window.addEventListener("NavigationPanelShown", function() { + window.removeEventListener("NavigationPanelShown", arguments.callee, false); + + setTimeout(function() { + EventUtils.synthesizeString(testURL_02, window); + EventUtils.synthesizeKey("VK_RETURN", {}, window); + + waitForPageShow(testURL_02, gCurrentTest.onUserTypedValue); + }, 0); + + }, false); + + gCurrentTest._currentTab = BrowserUI.newTab("about:blank"); + }, + + onUserTypedValue: function() { + let urlbarTitle = document.getElementById("urlbar-title"); + is(urlbarTitle.value, "Browser Blank Page 02", "The title should be equal to the typed page url title"); + + // about:blank has been closed, so we need to close the last selected one + BrowserUI.closeTab(Browser.selectedTab); + + // Wait for the awesomebar to load, then do the test + window.addEventListener("NavigationPanelShown", function() { + window.removeEventListener("NavigationPanelShown", arguments.callee, false); + + EventUtils.synthesizeString("no_title", window); + + // Wait until the no_title result row is here + let popup = document.getElementById("popup_autocomplete"); + let result = null; + function hasResults() { + result = popup._items.childNodes[0]; + if (result) + return result.getAttribute("value") == (titleURL + "no_title"); + + return false; + }; + waitFor(function() { EventUtils.synthesizeMouse(result, result.width / 2, result.height / 2, {}); }, hasResults); + + urlbarTitle.addEventListener("DOMAttrModified", function(aEvent) { + if (aEvent.attrName == "value") { + urlbarTitle.removeEventListener("DOMAttrModified", arguments.callee, false); + is(urlbarTitle.value, titleURL + "no_title", "The title should be equal to the url of the clicked row"); + } + }, false); + + waitForPageShow(titleURL + "no_title", gCurrentTest.onUserSelectValue); + }, false); + + gCurrentTest._currentTab = BrowserUI.newTab("about:blank"); + }, + + onUserSelectValue: function() { + let urlbarTitle = document.getElementById("urlbar-title"); + is(urlbarTitle.value, Browser.selectedTab.browser.currentURI.spec, "The title should be equal to the clicked page url"); + + // about:blank has been closed, so we need to close the last selected one + BrowserUI.closeTab(Browser.selectedTab); + + //is(urlbarTitle.value, "Browser Blank Page 02", "The title of the second page must be displayed"); + runNextTest(); + } +}); + +// Case: Check for appearance of the favicon +gTests.push({ + desc: "Check for appearance of the favicon", + _currentTab: null, + + run: function() { + gCurrentTest._currentTab = BrowserUI.newTab(testURL_01); + waitForPageShow(testURL_01, gCurrentTest.onPageReady); + }, + + onPageReady: function() { + let favicon = document.getElementById("urlbar-favicon"); + is(favicon.src, "", "The default favicon must be loaded"); + BrowserUI.closeTab(gCurrentTest._currentTab); + + gCurrentTest._currentTab = BrowserUI.newTab(testURL_02); + waitForPageShow(testURL_02, gCurrentTest.onPageFinish); + }, + + onPageFinish: function(){ + let favicon = document.getElementById("urlbar-favicon"); + is(favicon.src, pngURL, "The page favicon must be loaded"); + BrowserUI.closeTab(gCurrentTest._currentTab); + runNextTest(); + } +}); + +// Bug 600707 - Back and forward buttons are updated when navigating within a page +// +// These tests use setTimeout instead of waitFor or addEventListener, because +// in-page navigation does not fire any loading events or progress +// notifications, and happens more or less instantly. +gTests.push({ + desc: "Navigating within a page via URI fragments", + _currentTab: null, + + run: function() { + gCurrentTest._currentTab = BrowserUI.newTab(testURL_01); + waitFor(gCurrentTest.onPageReady, pageLoaded(testURL_01)); + }, + + onPageReady: function() { + ok(back.disabled, "Can't go back"); + ok(forward.disabled, "Can't go forward"); + + messageManager.addMessageListener("Content:LocationChange", gCurrentTest.onFragmentLoaded); + Browser.loadURI(testURL_01 + "#fragment"); + }, + + onFragmentLoaded: function() { + messageManager.removeMessageListener("Content:LocationChange", arguments.callee); + + ok(!back.disabled, "Can go back"); + ok(forward.disabled, "Can't go forward"); + + messageManager.addMessageListener("Content:LocationChange", gCurrentTest.onBack); + CommandUpdater.doCommand("cmd_back"); + }, + + onBack: function() { + messageManager.removeMessageListener("Content:LocationChange", arguments.callee); + + ok(back.disabled, "Can't go back"); + ok(!forward.disabled, "Can go forward"); + + messageManager.addMessageListener("Content:LocationChange", gCurrentTest.onForward); + CommandUpdater.doCommand("cmd_forward"); + }, + + onForward: function() { + messageManager.removeMessageListener("Content:LocationChange", arguments.callee); + + ok(!back.disabled, "Can go back"); + ok(forward.disabled, "Can't go forward"); + + gCurrentTest.finish(); + }, + + finish: function() { + BrowserUI.closeTab(gCurrentTest._currentTab); + runNextTest(); + } +}); diff --git a/mobile/android/chrome/tests/browser_preferences_fulltoggle.js b/mobile/android/chrome/tests/browser_preferences_fulltoggle.js new file mode 100644 index 00000000000..9ce68fbe22f --- /dev/null +++ b/mobile/android/chrome/tests/browser_preferences_fulltoggle.js @@ -0,0 +1,67 @@ +// browser-chrome test for fennec preferences to toggle values while clicking on the preference name + +var gTests = []; +var gCurrentTest = null; + +function test() { + // The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()" + // We call "finish()" when the tests are finished + waitForExplicitFinish(); + + // Start the tests + runNextTest(); +} +//------------------------------------------------------------------------------ +// Iterating tests by shifting test out one by one as runNextTest is called. +function runNextTest() { + // Run the next test until all tests completed + if (gTests.length > 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + gCurrentTest.run(); + } + else { + // Cleanup. All tests are completed at this point + finish(); + } +} + +// ----------------------------------------------------------------------------------------- +// Verify preferences and text +gTests.push({ + desc: "Verify full toggle on Preferences", + + run: function(){ + // 1.Click preferences to view prefs + document.getElementById("tool-panel-open").click(); + is(document.getElementById("panel-container").hidden, false, "Preferences should be visible"); + + var contentRegion = document.getElementById("prefs-content"); + + // Check for *Show images* + var imageRegion = document.getAnonymousElementByAttribute(contentRegion, "pref", "permissions.default.image"); + var imageValue = imageRegion.value; + var imageTitle = document.getAnonymousElementByAttribute(imageRegion, "class", "preferences-title"); + var imageButton = document.getAnonymousElementByAttribute(imageRegion, "anonid", "input"); + + var ibEvent = document.createEvent("MouseEvents"); + ibEvent.initEvent("TapSingle", true, false); + imageButton.dispatchEvent(ibEvent); + is(imageRegion.value, !imageValue, "Tapping on input control should change the value"); + + var itEvent = document.createEvent("MouseEvents"); + itEvent.initEvent("TapSingle", true, false); + imageTitle.dispatchEvent(itEvent); + is(imageRegion.value, imageValue, "Tapping on the title should change the value"); + + var irEvent = document.createEvent("MouseEvents"); + irEvent.initEvent("TapSingle", true, false); + imageRegion.dispatchEvent(irEvent); + is(imageRegion.value, !imageValue, "Tapping on the setting should change the value"); + + BrowserUI.hidePanel(); + is(document.getElementById("panel-container").hidden, true, "Preferences panel should be closed"); + runNextTest(); + } +}); + diff --git a/mobile/android/chrome/tests/browser_preferences_text.js b/mobile/android/chrome/tests/browser_preferences_text.js new file mode 100644 index 00000000000..de21f56fd5e --- /dev/null +++ b/mobile/android/chrome/tests/browser_preferences_text.js @@ -0,0 +1,131 @@ +// Bug 571866 - --browser-chrome test for fennec preferences and text values + +var gTests = []; +var gCurrentTest = null; +var expected = { + "aboutButton": {"tagName": "button", "element_id": "prefs-about-button"}, + "homepage": {"element_id": "prefs-homepage", + "home_page": "prefs-homepage-default", + "blank_page": "prefs-homepage-none", + "current_page": "prefs-homepage-currentpage"}, + "doneButton": {"tagName": "button"}, + "contentRegion": {"element_id": "prefs-content"}, + "imageRegion": {"pref": "permissions.default.image", "anonid": "input", "localName": "checkbox"}, + "jsRegion": {"pref": "javascript.enabled", "anonid": "input", "localName": "checkbox"}, + "privacyRegion": {"element_id": "prefs-privacy" }, + "cookiesRegion": {"pref": "network.cookie.cookieBehavior", "anonid": "input", "localName": "checkbox"}, + "passwordsRegion": {"pref": "signon.rememberSignons", "anonid": "input", "localName": "checkbox"}, + "clearDataButton": {"element_id": "prefs-clear-data", "tagName": "button"} +}; + +function getPreferencesElements() { + let prefElements = {}; + prefElements.panelOpen = document.getElementById("tool-panel-open"); + prefElements.panelContainer = document.getElementById("panel-container"); + prefElements.homeButton = document.getElementById("prefs-homepage-options"); + prefElements.doneButton = document.getElementById("select-buttons-done"); + prefElements.homePageControl = document.getElementById("prefs-homepage"); + prefElements.selectContainer = document.getElementById("menulist-container"); + return prefElements; +} + +function test() { + // The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()" + // We call "finish()" when the tests are finished + waitForExplicitFinish(); + + // Start the tests + runNextTest(); +} +//------------------------------------------------------------------------------ +// Iterating tests by shifting test out one by one as runNextTest is called. +function runNextTest() { + // Run the next test until all tests completed + if (gTests.length > 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + gCurrentTest.run(); + } + else { + // Cleanup. All tests are completed at this point + finish(); + } +} + +// ----------------------------------------------------------------------------------------- +// Verify preferences and text +gTests.push({ + desc: "Verify Preferences and Text", + + run: function(){ + var prefs = getPreferencesElements(); + // 1.Click preferences to view prefs + prefs.panelOpen.click(); + + // 2. For each prefs *verify text *the button/option type *verify height of each field to be the same + is(prefs.panelContainer.hidden, false, "Preferences should be visible"); + + var prefsList = document.getElementById("prefs-messages"); + + // Check for *About page* + let about = expected.aboutButton; + var aboutRegion = document.getAnonymousElementByAttribute(prefsList, "title", "About Fennec"); + var aboutButton = document.getElementById(about.element_id); + is(aboutButton.tagName, about.tagName, "The About Fennec input must be a button"); + + // Check for *Startpage* + let homepage = expected.homepage; + var homepageRegion = document.getElementById(homepage.element_id); + prefs.homeButton.click(); + + is(prefs.selectContainer.hidden, false, "Homepage select dialog must be visible"); + + EventUtils.synthesizeKey("VK_ESCAPE", {}, window); + is(prefs.selectContainer.hidden, true, "Homepage select dialog must be closed"); + + let content = expected.contentRegion; + var contentRegion = document.getElementById(content.element_id); + + // Check for *Show images* + var images = expected.imageRegion; + var imageRegion = document.getAnonymousElementByAttribute(contentRegion, "pref", images.pref); + var imageButton = document.getAnonymousElementByAttribute(imageRegion, "anonid", images.anonid); + is(imageButton.localName, images.localName, "Show images checkbox check"); + // Checkbox or radiobutton? + + // Check for *Enable javascript* + let js = expected.jsRegion; + var jsRegion = document.getAnonymousElementByAttribute(contentRegion, "pref", js.pref); + var jsButton = document.getAnonymousElementByAttribute(jsRegion, "anonid", js.anonid); + is(jsButton.localName, js.localName, "Enable JavaScript checkbox check"); + // Checkbox or radiobutton? + + let privacyRegion = expected.privacyRegion; + var prefsPrivacy = document.getElementById(privacyRegion.element_id); + + // Check for *Allow cookies* + let cookies = expected.cookiesRegion; + var cookiesRegion = document.getAnonymousElementByAttribute(prefsPrivacy, "pref", cookies.pref); + var cookiesButton = document.getAnonymousElementByAttribute(cookiesRegion, "anonid", cookies.anonid); + is(cookiesButton.localName, cookies.localName, "Allow cookies checkbox check"); + // Checkbox or radiobutton? + + // Check for *Remember password* + let passwords = expected.passwordsRegion; + var passwordsRegion = document.getAnonymousElementByAttribute(prefsPrivacy, "pref", passwords.pref); + var passwordsButton = document.getAnonymousElementByAttribute(passwordsRegion, "anonid", passwords.anonid); + is(passwordsButton.localName, passwords.localName, "Allow cookies checkbox check"); + // Checkbox or radiobutton? + + // Check for *Clear Private Data* + let clearData = expected.clearDataButton; + var clearDataRegion = prefsPrivacy.lastChild; + var clearDataButton = document.getElementById(clearData.element_id); + is(clearDataButton.tagName, clearData.tagName, "Check for Clear Private Data button type"); + + BrowserUI.hidePanel(); + is(document.getElementById("panel-container").hidden, true, "Preferences panel should be closed"); + runNextTest(); + } +}); + diff --git a/mobile/android/chrome/tests/browser_rect.js b/mobile/android/chrome/tests/browser_rect.js new file mode 100644 index 00000000000..fb8be8cc4d2 --- /dev/null +++ b/mobile/android/chrome/tests/browser_rect.js @@ -0,0 +1,107 @@ +function test() { + waitForExplicitFinish(); + + ok(Rect, "Rect class exists"); + + for (let test in tests) { + tests[test](); + } + + finish(); +} + +let tests = { + testGetDimensions: function() { + let r = new Rect(5, 10, 100, 50); + ok(r.left == 5, "rect has correct left value"); + ok(r.top == 10, "rect has correct top value"); + ok(r.right == 105, "rect has correct right value"); + ok(r.bottom == 60, "rect has correct bottom value"); + ok(r.width == 100, "rect has correct width value"); + ok(r.height == 50, "rect has correct height value"); + ok(r.x == 5, "rect has correct x value"); + ok(r.y == 10, "rect has correct y value"); + }, + + testIsEmpty: function() { + let r = new Rect(0, 0, 0, 10); + ok(r.isEmpty(), "rect with nonpositive width is empty"); + let r = new Rect(0, 0, 10, 0); + ok(r.isEmpty(), "rect with nonpositive height is empty"); + let r = new Rect(0, 0, 10, 10); + ok(!r.isEmpty(), "rect with positive dimensions is not empty"); + }, + + testRestrictTo: function() { + let r1 = new Rect(10, 10, 100, 100); + let r2 = new Rect(50, 50, 100, 100); + r1.restrictTo(r2); + ok(r1.equals(new Rect(50, 50, 60, 60)), "intersection is non-empty"); + + let r1 = new Rect(10, 10, 100, 100); + let r2 = new Rect(120, 120, 100, 100); + r1.restrictTo(r2); + ok(r1.isEmpty(), "intersection is empty"); + + let r1 = new Rect(10, 10, 100, 100); + let r2 = new Rect(0, 0, 0, 0); + r1.restrictTo(r2); + ok(r1.isEmpty(), "intersection of rect and empty is empty"); + + let r1 = new Rect(0, 0, 0, 0); + let r2 = new Rect(0, 0, 0, 0); + r1.restrictTo(r2); + ok(r1.isEmpty(), "intersection of empty and empty is empty"); + }, + + testExpandToContain: function() { + let r1 = new Rect(10, 10, 100, 100); + let r2 = new Rect(50, 50, 100, 100); + r1.expandToContain(r2); + ok(r1.equals(new Rect(10, 10, 140, 140)), "correct expandToContain on intersecting rectangles"); + + let r1 = new Rect(10, 10, 100, 100); + let r2 = new Rect(120, 120, 100, 100); + r1.expandToContain(r2); + ok(r1.equals(new Rect(10, 10, 210, 210)), "correct expandToContain on non-intersecting rectangles"); + + let r1 = new Rect(10, 10, 100, 100); + let r2 = new Rect(0, 0, 0, 0); + r1.expandToContain(r2); + ok(r1.equals(new Rect(10, 10, 100, 100)), "expandToContain of rect and empty is rect"); + + let r1 = new Rect(10, 10, 0, 0); + let r2 = new Rect(0, 0, 0, 0); + r1.expandToContain(r2); + ok(r1.isEmpty(), "expandToContain of empty and empty is empty"); + }, + + testSubtract: function testSubtract() { + function equals(rects1, rects2) { + return rects1.length == rects2.length && rects1.every(function(r, i) { + return r.equals(rects2[i]); + }); + } + + let r1 = new Rect(0, 0, 100, 100); + let r2 = new Rect(500, 500, 100, 100); + ok(equals(r1.subtract(r2), [r1]), "subtract area outside of region yields same region"); + + let r1 = new Rect(0, 0, 100, 100); + let r2 = new Rect(-10, -10, 50, 120); + ok(equals(r1.subtract(r2), [new Rect(40, 0, 60, 100)]), "subtracting vertical bar from edge leaves one rect"); + + let r1 = new Rect(0, 0, 100, 100); + let r2 = new Rect(-10, -10, 120, 50); + ok(equals(r1.subtract(r2), [new Rect(0, 40, 100, 60)]), "subtracting horizontal bar from edge leaves one rect"); + + let r1 = new Rect(0, 0, 100, 100); + let r2 = new Rect(40, 40, 20, 20); + ok(equals(r1.subtract(r2), [ + new Rect(0, 0, 40, 100), + new Rect(40, 0, 20, 40), + new Rect(40, 60, 20, 40), + new Rect(60, 0, 40, 100)]), + "subtracting rect in middle leaves union of rects"); + }, +}; diff --git a/mobile/android/chrome/tests/browser_rememberPassword.js b/mobile/android/chrome/tests/browser_rememberPassword.js new file mode 100644 index 00000000000..f2708a4b16e --- /dev/null +++ b/mobile/android/chrome/tests/browser_rememberPassword.js @@ -0,0 +1,60 @@ +var testURL_01 = chromeRoot + "browser_blank_01.html"; + +// Tests for the Remember Password UI + +let gCurrentTab = null; +function test() { + waitForExplicitFinish(); + + messageManager.addMessageListener("pageshow", function() { + if (gCurrentTab.browser.currentURI.spec == testURL_01) { + messageManager.removeMessageListener("pageshow", arguments.callee); + pageLoaded(); + } + }); + + gCurrentTab = Browser.addTab(testURL_01, true); +} + +function pageLoaded() { + let iHandler = getIdentityHandler(); + let iPassword = document.getElementById("pageaction-password"); + let lm = getLoginManager(); + let host = gCurrentTab.browser.currentURI.prePath; + let nullSubmit = createLogin(host, host, null); + let nullForm = createLogin(host, null, "realm"); + + lm.removeAllLogins(); + + iHandler.show(); + is(iPassword.hidden, true, "Remember password hidden for no logins"); + iHandler.hide(); + + lm.addLogin(nullSubmit); + iHandler.show(); + is(iPassword.hidden, false, "Remember password shown for form logins"); + iPassword.click(); + is(iPassword.hidden, true, "Remember password hidden after click"); + is(lm.countLogins(host, "", null), 0, "Logins deleted when clicked"); + iHandler.hide(); + + lm.addLogin(nullForm); + iHandler.show(); + is(iPassword.hidden, false, "Remember password shown for protocol logins"); + iPassword.click(); + is(iPassword.hidden, true, "Remember password hidden after click"); + is(lm.countLogins(host, null, ""), 0, "Logins deleted when clicked"); + iHandler.hide(); + + Browser.closeTab(gCurrentTab); + finish(); +} + +function getLoginManager() { + return Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager); +} + +function createLogin(aHostname, aFormSubmitURL, aRealm) { + let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Components.interfaces.nsILoginInfo, "init"); + return new nsLoginInfo(aHostname, aFormSubmitURL, aRealm, "username", "password", "uname", "pword"); +} diff --git a/mobile/android/chrome/tests/browser_scroll.html b/mobile/android/chrome/tests/browser_scroll.html new file mode 100644 index 00000000000..e0f816a9617 --- /dev/null +++ b/mobile/android/chrome/tests/browser_scroll.html @@ -0,0 +1,16 @@ + + + + scrollTo test + + + + +

scrollTo test

+

The urlbar should scroll out of view after this page loads.

+ + diff --git a/mobile/android/chrome/tests/browser_scroll.js b/mobile/android/chrome/tests/browser_scroll.js new file mode 100644 index 00000000000..5445280589b --- /dev/null +++ b/mobile/android/chrome/tests/browser_scroll.js @@ -0,0 +1,19 @@ +// Test behavior of window.scrollTo during page load (bug 654122). +"use strict"; + +var gTab; +registerCleanupFunction(function() Browser.closeTab(gTab)); + +const TEST_URL = baseURI + "browser_scroll.html"; + +function test() { + waitForExplicitFinish(); + gTab = Browser.addTab(TEST_URL, true); + onMessageOnce(gTab.browser.messageManager, "Browser:FirstPaint", function() { + executeSoon(function() { + let rect = Elements.browsers.getBoundingClientRect(); + is(rect.top, 0, "Titlebar is hidden."); + finish(); + }); + }); +} diff --git a/mobile/android/chrome/tests/browser_scrollbar.js b/mobile/android/chrome/tests/browser_scrollbar.js new file mode 100644 index 00000000000..008d43c35f9 --- /dev/null +++ b/mobile/android/chrome/tests/browser_scrollbar.js @@ -0,0 +1,179 @@ +let testURL_01 = baseURI + "browser_scrollbar.sjs?"; + +let gCurrentTest = null; +let gTests = []; +let gOpenedTabs = []; // for cleanup + +//------------------------------------------------------------------------------ +// Iterating tests by shifting test out one by one as runNextTest is called. +function runNextTest() { + // Run the next test until all tests completed + if (gTests.length > 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + gCurrentTest.run(); + } + else { + // Close the awesome panel just in case + AwesomeScreen.activePanel = null; + finish(); + } +} + +function waitForPageShow(aPageURL, aCallback) { + messageManager.addMessageListener("pageshow", function(aMessage) { + if (aMessage.target.currentURI.spec == aPageURL) { + messageManager.removeMessageListener("pageshow", arguments.callee); + + setTimeout(aCallback, 0); + } + }); +}; + +//------------------------------------------------------------------------------ +// Entry point (must be named "test") +function test() { + // This test is async + waitForExplicitFinish(); + runNextTest(); +} + +let horizontalScrollbar = document.getElementById("horizontal-scroller"); +let verticalScrollbar = document.getElementById("vertical-scroller"); + +function checkScrollbars(aHorizontalVisible, aVerticalVisible, aHorizontalPosition, aVerticalPosition) { + let browser = getBrowser(); + let width = browser.getBoundingClientRect().width; + let height = browser.getBoundingClientRect().height; + EventUtils.synthesizeMouse(browser, width / 2, height / 4, { type: "mousedown" }); + EventUtils.synthesizeMouse(browser, width / 2, height * 3 / 4, { type: "mousemove" }); + + let horizontalVisible = horizontalScrollbar.hasAttribute("panning"), + verticalVisible = verticalScrollbar.hasAttribute("panning"); + is(horizontalVisible, aHorizontalVisible, "The horizontal scrollbar should be " + (aHorizontalVisible ? "visible" : "hidden")); + is(verticalVisible, aVerticalVisible, "The vertical scrollbar should be " + (aVerticalVisible ? "visible" : "hidden")); + + EventUtils.synthesizeMouse(browser, width / 2, height * 3 / 4, { type: "mouseup" }); +} + +function checkScrollbarsPosition(aX) { + let browser = getBrowser(); + let width = browser.getBoundingClientRect().width; + let height = browser.getBoundingClientRect().height; + EventUtils.synthesizeMouse(browser, width / 2, height / 4, { type: "mousedown" }); + EventUtils.synthesizeMouse(browser, width / 2, height * 3 / 4, { type: "mousemove" }); + + let verticalRect = verticalScrollbar.getBoundingClientRect(); + let margin = parseInt(verticalScrollbar.getAttribute("end")); + let expectedPosition = window.innerWidth - aX - margin; + is(verticalRect.right, expectedPosition, "The vertical scrollbar should be position to " + expectedPosition + " (got " + verticalRect.right + ")"); + + EventUtils.synthesizeMouse(browser, width / 2, height * 3 / 4, { type: "mouseup" }); +} + +gTests.push({ + desc: "Testing visibility of scrollbars", + + run: function() { + waitForPageShow(testURL_01 + "blank", gCurrentTest.checkNotScrollable); + gOpenedTabs.push(Browser.addTab(testURL_01 + "blank", true)); + }, + + checkNotScrollable: function() { + checkScrollbars(false, false); + + waitForPageShow(testURL_01 + "horizontal", gCurrentTest.checkHorizontalScrollable); + gOpenedTabs.push(Browser.addTab(testURL_01 + "horizontal", true)); + }, + + checkHorizontalScrollable: function() { + checkScrollbars(true, false); + + waitForPageShow(testURL_01 + "vertical", gCurrentTest.checkVerticalScrollable); + gOpenedTabs.push(Browser.addTab(testURL_01 + "vertical", true)); + }, + + checkVerticalScrollable: function() { + checkScrollbars(false, true); + + waitForPageShow(testURL_01 + "both", gCurrentTest.checkBothScrollable); + gOpenedTabs.push(Browser.addTab(testURL_01 + "both", true)); + }, + + checkBothScrollable: function() { + checkScrollbars(true, true); + Elements.browsers.addEventListener("PanFinished", function(aEvent) { + Elements.browsers.removeEventListener("PanFinished", arguments.callee, false); + setTimeout(function() { + Browser.hideSidebars(); + }, 0); + runNextTest(); + }, false); + } +}); + +gTests.push({ + desc: "Testing position of scrollbars", + + run: function() { + waitForPageShow(testURL_01 + "vertical", gCurrentTest.checkScrollbarsPosition); + gOpenedTabs.push(Browser.addTab(testURL_01 + "vertical", true)); + }, + + checkScrollbarsPosition: function() { + let [,, tabsWidth, controlsWidth] = Browser.computeSidebarVisibility(); + + checkScrollbarsPosition(0); + + // Show the left sidebar and ensure scrollbar is visible + Browser.controlsScrollboxScroller.scrollTo(0, 0); + checkScrollbarsPosition(-tabsWidth); + + // Show the right sidebar and ensure scrollbar is visible + Browser.controlsScrollboxScroller.scrollTo(tabsWidth + controlsWidth, 0); + checkScrollbarsPosition(controlsWidth); + + gCurrentTest.finish(); + }, + + finish: function() { + Elements.browsers.addEventListener("PanFinished", function(aEvent) { + Elements.browsers.removeEventListener("PanFinished", arguments.callee, false); + setTimeout(function() { + Browser.hideSidebars(); + }, 0); + runNextTest(); + }, false); + } +}); + + +gTests.push({ + desc: "Check scrollbar visibility when the touch sequence is cancelled", + + run: function() { + waitForPageShow(testURL_01 + "both", gCurrentTest.checkVisibility); + gOpenedTabs.push(Browser.addTab(testURL_01 + "both", true)); + }, + + checkVisibility: function() { + let browser = getBrowser(); + let width = browser.getBoundingClientRect().width; + let height = browser.getBoundingClientRect().height; + EventUtils.synthesizeMouse(browser, width / 2, height / 4, { type: "mousedown" }); + EventUtils.synthesizeMouse(browser, width / 2, height * 3 / 4, { type: "mousemove" }); + + let event = document.createEvent("Events"); + event.initEvent("CancelTouchSequence", true, false); + document.dispatchEvent(event); + + let horizontalVisible = horizontalScrollbar.hasAttribute("panning"), + verticalVisible = verticalScrollbar.hasAttribute("panning"); + is(horizontalVisible, false, "The horizontal scrollbar should be hidden when a canceltouchsequence is fired"); + is(verticalVisible, false, "The vertical scrollbar should be hidden should be hidden when a canceltouchsequence is called"); + + for (let iTab=0; iTab"); + response.write(""); + + let body = "" + query + ""; + switch (query) { + case "blank": + response.write("This is a not a scrollable page"); + break; + case "horizontal": + response.write("This is a horizontally scrollable page"); + body += "\n
Browser scrollbar test
"; + break; + case "vertical": + response.write("This is a vertically scrollable page"); + body += "\n
Browser scrollbar test
"; + break; + case "both": + response.write("This is a scrollable page in both directions"); + body += "\n
Browser scrollbar test
"; + break; + default: + break; + } + response.write("" + body + ""); +} diff --git a/mobile/android/chrome/tests/browser_select.html b/mobile/android/chrome/tests/browser_select.html new file mode 100644 index 00000000000..4de8ead4e20 --- /dev/null +++ b/mobile/android/chrome/tests/browser_select.html @@ -0,0 +1,99 @@ + +Browser Blank Page 01 + + + +
+ onchange: (selectedIndex) [value] +
+ - +
+ + + +
+
+ + +
+ onchange: (selectedIndex) [value] +
+ - +
+
+ + +
+
+ +
OptGroup Combobox:
+ +
+
+ + +
+ +

+
+
+
diff --git a/mobile/android/chrome/tests/browser_select.js b/mobile/android/chrome/tests/browser_select.js
new file mode 100644
index 00000000000..f9aca619ccc
--- /dev/null
+++ b/mobile/android/chrome/tests/browser_select.js
@@ -0,0 +1,87 @@
+let testURL = chromeRoot + "browser_select.html";
+let new_tab = null;
+
+//------------------------------------------------------------------------------
+// Entry point (must be named "test")
+function test() {
+  // This test is async
+  waitForExplicitFinish();
+
+  // Add new tab to hold the 
+  
+
+  
+ +
+ + + diff --git a/mobile/android/chrome/tests/browser_tapping.js b/mobile/android/chrome/tests/browser_tapping.js new file mode 100644 index 00000000000..12c203a9e65 --- /dev/null +++ b/mobile/android/chrome/tests/browser_tapping.js @@ -0,0 +1,306 @@ +/* + * Testing the tapping interactions: + * single tap, double tap & long tap + */ + +let testURL = chromeRoot + "browser_tap_content.html"; + +let gTests = []; +let gCurrentTest = null; +let gCurrentTab; + +const kDoubleClickIntervalPlus = kDoubleClickInterval + 100; + +let gEvents = []; +function dumpEvents(aEvent) { + if (aEvent.target != gCurrentTab.browser.parentNode) + return; + + gEvents.push(aEvent.type); +} + +function clearEvents() { + gEvents = []; +} + +function checkEvents(aEvents) { + if (aEvents.length != gEvents.length) { + info("---- event check: failed length (" + aEvents.length + " != " + gEvents.length + ")\n"); + info("---- expected: [" + aEvents.join(",") + "] actual: [" + gEvents.join(",") + "]\n"); + return false; + } + + for (let i=0; i 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + gCurrentTest.run(); + } + else { + window.removeEventListener("TapSingle", dumpEvents, true); + window.removeEventListener("TapDouble", dumpEvents, true); + window.removeEventListener("TapLong", dumpEvents, true); + + SelectionHelper.enabled = true; + Browser.closeTab(gCurrentTab); + + finish(); + } +} + +//------------------------------------------------------------------------------ +// Case: Test the double tap behavior +gTests.push({ + desc: "Test the double tap behavior", + + run: function() { + let inputHandler = gCurrentTab.browser.parentNode; + let width = inputHandler.getBoundingClientRect().width; + let height = inputHandler.getBoundingClientRect().height; + + // Should fire "TapSingle" + info("Test good single tap"); + clearEvents(); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height / 2, {}); + + // We wait a bit because of the delay allowed for double clicking on device + // where it is not native + setTimeout(function() { + ok(checkEvents(["TapSingle"]), "Fired a good single tap"); + clearEvents(); + gCurrentTest.doubleTapTest(); + }, kDoubleClickIntervalPlus); + }, + + doubleTapTest: function() { + let inputHandler = gCurrentTab.browser.parentNode; + let width = inputHandler.getBoundingClientRect().width; + let height = inputHandler.getBoundingClientRect().height; + + // Should fire "TapDouble" + info("Test good double tap"); + clearEvents(); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height / 2, {}); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height / 2, {}); + + setTimeout(function() { + let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2); + if (sysInfo.get("device")) + todo(checkEvents(["TapDouble"]), "Fired a good double tap"); + else + ok(checkEvents(["TapDouble"]), "Fired a good double tap"); + + clearEvents(); + + gCurrentTest.doubleTapFailTest(); + }, kDoubleClickIntervalPlus); + }, + + doubleTapFailTest: function() { + let inputHandler = gCurrentTab.browser.parentNode; + let width = inputHandler.getBoundingClientRect().width; + let height = inputHandler.getBoundingClientRect().height; + + // Should fire "TapSingle", "TapSingle" + info("Test two single taps in different locations"); + clearEvents(); + EventUtils.synthesizeMouse(document.documentElement, width / 3, height / 3, {}); + EventUtils.synthesizeMouse(document.documentElement, width * 2 / 3, height * 2 / 3, {}); + + setTimeout(function() { + ok(checkEvents(["TapSingle", "TapSingle"]), "Fired two single taps in different places, not a double tap"); + clearEvents(); + + gCurrentTest.tapPanTest(); + }, 500); + }, + + tapPanTest: function() { + let inputHandler = gCurrentTab.browser.parentNode; + let width = inputHandler.getBoundingClientRect().width; + let height = inputHandler.getBoundingClientRect().height; + + info("Test a pan - non-tap event"); + clearEvents(); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height / 3, { type: "mousedown" }); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height * 2 / 3, { type: "mousemove" }); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height * 2 / 3, { type: "mouseup" }); + ok(checkEvents([]), "Fired a pan which should be seen as a non event"); + clearEvents(); + + setTimeout(function() { gCurrentTest.longTapFailTest(); }, 500); + }, + + longTapFailTest: function() { + let inputHandler = gCurrentTab.browser.parentNode; + let width = inputHandler.getBoundingClientRect().width; + let height = inputHandler.getBoundingClientRect().height; + + info("Test a long pan - non-tap event"); + clearEvents(); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height / 3, { type: "mousedown" }); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height * 2 / 3, { type: "mousemove" }); + setTimeout(function() { + EventUtils.synthesizeMouse(document.documentElement, width / 2, height * 2 / 3, { type: "mouseup" }); + ok(checkEvents([]), "Fired a pan + delay which should be seen as a non-event"); + clearEvents(); + + window.addEventListener("PanFinished", function() { + window.removeEventListener("PanFinished", arguments.callee, true); + setTimeout(gCurrentTest.longTapPassTest, 0); + }, true); + }, 500); + }, + + longTapPassTest: function() { + let browser = gCurrentTab.browser; + let inputHandler = browser.parentNode; + let width = inputHandler.getBoundingClientRect().width; + let height = inputHandler.getBoundingClientRect().height; + + window.addEventListener("TapLong", function() { + window.removeEventListener("TapLong", arguments.callee, true); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height / 2, { type: "mouseup" }); + ok(checkEvents(["TapLong"]), "Fired a good long tap"); + clearEvents(); + }, true); + + browser.messageManager.addMessageListener("Browser:ContextMenu", function(aMessage) { + browser.messageManager.removeMessageListener(aMessage.name, arguments.callee); + setTimeout(gCurrentTest.contextPlainLinkTest, 0); + }); + + info("Test a good long pan"); + clearEvents(); + EventUtils.synthesizeMouse(document.documentElement, width / 2, height / 2, { type: "mousedown" }); + }, + + contextPlainLinkTest: function() { + waitForContextMenu(function(aJSON) { + is(aJSON.linkTitle, "A blank page - nothing interesting", "Text content should be the content of the second link"); + ok(checkContextTypes(["link", "link-openable"]), "Plain link context types"); + }, gCurrentTest.contextPlainImageTest); + + let browser = gCurrentTab.browser; + let linkDisabled = browser.contentDocument.getElementById("link-disabled"); + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + linkDisabled.dispatchEvent(event); + + let link = browser.contentDocument.getElementById("link-single"); + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + link.dispatchEvent(event); + }, + + contextPlainImageTest: function() { + waitForContextMenu(function() { + ok(checkContextTypes(["image","image-shareable","image-loaded", "content-text"]), "Plain image context types"); + }, gCurrentTest.contextNestedImageTest); + + let browser = gCurrentTab.browser; + let img = browser.contentDocument.getElementById("img-single"); + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + img.dispatchEvent(event); + }, + + contextNestedImageTest: function() { + waitForContextMenu(function() { + ok(checkContextTypes(["link","image","image-shareable","image-loaded","link-openable"]), "Nested image context types"); + }, runNextTest); + + let browser = gCurrentTab.browser; + let img = browser.contentDocument.getElementById("img-nested"); + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + img.dispatchEvent(event); + } +}); + diff --git a/mobile/android/chrome/tests/browser_tapping_edit.js b/mobile/android/chrome/tests/browser_tapping_edit.js new file mode 100644 index 00000000000..b1e4c139a47 --- /dev/null +++ b/mobile/android/chrome/tests/browser_tapping_edit.js @@ -0,0 +1,279 @@ +/* + * Testing the context menus on editboxes: + * plain and url + */ + +let testURL = chromeRoot + "browser_tap_contentedit.html"; + +let gTests = []; +let gCurrentTest = null; +let gCurrentTab; + +const kDoubleClickIntervalPlus = kDoubleClickInterval + 100; + +let gEvents = []; +function dumpEvents(aEvent) { + if (aEvent.target != gCurrentTab.browser.parentNode) + return; + + gEvents.push(aEvent.type); +} + +function clearEvents() { + gEvents = []; +} + +function checkEvents(aEvents) { + if (aEvents.length != gEvents.length) { + info("---- event check: failed length (" + aEvents.length + " != " + gEvents.length + ")\n"); + info("---- expected: [" + aEvents.join(",") + "] actual: [" + gEvents.join(",") + "]\n"); + return false; + } + + for (let i=0; i 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + gCurrentTest.run(); + } + else { + let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard); + clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard); + + window.removeEventListener("TapSingle", dumpEvents, true); + window.removeEventListener("TapDouble", dumpEvents, true); + window.removeEventListener("TapLong", dumpEvents, true); + + SelectionHelper.enabled = true; + Browser.closeTab(gCurrentTab); + + finish(); + } +} + +//------------------------------------------------------------------------------ +gTests.push({ + desc: "Test empty plain textbox", + + run: function() { + waitForContextMenu(function(aJSON) { + ok(checkContextTypes(["input-text"]), "Editbox with no text, no selection and no clipboard"); + }, runNextTest); + + let browser = gCurrentTab.browser; + let plainEdit = browser.contentDocument.getElementById("plain-edit"); + plainEdit.readOnly = false; + plainEdit.value = ""; + + // Try very hard to keep "paste" from if the clipboard has data + let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard); + clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard); + plainEdit.readOnly = true; + + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + plainEdit.dispatchEvent(event); + } +}); + +//------------------------------------------------------------------------------ +gTests.push({ + desc: "Test plain textbox with text fully selected", + + run: function() { + waitForContextMenu(function(aJSON) { + ok(checkContextTypes(["input-text", "copy"]), "Editbox with text and full selection, but no clipboard"); + }, runNextTest); + + let browser = gCurrentTab.browser; + let plainEdit = browser.contentDocument.getElementById("plain-edit"); + plainEdit.readOnly = false; + plainEdit.value = "Every time we fix a bug, Stuart call's the President"; + let plainEdit = plainEdit.QueryInterface(Ci.nsIDOMNSEditableElement); + plainEdit.editor.selectAll(); + + // Try very hard to keep "paste" from if the clipboard has data + let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard); + clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard); + plainEdit.readOnly = true; + + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + plainEdit.dispatchEvent(event); + } +}); + +//------------------------------------------------------------------------------ +gTests.push({ + desc: "Test plain textbox with text no selection", + + run: function() { + waitForContextMenu(function(aJSON) { + ok(checkContextTypes(["input-text", "copy-all", "select-all"]), "Editbox with text, but no selection and no clipboard"); + }, runNextTest); + + let browser = gCurrentTab.browser; + let plainEdit = browser.contentDocument.getElementById("plain-edit"); + plainEdit.readOnly = false; + plainEdit.value = "Every time we fix a bug, Stuart call's the President"; + plainEdit.selectionStart = 0; + plainEdit.selectionEnd = 0; + + // Try very hard to keep "paste" from if the clipboard has data + let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard); + clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard); + plainEdit.readOnly = true; + + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + plainEdit.dispatchEvent(event); + } +}); + +//------------------------------------------------------------------------------ +gTests.push({ + desc: "Test plain textbox with text no selection and text on clipboard", + + run: function() { + waitForContextMenu(function(aJSON) { + ok(checkContextTypes(["input-text", "copy-all", "select-all", "paste"]), "Editbox with text and clipboard, but no selection"); + }, runNextTest); + + let browser = gCurrentTab.browser; + let plainEdit = browser.contentDocument.getElementById("plain-edit"); + plainEdit.readOnly = false; + plainEdit.value = "Every time we fix a bug, Stuart call's the President"; + plainEdit.selectionStart = 0; + plainEdit.selectionEnd = 0; + + // Put some data on the clipboard to get "paste" to be active + let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); + clipboard.copyString("We are testing Firefox"); + + let event = content.document.createEvent("PopupEvents"); + event.initEvent("contextmenu", true, true); + plainEdit.dispatchEvent(event); + } +}); + +//------------------------------------------------------------------------------ +gTests.push({ + desc: "Test that tapping on input box causes mouse events to fire", + + run: function() { + let browser = gCurrentTab.browser; + let plainEdit = browser.contentDocument.getElementById("plain-edit"); + plainEdit.blur(); + plainEdit.value = ''; + + let eventArray = ['mouseover', 'mousedown', 'mouseup', 'click']; + + while (eventArray.length > 0) { + let currentEventType = eventArray.shift(); + browser.contentWindow.addEventListener(currentEventType, function(e) { + browser.contentWindow.removeEventListener(currentEventType, arguments.callee, true); + ok(e.target == plainEdit, e.type + " should fire over input id=" + plainEdit.id); + plainEdit.value += e.type + ' '; + + if (e.type == 'click') { + ok(plainEdit.value == 'mouseover mousedown mouseup click ', + 'Events should fire in this order: mouseover mousedown mouseup click '); + runNextTest(); + } + } , true); + } + + EventUtils.synthesizeMouse(plainEdit, browser.getBoundingClientRect().left + plainEdit.getBoundingClientRect().left + 2, + browser.getBoundingClientRect().top + plainEdit.getBoundingClientRect().top + 2, {}); + } +}); + diff --git a/mobile/android/chrome/tests/browser_test.js b/mobile/android/chrome/tests/browser_test.js new file mode 100644 index 00000000000..c0a987eb4c0 --- /dev/null +++ b/mobile/android/chrome/tests/browser_test.js @@ -0,0 +1,20 @@ +// Tests for the test functions in head.js + +function test() { + waitForExplicitFinish(); + testWaitForAndContinue(); +} + +function testWaitForAndContinue() { + waitForAndContinue(function() { + ok(true, "continues on success") + testWaitForAndContinue2(); + }, function() true); +} + +function testWaitForAndContinue2() { + waitForAndContinue(function() { + ok(true, "continues on failure"); + finish(); + }, function() false); +} diff --git a/mobile/android/chrome/tests/browser_thumbnails.js b/mobile/android/chrome/tests/browser_thumbnails.js new file mode 100644 index 00000000000..59ac82d731e --- /dev/null +++ b/mobile/android/chrome/tests/browser_thumbnails.js @@ -0,0 +1,155 @@ +// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- +/* + * ***** 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): + * Wes Johnston + * + * 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 ***** */ + +let testURL_blank = baseURI + "browser_blank_01.html"; + +const DEFAULT_WIDTH = 800; + +function testURL(n) { + if (n < 0) + return testURL_blank; + + return baseURI + "browser_viewport.sjs?" + encodeURIComponent(gTestData[n].metadata); +} + +function scaleRatio(n) { + if ("scaleRatio" in gTestData[n]) + return gTestData[n].scaleRatio; + return 150; // Default value matches our main target hardware (N900, Nexus One, etc.) +} + +let currentTab; + +let loadURL = function loadURL(aPageURL) { + BrowserUI.goToURI(aPageURL); +}; + +let gTestData = [ + { metadata: "", width: DEFAULT_WIDTH, scale: 1 }, + { metadata: "width=device-width, initial-scale=1" }, + { metadata: "width=device-width" }, + { metadata: "width=320, initial-scale=1" }, + { metadata: "initial-scale=1.0, user-scalable=no" }, + { metadata: "width=200,height=500" }, + { metadata: "width=2000, minimum-scale=0.75" }, + { metadata: "width=100, maximum-scale=2.0" }, + { metadata: "width=2000, initial-scale=0.75" }, + { metadata: "width=20000, initial-scale=100" }, + { metadata: "XHTML" }, + /* testing opening and switching between pages without a viewport */ + { metadata: "style=width:400px;margin:0px;" }, + { metadata: "style=width:1000px;margin:0px;" }, + { metadata: "style=width:800px;margin:0px;" }, + { metadata: "style=width:800px;height:300px;margin:0px;" }, + { metadata: "style=width:800px;height:1000px;margin:0px;" }, +]; + + + +//------------------------------------------------------------------------------ +// Entry point (must be named "test") +let gCurrentTest = -1; +let secondPass = false; +let oldRendererFactory; +let gDevice = null; +function test() { + oldRendererFactory = rendererFactory; + rendererFactory = newRendererFactory; + + // if we are on desktop, we can run tests in both portrait and landscape modes + // on devices we should just use the current orientation + let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2); + gDevice = sysInfo.get("device"); + if (gDevice != null) + secondPass = true; + + // This test is async + waitForExplicitFinish(); + + currentTab = Browser.addTab("about:blank", true); + ok(currentTab, "Tab Opened"); + + startTest(gCurrentTest); +} + +function startTest(n) { + let url = testURL(gCurrentTest); + info("Testing: " + url) + loadURL(url); +} + +function newRendererFactory(aBrowser, aCanvas) { + let wrapper = {}; + let ctx = aCanvas.MozGetIPCContext("2d"); + let draw = function(browser, aLeft, aTop, aWidth, aHeight, aColor, aFlags) { + is(aLeft, 0,"Thumbnail drawn at x=0"); + is(aTop, 0,"Thumbnail drawn at y=0"); + ok(aWidth <= browser.contentDocumentWidth, "Thumbnail ok width: " + aWidth + " <= " + browser.contentDocumentWidth); + ok(aHeight <= browser.contentDocumentHeight,"Thumbnail ok height:" + aHeight + " <= " + browser.contentDocumentHeight); + finishTest(); + }; + wrapper.checkBrowser = function(browser) { + return browser.contentWindow; + }; + wrapper.drawContent = function(callback) { + callback(ctx, draw); + }; + + return wrapper; +}; + +function finishTest() { + gCurrentTest++; + if (gCurrentTest < gTestData.length) { + startTest(gCurrentTest); + } else if (secondPass) { + + if (gDevice == null) + window.top.resizeTo(480,800); + + Browser.closeTab(currentTab); + rendererFactory = oldRendererFactory; + finish(); + } else { + secondPass = true; + gCurrentTest = -1; + window.top.resizeTo(800,480); + startTest(gCurrentTest); + } +} diff --git a/mobile/android/chrome/tests/browser_title.sjs b/mobile/android/chrome/tests/browser_title.sjs new file mode 100644 index 00000000000..a523c1de5de --- /dev/null +++ b/mobile/android/chrome/tests/browser_title.sjs @@ -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 Mobile Browser. + * + * 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): + * Aditya Rao + * Vivien Nicolas <21@vingtetun.org> + * + * 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 ***** */ + +function handleRequest(request, response) { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/html", false); + + let action = ""; + let query = decodeURIComponent(request.queryString || ""); + response.write(""); + + switch (query) { + case "no_title": + break; + case "english_title": + response.write("English Title Page"); + break; + case "dynamic_title": + response.write("This is an english title page"); + response.write(""); + break; + case "redirect": + response.write(""); + break; + case "location": + response.write(""); + break; + default: + break; + } + response.write("" + query + ""); +} diff --git a/mobile/android/chrome/tests/browser_upgrade.rdf b/mobile/android/chrome/tests/browser_upgrade.rdf new file mode 100644 index 00000000000..bfde13200e0 --- /dev/null +++ b/mobile/android/chrome/tests/browser_upgrade.rdf @@ -0,0 +1,45 @@ + + + + + + + +
  • + + 2.0 + + + toolkit@mozilla.org + 0 + * + http://example.com/browser/mobile/chrome/tests/addons/browser_install1_3.xpi + + + +
  • +
    +
    +
    + + + + +
  • + + 1.0 + + + mochikit@mozilla.org + 0 + * + + + +
  • +
    +
    +
    + +
    diff --git a/mobile/android/chrome/tests/browser_viewport.js b/mobile/android/chrome/tests/browser_viewport.js new file mode 100644 index 00000000000..bb95cc2eb6d --- /dev/null +++ b/mobile/android/chrome/tests/browser_viewport.js @@ -0,0 +1,209 @@ +// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- +/* + * ***** 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): + * Mark Finkle + * Matt Brubeck + * + * 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 ***** */ + +let testURL_blank = baseURI + "browser_blank_01.html"; + +const DEFAULT_WIDTH = 800; + +function testURL(n) { + return baseURI + "browser_viewport.sjs" + + "?metadata=" + encodeURIComponent(gTestData[n].metadata || "") + + "&style=" + encodeURIComponent(gTestData[n].style || "") + + "&xhtml=" + encodeURIComponent(!!gTestData[n].xhtml); +} + +function scaleRatio(n) { + if ("scaleRatio" in gTestData[n]) + return gTestData[n].scaleRatio; + return 150; // Default value matches our main target hardware (N900, Nexus One, etc.) +} + +let currentTab; + +let loadURL = function loadURL(aPageURL, aCallback, aScale) { + messageManager.addMessageListener("pageshow", function(aMessage) { + if (aMessage.target.currentURI.spec == aPageURL) { + messageManager.removeMessageListener(aMessage.name, arguments.callee); + + waitFor(aCallback, function() { + return !aScale || aScale == aMessage.target.scale; + }); + } + }); + + BrowserUI.goToURI(aPageURL); +}; + +// XXX Tests do not yet run correctly in portrait. +window.resizeTo(800, 480); + +let gTestData = [ + { metadata: "", width: DEFAULT_WIDTH, scale: 1 }, + { metadata: "width=device-width, initial-scale=1", width: 533.33, scale: 1.5 }, + { metadata: "width=device-width", width: 533.33, scale: 1.5 }, + { metadata: "width=device-width, initial-scale=1", scaleRatio: 100, width: 800, scale: 1 }, + { metadata: "width=320, initial-scale=1", width: 533.33, scale: 1.5 }, + { metadata: "initial-scale=1.0, user-scalable=no", width: 533.33, scale: 1.5, disableZoom: true }, + { metadata: "initial-scale=1.0, user-scalable=0", width: 533.33, scale: 1.5, disableZoom: true }, + { metadata: "initial-scale=1.0, user-scalable=false", width: 533.33, scale: 1.5, disableZoom: true }, + { metadata: "initial-scale=1.0, user-scalable=NO", width: 533.33, scale: 1.5, disableZoom: false }, // values are case-sensitive + { metadata: "width=200,height=500", width: 200, scale: 4 }, + { metadata: "width=2000, minimum-scale=0.75", width: 2000, scale: 1.125, minScale: 1.125 }, + { metadata: "width=100, maximum-scale=2.0", width: 266.67, scale: 3, maxScale: 3 }, + { metadata: "width=2000, initial-scale=0.75", width: 2000, scale: 1.125 }, + { metadata: "width=20000, initial-scale=100", width: 10000, scale: 4 }, + { xhtml: true, width: 533.33, scale: 1.5, disableZoom: false }, + /* testing spaces between arguments (bug 572696) */ + { metadata: "width= 2000, minimum-scale=0.75", width: 2000, scale: 1.125 }, + { metadata: "width = 2000, minimum-scale=0.75", width: 2000, scale: 1.125 }, + { metadata: "width = 2000 , minimum-scale=0.75", width: 2000, scale: 1.125 }, + { metadata: "width = 2000 , minimum-scale =0.75", width: 2000, scale: 1.125 }, + { metadata: "width = 2000 , minimum-scale = 0.75", width: 2000, scale: 1.125 }, + { metadata: "width = 2000 , minimum-scale = 0.75", width: 2000, scale: 1.125 }, + /* testing opening and switching between pages without a viewport */ + { style: "width:400px;margin:0px;", width: DEFAULT_WIDTH, scale: 1 }, + { style: "width:2000px;margin:0px;", width: 980, scale: window.innerWidth/2000 }, + { style: "width:800px;margin:0px;", width: DEFAULT_WIDTH, scale: 1 }, +]; + + +//------------------------------------------------------------------------------ +// Entry point (must be named "test") +function test() { + // This test is async + waitForExplicitFinish(); + requestLongerTimeout(2); + + currentTab = Browser.addTab("about:blank", true); + ok(currentTab, "Tab Opened"); + + startTest(0); +} + +function startTest(n) { + info(JSON.stringify(gTestData[n])); + BrowserUI.goToURI(testURL_blank); + loadURL(testURL_blank, verifyBlank(n)); + Services.prefs.setIntPref("browser.viewport.scaleRatio", scaleRatio(n)); +} + +function verifyBlank(n) { + return function() { + // Do sanity tests + let uri = currentTab.browser.currentURI.spec; + is(uri, testURL_blank, "URL Matches blank page " + n); + + waitFor(function() { + loadURL(testURL(n), verifyTest(n), gTestData[n].scale); + }, function() { + return currentTab.browser.contentWindowWidth == DEFAULT_WIDTH; + }); + } +} + +function is_approx(actual, expected, fuzz, description) { + ok(Math.abs(actual - expected) <= fuzz, + description + " [got " + actual + ", expected " + expected + "]"); +} + +function verifyTest(n) { + let assumedWidth = 480; + if (!Util.isPortrait()) + assumedWidth = 800; + + return function() { + is(window.innerWidth, assumedWidth, "Test assumes window width is " + assumedWidth + "px"); + + // Do sanity tests + let uri = currentTab.browser.currentURI.spec; + is(uri, testURL(n), "URL is " + testURL(n)); + + let data = gTestData[n]; + let actualWidth = currentTab.browser.contentWindowWidth; + is_approx(actualWidth, parseFloat(data.width), .01, "Viewport width=" + data.width); + + let zoomLevel = getBrowser().scale; + is_approx(zoomLevel, parseFloat(data.scale), .01, "Viewport scale=" + data.scale); + + // Test zooming + if (data.disableZoom) { + ok(!currentTab.allowZoom, "Zoom disabled"); + + Browser.zoom(-1); + is(getBrowser().scale, zoomLevel, "Zoom in does nothing"); + + Browser.zoom(1); + is(getBrowser().scale, zoomLevel, "Zoom out does nothing"); + } + else { + ok(Browser.selectedTab.allowZoom, "Zoom enabled"); + } + + + if (data.minScale) { + do { // Zoom out until we can't go any farther. + zoomLevel = getBrowser().scale; + Browser.zoom(1); + } while (getBrowser().scale != zoomLevel); + ok(getBrowser().scale >= data.minScale, "Zoom out limited"); + } + + if (data.maxScale) { + do { // Zoom in until we can't go any farther. + zoomLevel = getBrowser().scale; + Browser.zoom(-1); + } while (getBrowser().scale != zoomLevel); + ok(getBrowser().scale <= data.maxScale, "Zoom in limited"); + } + + finishTest(n); + } +} + +function finishTest(n) { + Services.prefs.clearUserPref("browser.viewport.scaleRatio"); + if (n + 1 < gTestData.length) { + startTest(n + 1); + } else { + window.resizeTo(480, 800); + Browser.closeTab(currentTab); + finish(); + } +} diff --git a/mobile/android/chrome/tests/browser_viewport.sjs b/mobile/android/chrome/tests/browser_viewport.sjs new file mode 100644 index 00000000000..e7351a3f675 --- /dev/null +++ b/mobile/android/chrome/tests/browser_viewport.sjs @@ -0,0 +1,65 @@ +/* ***** 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) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Matt Brubeck + * + * 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 ***** */ + + function decodeQuery(query) { + let result = {}; + query.split("&").forEach(function(pair) { + let [key, val] = pair.split("="); + result[key] = decodeURIComponent(val); + }); + return result; + } + +function handleRequest(request, response) { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/html", false); + + let params = decodeQuery(request.queryString || ""); + + if (params.xhtml == "true") { + response.write(""); + response.write(""); + } + response.write("Browser Viewport Test"); + if (params.metadata) + response.write(""); + response.write(" "); +} diff --git a/mobile/android/chrome/tests/browser_vkb.js b/mobile/android/chrome/tests/browser_vkb.js new file mode 100644 index 00000000000..d20efe6c75a --- /dev/null +++ b/mobile/android/chrome/tests/browser_vkb.js @@ -0,0 +1,150 @@ +/* + * Check VKB show/hide behavior + */ +let testURL_01 = chromeRoot + "browser_forms.html"; +messageManager.loadFrameScript(chromeRoot + "remote_vkb.js", true); + +/* ============================= Tests Utils =============================== */ +let gTests = []; +let gCurrentTest = null; + +// Iterating tests by shifting test out one by one as runNextTest is called. +function runNextTest() { + // Run the next test until all tests completed + if (gTests.length > 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + gCurrentTest.run(); + } + else { + // Close the awesome panel just in case + AwesomeScreen.activePanel = null; + finish(); + } +} + +function test() { + // The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()" + // We call "finish()" when the tests are finished + waitForExplicitFinish(); + + // Start the tests + if ("gTimeout" in window) + setTimeout(runNextTest, gTimeout); + else + runNextTest(); +} +/* ============================ End Utils ================================== */ + +Components.utils.import("resource://gre/modules/Services.jsm"); +let VKBStateHasChanged = false; +let VKBObserver = { + _enabled: false, + observe: function(aTopic, aSubject, aData) { + if (this._enabled != parseInt(aData)) { + this._enabled = parseInt(aData); + VKBstateHasChanged = true; + } + } +}; +Services.obs.addObserver(VKBObserver, "ime-enabled-state-changed", false); + +function waitForVKBChange(aCallback, aState) { + waitForAndContinue(aCallback, function() { + if (VKBStateHasChanged) { + VKBStateHasChanged = false; + return true; + } + + return VKBStateHasChanged; + }); +} + +let newTab = null; + +function waitForPageShow(aPageURL, aCallback) { + messageManager.addMessageListener("pageshow", function(aMessage) { + if (aMessage.target.currentURI.spec == aPageURL) { + messageManager.removeMessageListener("pageshow", arguments.callee); + setTimeout(function() { aCallback(); }, 0); + } + }); +}; + +function dragElement(element, x1, y1, x2, y2) { + EventUtils.synthesizeMouse(element, x1, y1, { type: "mousedown" }); + EventUtils.synthesizeMouse(element, x2, y2, { type: "mousemove" }); + EventUtils.synthesizeMouse(element, x2, y2, { type: "mouseup" }); +} + +//------------------------------------------------------------------------------ +// Case: Test interactions with a VKB from content +gTests.push({ + desc: "Test interactions with a VKB from content", + run: function() { + waitForPageShow(testURL_01, gCurrentTest.focusContentInputField); + + newTab = Browser.addTab(testURL_01, true); + ok(newTab, "Tab Opened"); + }, + + focusContentInputField: function() { + is(VKBObserver._enabled, false, "Initially the VKB should be closed"); + + AsyncTests.waitFor("Test:FocusRoot", {}, function(json) { + waitForVKBChange(gCurrentTest.showLeftSidebar); + }) + }, + + showLeftSidebar: function() { + is(VKBObserver._enabled, true, "When focusing an input field the VKB should be opened"); + + let browsers = document.getElementById("browsers"); + dragElement(browsers, window.innerWidth / 2, window.innerHeight / 2, 1000, 1000); + waitForVKBChange(gCurrentTest.showRightSidebar); + }, + + showRightSidebar: function() { + is(VKBObserver._enabled, true, "When pannning to the leftSidebar the VKB state should not changed"); + + let browsers = document.getElementById("browsers"); + dragElement(browsers, window.innerWidth / 2, window.innerHeight / 2, -1000, -1000); + waitForVKBChange(gCurrentTest.changeTab); + }, + + changeTab: function() { + is(VKBObserver._enabled, true, "When panning to the right sidebar the VKB state should not changed"); + + let firstTab = document.getElementById("tabs").children.firstChild; + BrowserUI.selectTab(firstTab); + waitForVKBChange(gCurrentTest.prepareOpenRightPanel); + }, + + prepareOpenRightPanel: function() { + is(VKBObserver._enabled, false, "Switching tab should close the VKB"); + + BrowserUI.selectTab(newTab); + + // Give back the focus to the content input and launch and check + // interaction with the right panel + AsyncTests.waitFor("Test:FocusRoot", {}, function(json) { + waitForVKBChange(gCurrentTest.openRightPanel); + }); + }, + + openRightPanel: function() { + is(VKBObserver._enabled, true, "Re-cliking on an input field should re-open the VKB"); + + let toolsButton = document.getElementById("tool-panel-open"); + let rect = toolsButton.getBoundingClientRect(); + EventUtils.synthesizeMouse(toolsButton, rect.width / 2, rect.height / 2, {}); + waitForVKBChange(function() { + is(VKBObserver._enabled, false, "Opening the right panel should close the VKB"); + BrowserUI.hidePanel(); + Browser.hideSidebars(); + BrowserUI.closeTab(newTab); + Services.obs.removeObserver(VKBObserver, "ime-enabled-state-changed"); + runNextTest(); + }); + } +}); diff --git a/mobile/android/chrome/tests/head.js b/mobile/android/chrome/tests/head.js new file mode 100644 index 00000000000..965858ec96f --- /dev/null +++ b/mobile/android/chrome/tests/head.js @@ -0,0 +1,122 @@ +/*============================================================================= + Common Helpers functions +=============================================================================*/ + +const kDefaultWait = 2000; +// Wait for a condition and call a supplied callback if condition is met within +// alloted time. If condition is not met, cause a hard failure, stopping the test. +function waitFor(callback, test, timeout) { + if (test()) { + callback(); + return; + } + + timeout = timeout || Date.now(); + if (Date.now() - timeout > kDefaultWait) + throw "waitFor timeout"; + setTimeout(waitFor, 50, callback, test, timeout); +}; + +// Wait for a condition and call a supplied callback if condition is met within +// alloted time. If condition is not met, continue anyway. Use this helper if the +// callback will test for the outcome, but not stop the entire test. +function waitForAndContinue(callback, test, timeout) { + if (test()) { + callback(); + return; + } + + timeout = timeout || Date.now(); + if (Date.now() - timeout > kDefaultWait) { + callback(); + return; + } + setTimeout(waitForAndContinue, 50, callback, test, timeout); +}; + +// Listen for the specified message once, then remove the listener. +function onMessageOnce(aMessageManager, aName, aCallback) { + aMessageManager.addMessageListener(aName, function onMessage(aMessage) { + aMessageManager.removeMessageListener(aName, onMessage); + setTimeout(function() { + aCallback(aMessage); + }, 0); + }); +}; + +// This function is useful for debugging one test where you need to wait for +// application to be ready +function waitForFirstPaint(aCallback) { + function hasFirstPaint() { + let startupInfo = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup).getStartupInfo(); + return ("firstPaint" in startupInfo); + } + + if (!hasFirstPaint()) { + waitFor(aCallback, hasFirstPaint, Date.now() + 3000); + return; + } + + aCallback(); +}; + +function makeURI(spec) { + return Services.io.newURI(spec, null, null); +}; + +EventUtils.synthesizeString = function synthesizeString(aString, aWindow) { + for (let i = 0; i < aString.length; i++) { + EventUtils.synthesizeKey(aString.charAt(i), {}, aWindow); + } +}; + +EventUtils.synthesizeMouseForContent = function synthesizeMouseForContent(aElement, aOffsetX, aOffsetY, aEvent, aWindow) { + let container = document.getElementById("browsers"); + let rect = container.getBoundingClientRect(); + + EventUtils.synthesizeMouse(aElement, rect.left + aOffsetX, rect.top + aOffsetY, aEvent, aWindow); +}; + +let AsyncTests = { + _tests: {}, + waitFor: function(aMessage, aData, aCallback) { + messageManager.addMessageListener(aMessage, this); + if (!this._tests[aMessage]) + this._tests[aMessage] = []; + + this._tests[aMessage].push(aCallback || function() {}); + setTimeout(function() { + Browser.selectedBrowser.messageManager.sendAsyncMessage(aMessage, aData || { }); + }, 0); + }, + + receiveMessage: function(aMessage) { + let test = this._tests[aMessage.name]; + let callback = test.shift(); + if (callback) + callback(aMessage.json); + } +}; + +let gCurrentTest = null; +let gTests = []; + +// Iterating tests by shifting test out one by one as runNextTest is called. +function runNextTest() { + // Run the next test until all tests completed + if (gTests.length > 0) { + gCurrentTest = gTests.shift(); + info(gCurrentTest.desc); + gCurrentTest.run(); + } + else { + finish(); + } +} + +let serverRoot = "http://example.com/browser/mobile/chrome/tests/"; +let baseURI = "http://mochi.test:8888/browser/mobile/chrome/tests/"; + +let chromeRoot = getRootDirectory(gTestPath); +messageManager.loadFrameScript(chromeRoot + "remote_head.js", true); +messageManager.loadFrameScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", true); diff --git a/mobile/android/chrome/tests/locales_list.sjs b/mobile/android/chrome/tests/locales_list.sjs new file mode 100644 index 00000000000..5843a82450c --- /dev/null +++ b/mobile/android/chrome/tests/locales_list.sjs @@ -0,0 +1,121 @@ +let fennecID = "{a23983c0-fd0e-11dc-95ff-0800200c9a66}"; +Components.utils.import("resource://gre/modules/Services.jsm"); + +function getLocale(aLocaleParams, aAppParams) { + let l = { + TARGETLOCALE: "test{IDNUMBER}", + NAME: "Test Locale {IDNUMBER}", + VERSION: "1.0", + INSTALL: "http://www.example.com/browser/mobile/chrome/tests/addons/browser_locale{IDNUMBER}.xpi", + TYPENUMBER: 5, + TYPENAME: "Language Pack (Application)", + IDNUMBER: "", + }; + let a = { + APPNAME: "Fennec", + MINVERSION: "4.0", MAXVERSION: "*", + APPID: fennecID + }; + + if (aLocaleParams) { + for (var entry in aLocaleParams) { + l[entry] = aLocaleParams[entry]; + } + } + + if (aAppParams) { + for (var entry in aAppParams) { + a[entry] = aAppParams[entry]; + } + } + + l.app = a; + return l; +} + +let appTemplate = "" + +"{APPNAME}" + + "{MINVERSION}" + + "{MAXVERSION}" + + "{APPID}" + +""; + +let template = ""+ + "{TARGETLOCALE}" + + "{NAME}"+ + "{TYPENAME}"+ + "langpack-{TARGETLOCALE}@firefox-mobile.mozilla.org"+ + "{VERSION}"+ + "Public"+ + "{APPS}"+ + "ALL"+ + "{INSTALL}\n" + + "title=TITLE\n" + + "continueIn=CONTINUEIN%S\n" + + "name=NAME\n" + + "choose=CHOOSE\n" + + "chooseLanguage=CHOOSELANGUAGE\n" + + "cancel=CANCEL\n" + + "continue=CONTINUE\n" + + "installing=INSTALLING%S\n" + + "installerror=INSTALLERROR\n" + + "loading=LOADING" + + ""+ +""; + +function handleRequest(request, response) { + + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/xml", false); + + response.write(""); + response.write(""); + + let locales = []; + let query = decodeURIComponent(request.queryString || "").split("="); + switch(query[0]) { + case "numvalid": + let numValid = parseInt(query[1]); + for (let i = 0; i < numValid; i++) { + locales.push( getLocale({IDNUMBER: i}) ); + } + break; + case "buildid": + locales.push( getLocale({IDNUMBER: 1, NAME: query[1]}) ); + break; + default : + locales.push( getLocale({IDNUMBER: 1}) ); + /* These locales should fail in the LocaleRepository */ + locales.push( getLocale({IDNUMBER: 1}) ); // no duplicate ids + locales.push( getLocale({IDNUMBER: 2, INSTALL: "INVALID_URL"}) ); + locales.push( getLocale({IDNUMBER: 3}, {APPID: "INVALID_ID"}) ); + locales.push( getLocale({IDNUMBER: 3}, {MAXVERSION: "0"}) ); + locales.push( getLocale({IDNUMBER: 4, TARGETLOCALE: ""}) ); + locales.push( getLocale({IDNUMBER: 5, NAME: ""}) ); + locales.push( getLocale({IDNUMBER: 6, VERSION: ""}) ); + locales.push( getLocale({IDNUMBER: 7, TYPENUMBER: ""}) ); + break; + } + + for(var i = 0; i < locales.length; i++) { + let t = template; + t = t.replace(/{TARGETLOCALE}/g, locales[i].TARGETLOCALE); + t = t.replace(/{NAME}/, locales[i].NAME); + t = t.replace(/{VERSION}/, locales[i].VERSION); + t = t.replace(/{INSTALL}/, locales[i].INSTALL); + t = t.replace(/{TYPENUMBER}/, locales[i].TYPENUMBER); + t = t.replace(/{TYPENAME}/, locales[i].TYPENAME); + t = t.replace(/{IDNUMBER}/g, locales[i].IDNUMBER) + + let a = appTemplate; + a = a.replace(/{APPNAME}/, locales[i].app.APPNAME); + a = a.replace(/{MINVERSION}/, locales[i].app.MINVERSION); + a = a.replace(/{MAXVERSION}/, locales[i].app.MAXVERSION); + a = a.replace(/{APPID}/, locales[i].app.APPID); + + t = t.replace(/{APPS}/, a); + response.write(t); + } + + response.write(""); +} diff --git a/mobile/android/chrome/tests/mock_autocomplete.json b/mobile/android/chrome/tests/mock_autocomplete.json new file mode 100644 index 00000000000..ef5e43d6fa5 --- /dev/null +++ b/mobile/android/chrome/tests/mock_autocomplete.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "result": { + "searchResult": 4, + "RESULT_NOMATCH_ONGOING": 5, + "RESULT_SUCCESS_ONGOING": 6, + "searchString": "", + "defaultIndex": 0, + "errorDescription": "", + "matchCount": 5, + "RESULT_IGNORED": 1, + "RESULT_FAILURE": 2, + "RESULT_NOMATCH": 3, + "RESULT_SUCCESS": 4, + "data": [["http://example.com/a", "A", "favicon", "http://example.com/a/favicon.png"], + ["http://example.com/b", "B", "favicon", "http://example.com/b/favicon.png"], + ["http://example.com/c", "C", "favicon", "http://example.com/c/favicon.png"], + ["http://example.com/d", "D", "bookmark", "http://example.com/d/favicon.png"], + ["http://example.com/e", "E", "boolmark", "http://example.com/e/favicon.png"] + ] + } +} diff --git a/mobile/android/chrome/tests/remote_autocomplete.js b/mobile/android/chrome/tests/remote_autocomplete.js new file mode 100644 index 00000000000..991671aa6ef --- /dev/null +++ b/mobile/android/chrome/tests/remote_autocomplete.js @@ -0,0 +1,22 @@ +dump("====================== Content Script Loaded =======================\n"); + +let assistant = Content.formAssistant; + +AsyncTests.add("TestRemoteAutocomplete:Click", function(aMessage, aJson) { + let element = content.document.getElementById(aJson.id); + assistant.open(element); + return true; +}); + +AsyncTests.add("TestRemoteAutocomplete:Check", function(aMessage, aJson) { + let element = content.document.getElementById(aJson.id); + return element.value; +}); + +AsyncTests.add("TestRemoteAutocomplete:Reset", function(aMessage, aJson) { + gFocusManager.focusedElement = null; + let element = content.document.getElementById(aJson.id); + element.value = ""; + return true; +}); + diff --git a/mobile/android/chrome/tests/remote_contentpopup.js b/mobile/android/chrome/tests/remote_contentpopup.js new file mode 100644 index 00000000000..f2156d700c5 --- /dev/null +++ b/mobile/android/chrome/tests/remote_contentpopup.js @@ -0,0 +1,18 @@ +dump("====================== Content Script Loaded =======================\n"); + +let assistant = Content.formAssistant; + +AsyncTests.add("TestRemoteAutocomplete:Click", function(aMessage, aJson) { + let element = content.document.getElementById(aJson.id); + assistant.open(element); + assistant._executeDelayed(function(assistant) { + sendAsyncMessage("FormAssist:AutoComplete", assistant._getJSON()); + }); + return true; +}); + +AsyncTests.add("TestRemoteAutocomplete:Check", function(aMessage, aJson) { + let element = content.document.getElementById(aJson.id); + return element.value; +}); + diff --git a/mobile/android/chrome/tests/remote_focus.js b/mobile/android/chrome/tests/remote_focus.js new file mode 100644 index 00000000000..d3c4544c271 --- /dev/null +++ b/mobile/android/chrome/tests/remote_focus.js @@ -0,0 +1,16 @@ +function focusReceived() { + sendAsyncMessage("Test:E10SFocusReceived"); +} + +function blurReceived() { + sendAsyncMessage("Test:E10SBlurReceived"); +} + +addEventListener("focus", focusReceived, true); +addEventListener("blur", blurReceived, true); + +addMessageListener("Test:E10SFocusTestFinished", function testFinished() { + removeEventListener("focus", focusReceived, true); + removeEventListener("blur", blurReceived, true); + removeMessageListener("Test:E10SFocusTestFinished", testFinished); +}); diff --git a/mobile/android/chrome/tests/remote_forms.js b/mobile/android/chrome/tests/remote_forms.js new file mode 100644 index 00000000000..36779f5ae15 --- /dev/null +++ b/mobile/android/chrome/tests/remote_forms.js @@ -0,0 +1,171 @@ +dump("====================== Content Script Loaded =======================\n"); + +let assistant = Content.formAssistant; + +// Copied from http://mxr.mozilla.org/mozilla-central/source/testing/mochitest/tests/SimpleTest/EventUtils.js +// except the netscape.security.PrivilegeManager.enablePrivilege call +function sendMouseEvent(aEvent, aTarget, aWindow) { + if (['click', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) { + throw new Error("sendMouseEvent doesn't know about event type '" + aEvent.type + "'"); + } + + if (!aWindow) { + aWindow = window; + } + + if (!(aTarget instanceof Element)) { + aTarget = aWindow.document.getElementById(aTarget); + } + + let event = aWindow.document.createEvent('MouseEvent'); + + let typeArg = aEvent.type; + let canBubbleArg = true; + let cancelableArg = true; + let viewArg = aWindow; + let detailArg = aEvent.detail || (aEvent.type == 'click' || + aEvent.type == 'mousedown' || + aEvent.type == 'mouseup' ? 1 : 0); + let screenXArg = aEvent.screenX || 0; + let screenYArg = aEvent.screenY || 0; + let clientXArg = aEvent.clientX || 0; + let clientYArg = aEvent.clientY || 0; + let ctrlKeyArg = aEvent.ctrlKey || false; + let altKeyArg = aEvent.altKey || false; + let shiftKeyArg = aEvent.shiftKey || false; + let metaKeyArg = aEvent.metaKey || false; + let buttonArg = aEvent.button || 0; + let relatedTargetArg = aEvent.relatedTarget || null; + + event.initMouseEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg, + screenXArg, screenYArg, clientXArg, clientYArg, + ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg, + buttonArg, relatedTargetArg); + + aTarget.dispatchEvent(event); +} + +AsyncTests.add("Test:Click", function(aMessage, aJson) { + sendMouseEvent({type: "click"}, "root", content); + return assistant._open; +}); + +AsyncTests.add("Test:Focus", function(aMessage, aJson) { + let targetElement = content.document.querySelector(aJson.value); + targetElement.focus(); + assistant._executeDelayed(function() { + sendAsyncMessage(aMessage, { result: assistant._open }); + }); +}); + +AsyncTests.add("Test:FocusRedirect", function(aMessage, aJson) { + let element = content.document.querySelector(aJson.value); + element.addEventListener("focus", function(aEvent) { + element.removeEventListener("focus", arguments.callee, false); + content.document.getElementById("root").focus(); + }, false); + element.focus(); + + assistant._executeDelayed(function() { + sendAsyncMessage(aMessage, { result: assistant._open }); + }); +}); + +// It should be only 2 ways to open the FormAssistant, the first one is +// by manually synchronizing the focus to the form helper and the other +// one is by a user click on an authorized element +AsyncTests.add("Test:OpenUIWithSyncFocus", function(aMessage, aJson) { + let element = content.document.querySelector(aJson.value); + + assistant._open = false; + assitant.focusSync = true; + element.focus(); + assistant._executeDelayed(function() { + assistant.focusSync = false; + sendAsyncMessage(aMessage, { result: assistant._open }); + }); +}); + +AsyncTests.add("Test:Open", function(aMessage, aJson) { + let element = content.document.querySelector(aJson.value); + assistant._open = false; + return assistant.open(element); +}); + +AsyncTests.add("Test:OpenWithFocusRedirect", function(aMessage, aJson) { + let element = content.document.querySelector(aJson.value); + assistant._open = false; + assistant.focusSync = true; + assistant.open(element); + assistant._executeDelayed(function() { + assistant.focusSync = false; + sendAsyncMessage(aMessage, { result: assistant._open }); + }); +}); + +AsyncTests.add("Test:CanShowUI", function(aMessage, aJson) { + let element = content.document.querySelector(aJson.value); + element.disabled = aJson.disabled; + assistant._open = false; + let open = assistant.open(element); + element.disabled = false; + return open; +}); + +AsyncTests.add("Test:CanShowUISelect", function(aMessage, aJson) { + let select = content.document.getElementById("select"); + select.disabled = aJson.disabled; + + let element = content.document.querySelector(aJson.value); + assistant._open = false; + let open = assistant.open(element); + select.disabled = false; + return open; +}); + +AsyncTests.add("Test:Previous", function(aMessage, aJson) { + let targetElement = content.document.querySelector(aJson.value); + assistant.currentIndex--; + return (assistant.currentElement == targetElement); +}); + +AsyncTests.add("Test:Next", function(aMessage, aJson) { + let targetElement = content.document.querySelector(aJson.value); + assistant.currentIndex++; + return (assistant.currentElement == targetElement); +}); + +// ============= iframe navigation ================== +let iframe = null; +let iframeInputs = null; +AsyncTests.add("Test:Iframe", function(aMessage, aJson) { + iframe = content.document.createElement("iframe"); + iframe.setAttribute("src", "data:text/html;charset=utf-8,%3Ciframe%20src%3D%22data%3Atext/html%3Bcharset%3Dutf-8%2C%253Cinput%253E%253Cbr%253E%253Cinput%253E%250A%22%3E%3C/iframe%3E"); + iframe.setAttribute("width", "300"); + iframe.setAttribute("height", "100"); + + iframe.addEventListener("load", function() { + iframe.removeEventListener("load", arguments.callee, false); + iframeInputs = iframe.contentDocument + .querySelector("iframe").contentDocument + .getElementsByTagName("input"); + sendAsyncMessage(aMessage, { result: true }); + }, false); + + content.document.body.appendChild(iframe); +}); + +AsyncTests.add("Test:IframeOpen", function(aMessage, aJson) { + return assistant.open(iframeInputs[0]); +}); + +AsyncTests.add("Test:IframePrevious", function(aMessage, aJson) { + assistant.currentIndex--; + return (assistant.currentElement == iframeInputs[aJson.value]); +}); + +AsyncTests.add("Test:IframeNext", function(aMessage, aJson) { + assistant.currentIndex++; + return (assistant.currentElement == iframeInputs[aJson.value]); +}); + diff --git a/mobile/android/chrome/tests/remote_formsZoom.js b/mobile/android/chrome/tests/remote_formsZoom.js new file mode 100644 index 00000000000..74cffac37d9 --- /dev/null +++ b/mobile/android/chrome/tests/remote_formsZoom.js @@ -0,0 +1,9 @@ +dump("====================== Content Script Loaded =======================\n"); + +let assistant = Content.formAssistant; + +AsyncTests.add("FormAssist:Show", function(aMessage, aJson) { + let element = content.document.getElementById(aJson.id); + assistant.open(element); +}); + diff --git a/mobile/android/chrome/tests/remote_head.js b/mobile/android/chrome/tests/remote_head.js new file mode 100644 index 00000000000..157d2e7b825 --- /dev/null +++ b/mobile/android/chrome/tests/remote_head.js @@ -0,0 +1,35 @@ +// XXX Those constants are here because EventUtils.js need them +window = content.document.defaultView.wrappedJSObject; +Element = Components.interfaces.nsIDOMElement; +netscape = window.netscape; + +let AsyncTests = { + _tests: [], + + add: function(aMessage, aCallback) { + addMessageListener(aMessage, this); + this._tests.push({ name: aMessage, callback: aCallback }); + }, + + receiveMessage: function(aMessage) { + let rv = { }; + let name = aMessage.name; + try { + let tests = this._tests; + for (let i = 0; i < tests.length; i++) { + if (tests[i].name == name) { + rv.result = tests[i].callback(name, aMessage.json); + break; + } + } + // Don't send test callback if rv.result == undefined, this allow to + // use a custom callback + if (rv.result != undefined) + sendAsyncMessage(name, rv); + } + catch(e) { + dump("receiveMessage: " + name + " - " + e + "\n"); + } + } +}; + diff --git a/mobile/android/chrome/tests/remote_vkb.js b/mobile/android/chrome/tests/remote_vkb.js new file mode 100644 index 00000000000..eb6b8283afc --- /dev/null +++ b/mobile/android/chrome/tests/remote_vkb.js @@ -0,0 +1,6 @@ +dump("====================== Content Script Loaded =======================\n"); + +AsyncTests.add("Test:FocusRoot", function(aMessage, aJson) { + content.document.getElementById("root").focus(); + return true; +}); diff --git a/mobile/android/components/AboutRedirector.js b/mobile/android/components/AboutRedirector.js new file mode 100644 index 00000000000..28f89b9ee9b --- /dev/null +++ b/mobile/android/components/AboutRedirector.js @@ -0,0 +1,163 @@ +/* ***** 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 About:FirstRun. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ryan Flint + * Justin Dolske + * Gavin Sharp + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +const Cc = Components.classes; +const Ci = Components.interfaces; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +let modules = { + // about:blank has some bad loading behavior we can avoid, if we use an alias + empty: { + uri: "about:blank", + privileged: false + }, + fennec: { + uri: "chrome://browser/content/about.xhtml", + privileged: true + }, + // about:firefox is an alias for about:fennec + get firefox() this.fennec, + + rights: { +#ifdef MOZ_OFFICIAL_BRANDING + uri: "chrome://browser/content/aboutRights.xhtml", +#else + uri: "chrome://global/content/aboutRights-unbranded.xhtml", +#endif + privileged: false + }, + blocked: { + uri: "chrome://browser/content/blockedSite.xhtml", + privileged: true + }, + certerror: { + uri: "chrome://browser/content/aboutCertError.xhtml", + privileged: true + }, + home: { + uri: "chrome://browser/content/aboutHome.xhtml", + privileged: true + } +} + +function AboutGeneric() {} +AboutGeneric.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]), + + _getModuleInfo: function (aURI) { + let moduleName = aURI.path.replace(/[?#].*/, "").toLowerCase(); + return modules[moduleName]; + }, + + // nsIAboutModule + getURIFlags: function(aURI) { + return Ci.nsIAboutModule.ALLOW_SCRIPT; + }, + + newChannel: function(aURI) { + let moduleInfo = this._getModuleInfo(aURI); + + var ios = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); + + var channel = ios.newChannel(moduleInfo.uri, null, null); + + if (!moduleInfo.privileged) { + let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]. + getService(Ci.nsIScriptSecurityManager); + let principal = secMan.getCodebasePrincipal(aURI); + channel.owner = principal; + } + + channel.originalURI = aURI; + + return channel; + } +}; + +function AboutEmpty() {} +AboutEmpty.prototype = { + __proto__: AboutGeneric.prototype, + classID: Components.ID("{433d2d75-5923-49b0-854d-f37267b03dc7}") +} + +function AboutFennec() {} +AboutFennec.prototype = { + __proto__: AboutGeneric.prototype, + classID: Components.ID("{842a6d11-b369-4610-ba66-c3b5217e82be}") +} + +function AboutFirefox() {} +AboutFirefox.prototype = { + __proto__: AboutGeneric.prototype, + classID: Components.ID("{dd40c467-d206-4f22-9215-8fcc74c74e38}") +} + +function AboutRights() {} +AboutRights.prototype = { + __proto__: AboutGeneric.prototype, + classID: Components.ID("{3b988fbf-ec97-4e1c-a5e4-573d999edc9c}") +} + +function AboutCertError() {} +AboutCertError.prototype = { + __proto__: AboutGeneric.prototype, + classID: Components.ID("{972efe64-8ac0-4e91-bdb0-22835d987815}") +} + +function AboutHome() {} +AboutHome.prototype = { + __proto__: AboutGeneric.prototype, + classID: Components.ID("{b071364f-ab68-4669-a9db-33fca168271a}") +} + +function AboutDougt() {} +AboutDougt.prototype = { + __proto__: AboutGeneric.prototype, + classID: Components.ID("{7490b75b-0ed4-4b2f-b80c-75e7f9c75682}") +} + +function AboutBlocked() {} +AboutBlocked.prototype = { + __proto__: AboutGeneric.prototype, + classID: Components.ID("{88fd40b6-c5c2-4120-9238-f2cb9ff98928}") +} + +const components = [AboutEmpty, AboutFennec, AboutRights, + AboutCertError, AboutFirefox, AboutHome, AboutDougt, AboutBlocked]; +const NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/mobile/android/components/AddonUpdateService.js b/mobile/android/components/AddonUpdateService.js new file mode 100644 index 00000000000..62c15d9f698 --- /dev/null +++ b/mobile/android/components/AddonUpdateService.js @@ -0,0 +1,234 @@ +/* ***** 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 Add-on Update Service. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyGetter(this, "AddonManager", function() { + Components.utils.import("resource://gre/modules/AddonManager.jsm"); + return AddonManager; +}); + +XPCOMUtils.defineLazyGetter(this, "AddonRepository", function() { + Components.utils.import("resource://gre/modules/AddonRepository.jsm"); + return AddonRepository; +}); + +XPCOMUtils.defineLazyGetter(this, "NetUtil", function() { + Components.utils.import("resource://gre/modules/NetUtil.jsm"); + return NetUtil; +}); + + +function getPref(func, preference, defaultValue) { + try { + return Services.prefs[func](preference); + } + catch (e) {} + return defaultValue; +} + +// ----------------------------------------------------------------------- +// Add-on auto-update management service +// ----------------------------------------------------------------------- + +const PREF_ADDON_UPDATE_ENABLED = "extensions.autoupdate.enabled"; + +var gNeedsRestart = false; + +function AddonUpdateService() {} + +AddonUpdateService.prototype = { + classDescription: "Add-on auto-update management", + classID: Components.ID("{93c8824c-9b87-45ae-bc90-5b82a1e4d877}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]), + + notify: function aus_notify(aTimer) { + if (aTimer && !getPref("getBoolPref", PREF_ADDON_UPDATE_ENABLED, true)) + return; + + // If we already auto-upgraded and installed new versions, ignore this check + if (gNeedsRestart) + return; + + Services.io.offline = false; + + // Assume we are doing a periodic update check + let reason = AddonManager.UPDATE_WHEN_PERIODIC_UPDATE; + if (!aTimer) + reason = AddonManager.UPDATE_WHEN_USER_REQUESTED; + + AddonManager.getAddonsByTypes(null, function(aAddonList) { + aAddonList.forEach(function(aAddon) { + if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE) { + let data = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); + data.data = JSON.stringify({ id: aAddon.id, name: aAddon.name }); + Services.obs.notifyObservers(data, "addon-update-started", null); + + let listener = new UpdateCheckListener(); + aAddon.findUpdates(listener, reason); + } + }); + }); + + RecommendedSearchResults.search(); + } +}; + +// ----------------------------------------------------------------------- +// Add-on update listener. Starts a download for any add-on with a viable +// update waiting +// ----------------------------------------------------------------------- + +function UpdateCheckListener() { + this._status = null; + this._version = null; +} + +UpdateCheckListener.prototype = { + onCompatibilityUpdateAvailable: function(aAddon) { + this._status = "compatibility"; + }, + + onUpdateAvailable: function(aAddon, aInstall) { + this._status = "update"; + this._version = aInstall.version; + aInstall.install(); + }, + + onNoUpdateAvailable: function(aAddon) { + if (!this._status) + this._status = "no-update"; + }, + + onUpdateFinished: function(aAddon, aError) { + let data = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); + if (this._version) + data.data = JSON.stringify({ id: aAddon.id, name: aAddon.name, version: this._version }); + else + data.data = JSON.stringify({ id: aAddon.id, name: aAddon.name }); + + if (aError) + this._status = "error"; + + Services.obs.notifyObservers(data, "addon-update-ended", this._status); + } +}; + +// ----------------------------------------------------------------------- +// RecommendedSearchResults fetches add-on data and saves it to a cache +// ----------------------------------------------------------------------- + +var RecommendedSearchResults = { + _getFile: function() { + let dirService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties); + let file = dirService.get("ProfD", Ci.nsILocalFile); + file.append("recommended-addons.json"); + return file; + }, + + _writeFile: function (aFile, aData) { + if (!aData) + return; + + // Initialize the file output stream. + let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); + ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN); + + // Obtain a converter to convert our data to a UTF-8 encoded input stream. + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + + // Asynchronously copy the data to the file. + let istream = converter.convertToInputStream(aData); + NetUtil.asyncCopy(istream, ostream, function(rc) { + if (Components.isSuccessCode(rc)) + Services.obs.notifyObservers(null, "recommended-addons-cache-updated", ""); + }); + }, + + searchSucceeded: function(aAddons, aAddonCount, aTotalResults) { + let self = this; + + // Filter addons already installed + AddonManager.getAllAddons(function(aAllAddons) { + let addons = aAddons.filter(function(addon) { + for (let i = 0; i < aAllAddons.length; i++) + if (addon.id == aAllAddons[i].id) + return false; + + return true; + }); + + let json = { + addons: [] + }; + + // Avoid any NSS costs. Convert https to http. + addons.forEach(function(aAddon){ + json.addons.push({ + id: aAddon.id, + name: aAddon.name, + version: aAddon.version, + description: aAddon.description, + averageRating: aAddon.averageRating, + iconURL: aAddon.iconURL.replace(/^https/, "http") + }) + }); + + let file = self._getFile(); + self._writeFile(file, JSON.stringify(json)); + }); + }, + + searchFailed: function searchFailed() { }, + + search: function() { + const kAddonsMaxDisplay = 2; + + if (AddonRepository.isSearching) + AddonRepository.cancelSearch(); + AddonRepository.retrieveRecommendedAddons(kAddonsMaxDisplay, RecommendedSearchResults); + } +} + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([AddonUpdateService]); + diff --git a/mobile/android/components/AlertsService.js b/mobile/android/components/AlertsService.js new file mode 100644 index 00000000000..c7f7d79661e --- /dev/null +++ b/mobile/android/components/AlertsService.js @@ -0,0 +1,59 @@ +/* ***** 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 Alerts Service. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +// ----------------------------------------------------------------------- +// Alerts Service +// ----------------------------------------------------------------------- + +function AlertsService() { } + +AlertsService.prototype = { + classID: Components.ID("{fe33c107-82a4-41d6-8c64-5353267e04c9}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]), + + showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName) { + let browser = Services.wm.getMostRecentWindow("navigator:browser"); + browser.AlertsHelper.showAlertNotification(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener); + } +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([AlertsService]); diff --git a/mobile/android/components/BlocklistPrompt.js b/mobile/android/components/BlocklistPrompt.js new file mode 100644 index 00000000000..87ec915a55c --- /dev/null +++ b/mobile/android/components/BlocklistPrompt.js @@ -0,0 +1,93 @@ +/* ***** 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 Alerts Service. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Wes Johnston + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cc = Components.classes; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +// ----------------------------------------------------------------------- +// BlocklistPrompt Service +// ----------------------------------------------------------------------- + + +function BlocklistPrompt() { } + +BlocklistPrompt.prototype = { + prompt: function(aAddons, aCount) { + let win = Services.wm.getMostRecentWindow("navigator:browser"); + if (win.ExtensionsView.visible) { + win.ExtensionsView.showRestart("blocked"); + } else { + let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); + let notifyBox = win.getNotificationBox(); + let restartCallback = function(aNotification, aDescription) { + // Notify all windows that an application quit has been requested + var 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 buttons = [{accessKey: null, + label: bundle.GetStringFromName("notificationRestart.button"), + callback: restartCallback}]; + notifyBox.appendNotification(bundle.GetStringFromName("notificationRestart.blocked"), + "blocked-add-on", + "", + "PRIORITY_CRITICAL_HIGH", + buttons); + } + // Disable softblocked items automatically + for (let i = 0; i < aAddons.length; i++) { + if (aAddons[i].item instanceof Ci.nsIPluginTag) + addonList[i].item.disabled = true; + else + aAddons[i].item.userDisabled = true; + } + }, + classID: Components.ID("{4e6ea350-b09a-11df-94e2-0800200c9a66}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIBlocklistPrompt]) +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([BlocklistPrompt]); + diff --git a/mobile/android/components/BrowserCLH.js b/mobile/android/components/BrowserCLH.js new file mode 100644 index 00000000000..40627dc4cd4 --- /dev/null +++ b/mobile/android/components/BrowserCLH.js @@ -0,0 +1,84 @@ +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + + +function dump(a) { + Cc["@mozilla.org/consoleservice;1"] + .getService(Ci.nsIConsoleService) + .logStringMessage(a); +} + +function openWindow(aParent, aURL, aTarget, aFeatures, aArgs) { + let argString = null; + if (aArgs && !(aArgs instanceof Ci.nsISupportsArray)) { + argString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); + argString.data = aArgs; + } + + return Services.ww.openWindow(aParent, aURL, aTarget, aFeatures, argString || aArgs); +} + + +function resolveURIInternal(aCmdLine, aArgument) { + let uri = aCmdLine.resolveURI(aArgument); + if (uri) + return uri; + + try { + let urifixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup); + uri = urifixup.createFixupURI(aArgument, 0); + } catch (e) { + Cu.reportError(e); + } + + return uri; +} + +function BrowserCLH() {} + +BrowserCLH.prototype = { + handle: function fs_handle(aCmdLine) { + let urlParam = "about:home"; + try { + urlParam = aCmdLine.handleFlagWithParam("remote", false); + } catch (e) { + // Optional so not a real error + } + dump("fs_handle: " + urlParam); + + try { + let uri = resolveURIInternal(aCmdLine, urlParam); + if (!uri) + return; + + let browserWin = Services.wm.getMostRecentWindow("navigator:browser"); + if (browserWin) { + browserWin.browserDOMWindow.openURI(uri, + null, + Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW, + Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL); + } else { + browserWin = openWindow(null, "chrome://browser/content/browser.xul", "_blank", "chrome,dialog=no,all", urlParam); + } + + aCmdLine.preventDefault = true; + } catch (x) { + Cc["@mozilla.org/consoleservice;1"] + .getService(Ci.nsIConsoleService) + .logStringMessage("fs_handle exception!: " + x); + } + }, + + // QI + QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]), + + // XPCOMUtils factory + classID: Components.ID("{be623d20-d305-11de-8a39-0800200c9a66}") +}; + +var components = [ BrowserCLH ]; +const NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/mobile/android/components/CapturePicker.js b/mobile/android/components/CapturePicker.js new file mode 100644 index 00000000000..78a28334812 --- /dev/null +++ b/mobile/android/components/CapturePicker.js @@ -0,0 +1,140 @@ +/* -*- Mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is CapturePicker.js + * + * 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): + * Kyle Huey + * Fabrice Desré + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +function CapturePicker() { + +} + +CapturePicker.prototype = { + _file: null, + _mode: -1, + _result: -1, + _shown: false, + _title: "", + _type: "", + _window: null, + _done: null, + + // + // nsICapturePicker + // + init: function(aWindow, aTitle, aMode) { + this._window = aWindow; + this._title = aTitle; + this._mode = aMode; + }, + + show: function() { + if (this._shown) + throw Cr.NS_ERROR_UNEXPECTED; + + this._shown = true; + this._file = null; + this._done = false; + + Services.obs.addObserver(this, "cameraCaptureDone", false); + + let msg = { gecko: { type: "onCameraCapture" } }; + Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge).handleGeckoMessage(JSON.stringify(msg)); + + // we need to turn all the async messaging into a blocking call + while (!this._done) + Services.tm.currentThread.processNextEvent(true); + + if (this._res.ok) { + this._file = this._res.path; + // delete the file when exiting + let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); + file.initWithPath(this._res.path); + Cc["@mozilla.org/uriloader/external-helper-app-service;1"].getService(Ci.nsPIExternalAppLauncher).deleteTemporaryFileOnExit(file); + } + + return (this._res.ok ? Ci.nsICapturePicker.RETURN_OK : Ci.nsICapturePicker.RETURN_CANCEL); + }, + + observe: function(aObject, aTopic, aData) { + Services.obs.removeObserver(this, "cameraCaptureDone"); + this._done = true; + this._res = JSON.parse(aData); + }, + + modeMayBeAvailable: function(aMode) { + if (aMode != Ci.nsICapturePicker.MODE_STILL) + return false; + return true; + }, + + get file() { + if (this._file) { + let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); + file.initWithPath(this._file); + let utils = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); + return utils.wrapDOMFile(file); + } else { + throw Cr.NS_ERROR_FAILURE; + } + }, + + get type() { + return this._type; + }, + + set type(aNewType) { + if (this._shown) + throw Cr.NS_ERROR_UNEXPECTED; + else + this._type = aNewType; + }, + + // QI + QueryInterface: XPCOMUtils.generateQI([Ci.nsICapturePicker, Ci.nsIObserver]), + + // XPCOMUtils factory + classID: Components.ID("{cb5a47f0-b58c-4fc3-b61a-358ee95f8238}"), +}; + +var components = [ CapturePicker ]; +const NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/mobile/android/components/ContentDispatchChooser.js b/mobile/android/components/ContentDispatchChooser.js new file mode 100644 index 00000000000..49025c69537 --- /dev/null +++ b/mobile/android/components/ContentDispatchChooser.js @@ -0,0 +1,70 @@ +/* ***** 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 Content Dispatch Chooser. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +function ContentDispatchChooser() {} + +ContentDispatchChooser.prototype = +{ + classID: Components.ID("5a072a22-1e66-4100-afc1-07aed8b62fc5"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentDispatchChooser]), + + ask: function ask(aHandler, aWindowContext, aURI, aReason) { + let window = null; + try { + if (aWindowContext) + window = aWindowContext.getInterface(Ci.nsIDOMWindow); + } catch (e) { /* it's OK to not have a window */ } + + let bundle = Services.strings.createBundle("chrome://mozapps/locale/handling/handling.properties"); + + let title = bundle.GetStringFromName("protocol.title"); + let message = bundle.GetStringFromName("protocol.description"); + + let open = Services.prompt.confirm(window, title, message); + if (open) + aHandler.launchWithURI(aURI, aWindowContext); + } +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentDispatchChooser]); + diff --git a/mobile/android/components/ContentPermissionPrompt.js b/mobile/android/components/ContentPermissionPrompt.js new file mode 100644 index 00000000000..755447eb2a9 --- /dev/null +++ b/mobile/android/components/ContentPermissionPrompt.js @@ -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.org 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 + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; +const Cc = Components.classes; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +const kCountBeforeWeRemember = 5; + +function dump(a) { + Cc["@mozilla.org/consoleservice;1"] + .getService(Ci.nsIConsoleService) + .logStringMessage(a); +} + +function setPagePermission(type, uri, allow) { + let pm = Services.perms; + let contentPrefs = Services.contentPrefs; + let contentPrefName = type + ".request.remember"; + + if (!contentPrefs.hasPref(uri, contentPrefName)) + contentPrefs.setPref(uri, contentPrefName, 0); + + let count = contentPrefs.getPref(uri, contentPrefName); + + if (allow == false) + count--; + else + count++; + + contentPrefs.setPref(uri, contentPrefName, count); + if (count == kCountBeforeWeRemember) + pm.add(uri, type, Ci.nsIPermissionManager.ALLOW_ACTION); + else if (count == -kCountBeforeWeRemember) + pm.add(uri, type, Ci.nsIPermissionManager.DENY_ACTION); +} + +const kEntities = { "geolocation": "geolocation", "desktop-notification": "desktopNotification", + "indexedDB": "offlineApps", "indexedDBQuota": "indexedDBQuota", + "openWebappsManage": "openWebappsManage" }; + +function ContentPermissionPrompt() {} + +ContentPermissionPrompt.prototype = { + classID: Components.ID("{C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]), + + handleExistingPermission: function handleExistingPermission(request) { + let result = Services.perms.testExactPermission(request.uri, request.type); + if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { + request.allow(); + return true; + } + if (result == Ci.nsIPermissionManager.DENY_ACTION) { + request.cancel(); + return true; + } + return false; + }, + + getChromeWindow: function getChromeWindow(aWindow) { + let chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow) + .QueryInterface(Ci.nsIDOMChromeWindow); + return chromeWin; + }, + + getChromeForRequest: function getChromeForRequest(request) { + if (request.window) { + let requestingWindow = request.window.top; + return this.getChromeWindow(requestingWindow).wrappedJSObject; + } + return request.element.ownerDocument.defaultView; + }, + + getTabForRequest: function getTabForRequest(request) { + let chromeWin = this.getChromeForRequest(request); + if (request.window) { + let browser = chromeWin.BrowserApp.getBrowserForWindow(request.window); + let tabID = chromeWin.BrowserApp.getTabForBrowser(browser).id; + return tabID; + } + // Fix this if e10s is needed again + return null; + }, + + prompt: function(request) { + // returns true if the request was handled + if (this.handleExistingPermission(request)) + return; + + let pm = Services.perms; + let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); + + let entityName = kEntities[request.type]; + + let tabID = this.getTabForRequest(request); + let chromeWin = this.getChromeForRequest(request); + + let buttons = [{ + label: browserBundle.GetStringFromName(entityName + ".allow"), + accessKey: null, + callback: function(notification) { + setPagePermission(request.type, request.uri, true); + request.allow(); + } + }, + { + label: browserBundle.GetStringFromName(entityName + ".dontAllow"), + accessKey: null, + callback: function(notification) { + setPagePermission(request.type, request.uri, false); + request.cancel(); + } + }]; + + let message = browserBundle.formatStringFromName(entityName + ".wantsTo", + [request.uri.host], 1); + + chromeWin.NativeWindow.doorhanger.show(message, + entityName + request.uri.host, + buttons, tabID); + } +}; + + +//module initialization +const NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]); diff --git a/mobile/android/components/DirectoryProvider.js b/mobile/android/components/DirectoryProvider.js new file mode 100644 index 00000000000..684a83f12a8 --- /dev/null +++ b/mobile/android/components/DirectoryProvider.js @@ -0,0 +1,99 @@ +/* ***** 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 XPI Dialog Service. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +// ----------------------------------------------------------------------- +// Directory Provider for special browser folders and files +// ----------------------------------------------------------------------- + +const NS_APP_CACHE_PARENT_DIR = "cachePDir"; +const XRE_UPDATE_ROOT_DIR = "UpdRootD"; +const ENVVAR_UPDATE_DIR = "UPDATES_DIRECTORY"; + +function DirectoryProvider() {} + +DirectoryProvider.prototype = { + classID: Components.ID("{ef0f7a87-c1ee-45a8-8d67-26f586e46a4b}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]), + + getFile: function(prop, persistent) { + if (prop == NS_APP_CACHE_PARENT_DIR) { + let dirsvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties); + let profile = dirsvc.get("ProfD", Ci.nsIFile); + + let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2); + let device = sysInfo.get("device"); + switch (device) { +#ifdef MOZ_PLATFORM_MAEMO + case "Nokia N900": + return profile; + + case "Nokia N8xx": + let folder = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); + folder.initWithPath("/media/mmc2/.mozilla/fennec"); + return folder; +#endif + default: + return profile; + } + } else if (prop == XRE_UPDATE_ROOT_DIR) { + let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); + if (env.exists(ENVVAR_UPDATE_DIR)) { + let path = env.get(ENVVAR_UPDATE_DIR); + if (path) { + let localFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); + localFile.initWithPath(path); + return localFile; + } + } + let dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager); + return dm.defaultDownloadsDirectory; + } + + // We are retuning null to show failure instead for throwing an error. The + // interface is called quite a bit and throwing an error is noisy. Returning + // null works with the way the interface is called [see bug 529077] + return null; + } +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([DirectoryProvider]); + diff --git a/mobile/android/components/DownloadManagerUI.js b/mobile/android/components/DownloadManagerUI.js new file mode 100644 index 00000000000..83dd8ab7dd7 --- /dev/null +++ b/mobile/android/components/DownloadManagerUI.js @@ -0,0 +1,78 @@ +/* ***** 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 Download Manager UI. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Ci = Components.interfaces; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); + +// ----------------------------------------------------------------------- +// Download Manager UI +// ----------------------------------------------------------------------- + +function DownloadManagerUI() { } + +DownloadManagerUI.prototype = { + classID: Components.ID("{93db15b1-b408-453e-9a2b-6619e168324a}"), + + show: function show(aWindowContext, aID, aReason) { + if (!aReason) + aReason = Ci.nsIDownloadManagerUI.REASON_USER_INTERACTED; + + let browser = Services.wm.getMostRecentWindow("navigator:browser"); + if (browser) + browser.showDownloadManager(aWindowContext, aID, aReason); + }, + + get visible() { + let browser = Services.wm.getMostRecentWindow("navigator:browser"); + if (browser) { + return browser.DownloadsView.visible; + } + return false; + }, + + getAttention: function getAttention() { + if (this.visible) + this.show(null, null, null); + else + throw Cr.NS_ERROR_UNEXPECTED; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadManagerUI]) +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([DownloadManagerUI]); diff --git a/mobile/android/components/FormAutoComplete.js b/mobile/android/components/FormAutoComplete.js new file mode 100644 index 00000000000..cf142b7bc7c --- /dev/null +++ b/mobile/android/components/FormAutoComplete.js @@ -0,0 +1,172 @@ +/* ***** 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 Form Autocomplete Plus. + * + * 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): + * Mark Finkle + * Dan Mills + * Justin Dolske + * Michael Hanson + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +function LOG() { + return; // comment out for verbose debugging + let msg = Array.join(arguments, " "); + dump(msg + "\n"); + Cu.reportError(msg); +} + +// Lazily get the base Form AutoComplete Search +XPCOMUtils.defineLazyGetter(this, "FAC", function() { + return Components.classesByID["{c11c21b2-71c9-4f87-a0f8-5e13f50495fd}"] + .getService(Ci.nsIFormAutoComplete); +}); + +XPCOMUtils.defineLazyGetter(this, "Contacts", function() { + Cu.import("resource:///modules/contacts.jsm"); + return Contacts; +}); + +function FormAutoComplete() { + LOG("new FAC"); +} + +FormAutoComplete.prototype = { + classDescription: "Form AutoComplete Plus", + classID: Components.ID("{cccd414c-3ec2-4cc5-9dc4-36c87cc3c4fe}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIFormAutoComplete]), + + // Specify the html5 types that we want and some values to guess + contactTypes: { + email: /^(?:.*(?:e-?mail|recipients?).*|(send_)?to(_b?cc)?)$/i, + tel: /^(?:tel(?:ephone)?|.*phone.*)$/i + }, + + checkQueryType: function checkQueryType(aName, aField) { + // If we have an input field with the desired html5 type, take it! + if (aField && "type" in aField) { + let type = aField.type; + if (type && type in this.contactTypes) + return type; + } + + // Grab properties to check for contact inputs + let props = [aName]; + if (aField) { + let specialProps = [aField["className"], aField["id"]]; + props = props.concat(specialProps.filter(function(aValue) { + return aValue; + })); + } + + // Check the gathered properties for contact-like values + for (let [type, regex] in Iterator(this.contactTypes)) { + if (props.some(function(prop) prop.search(regex) != -1)) + return type; + } + return null; + }, + + findContact: function findContact(aQuery, aType, aResult, aDupCheck) { + // Match the name and show the email for now.. + Contacts.find({ fullName: aQuery }).forEach(function(contact) { + // Might not have an email for some reason... ? + try { + LOG("findContact", "Contact " + contact.fullName); + + let suggestions; + switch (aType) { + case "email": + suggestions = contact.emails; + break; + case "tel": + suggestions = contact.phoneNumbers; + break; + default: + LOG("unknown type!", aType); + return; + } + + for each (let suggestion in suggestions) { + if (aDupCheck[suggestion]) + continue; + aDupCheck[suggestion] = true; + + let data = contact.fullName + " <" + suggestion + ">"; + aResult.appendMatch(suggestion, data, null, "contact"); + } + } + catch(ex) { + LOG("findContact error", ex); + } + }); + }, + + autoCompleteSearch: function autoCompleteSearch(aName, aQuery, aField, aPrev) { + if (!Services.prefs.getBoolPref("browser.formfill.enable")) + return null; + + LOG("autocomplete search", Array.slice(arguments)); + let result = Cc["@mozilla.org/autocomplete/simple-result;1"].createInstance(Ci.nsIAutoCompleteSimpleResult); + result.setSearchString(aQuery); + + // Don't allow duplicates get merged into the final results + let dupCheck = {}; + + // Use the base form autocomplete for non-contact searches + let normal = FAC.autoCompleteSearch(aName, aQuery, aField, aPrev); + if (normal.matchCount > 0) { + for (let i = 0; i < normal.matchCount; i++) { + dupCheck[normal.getValueAt(i)] = true; + result.appendMatch(normal.getValueAt(i), normal.getCommentAt(i), normal.getImageAt(i), normal.getStyleAt(i)); + } + } + + // Do searches for certain input fields + let type = this.checkQueryType(aName, aField); + if (type != null) + this.findContact(aQuery, type, result, dupCheck); + + let resultCode = result.matchCount ? "RESULT_SUCCESS" : "RESULT_NOMATCH"; + result.setSearchResult(Ci.nsIAutoCompleteResult[resultCode]); + return result; + } +}; + +let components = [FormAutoComplete]; +const NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/mobile/android/components/HelperAppDialog.js b/mobile/android/components/HelperAppDialog.js new file mode 100644 index 00000000000..c9f1ef0303a --- /dev/null +++ b/mobile/android/components/HelperAppDialog.js @@ -0,0 +1,252 @@ +/* ***** 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 HelperApp Launcher Dialog. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +const PREF_BD_USEDOWNLOADDIR = "browser.download.useDownloadDir"; +#ifdef ANDROID +const URI_GENERIC_ICON_DOWNLOAD = "drawable://alertdownloads"; +#else +const URI_GENERIC_ICON_DOWNLOAD = "chrome://browser/skin/images/alert-downloads-30.png"; +#endif + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +// ----------------------------------------------------------------------- +// HelperApp Launcher Dialog +// ----------------------------------------------------------------------- + +function HelperAppLauncherDialog() { } + +HelperAppLauncherDialog.prototype = { + classID: Components.ID("{e9d277a0-268a-4ec2-bb8c-10fdf3e44611}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]), + + show: function hald_show(aLauncher, aContext, aReason) { + // Check to see if we can open this file or not + if (aLauncher.MIMEInfo.hasDefaultHandler) { + aLauncher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.useSystemDefault; + aLauncher.launchWithApplication(null, false); + } else { + let wasClicked = false; + let listener = { + observe: function(aSubject, aTopic, aData) { + if (aTopic == "alertclickcallback") { + wasClicked = true; + let win = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator).getMostRecentWindow("navigator:browser"); + if (win) + win.BrowserUI.showPanel("downloads-container"); + + aLauncher.saveToDisk(null, false); + } else { + if (!wasClicked) + aLauncher.cancel(Cr.NS_BINDING_ABORTED); + } + } + }; + this._notify(aLauncher, listener); + } + }, + + promptForSaveToFile: function hald_promptForSaveToFile(aLauncher, aContext, aDefaultFile, aSuggestedFileExt, aForcePrompt) { + let file = null; + let prefs = Services.prefs; + + if (!aForcePrompt) { + // Check to see if the user wishes to auto save to the default download + // folder without prompting. Note that preference might not be set. + let autodownload = true; + try { + autodownload = prefs.getBoolPref(PREF_BD_USEDOWNLOADDIR); + } catch (e) { } + + if (autodownload) { + // Retrieve the user's default download directory + let dnldMgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager); + let defaultFolder = dnldMgr.userDownloadsDirectory; + + try { + file = this.validateLeafName(defaultFolder, aDefaultFile, aSuggestedFileExt); + } + catch (e) { + } + + // Check to make sure we have a valid directory, otherwise, prompt + if (file) + return file; + } + } + + // Use file picker to show dialog. + let picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); + let windowTitle = ""; + let parent = aContext.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow); + picker.init(parent, windowTitle, Ci.nsIFilePicker.modeSave); + picker.defaultString = aDefaultFile; + + if (aSuggestedFileExt) { + // aSuggestedFileExtension includes the period, so strip it + picker.defaultExtension = aSuggestedFileExt.substring(1); + } + else { + try { + picker.defaultExtension = aLauncher.MIMEInfo.primaryExtension; + } + catch (e) { } + } + + var wildCardExtension = "*"; + if (aSuggestedFileExt) { + wildCardExtension += aSuggestedFileExt; + picker.appendFilter(aLauncher.MIMEInfo.description, wildCardExtension); + } + + picker.appendFilters(Ci.nsIFilePicker.filterAll); + + // Default to lastDir if it is valid, otherwise use the user's default + // downloads directory. userDownloadsDirectory should always return a + // valid directory, so we can safely default to it. + var dnldMgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager); + picker.displayDirectory = dnldMgr.userDownloadsDirectory; + + // The last directory preference may not exist, which will throw. + try { + let lastDir = prefs.getComplexValue("browser.download.lastDir", Ci.nsILocalFile); + if (isUsableDirectory(lastDir)) + picker.displayDirectory = lastDir; + } + catch (e) { } + + if (picker.show() == Ci.nsIFilePicker.returnCancel) { + // null result means user cancelled. + return null; + } + + // Be sure to save the directory the user chose through the Save As... + // dialog as the new browser.download.dir since the old one + // didn't exist. + file = picker.file; + + if (file) { + try { + // Remove the file so that it's not there when we ensure non-existence later; + // this is safe because for the file to exist, the user would have had to + // confirm that he wanted the file overwritten. + if (file.exists()) + file.remove(false); + } + catch (e) { } + var newDir = file.parent.QueryInterface(Ci.nsILocalFile); + prefs.setComplexValue("browser.download.lastDir", Ci.nsILocalFile, newDir); + file = this.validateLeafName(newDir, file.leafName, null); + } + return file; + }, + + validateLeafName: function hald_validateLeafName(aLocalFile, aLeafName, aFileExt) { + if (!(aLocalFile && this.isUsableDirectory(aLocalFile))) + return null; + + // Remove any leading periods, since we don't want to save hidden files + // automatically. + aLeafName = aLeafName.replace(/^\.+/, ""); + + if (aLeafName == "") + aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : ""); + aLocalFile.append(aLeafName); + + this.makeFileUnique(aLocalFile); + return aLocalFile; + }, + + makeFileUnique: function hald_makeFileUnique(aLocalFile) { + try { + // Note - this code is identical to that in + // toolkit/content/contentAreaUtils.js. + // If you are updating this code, update that code too! We can't share code + // here since this is called in a js component. + var collisionCount = 0; + while (aLocalFile.exists()) { + collisionCount++; + if (collisionCount == 1) { + // Append "(2)" before the last dot in (or at the end of) the filename + // special case .ext.gz etc files so we don't wind up with .tar(2).gz + if (aLocalFile.leafName.match(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i)) + aLocalFile.leafName = aLocalFile.leafName.replace(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i, "(2)$&"); + else + aLocalFile.leafName = aLocalFile.leafName.replace(/(\.[^\.]*)?$/, "(2)$&"); + } + else { + // replace the last (n) in the filename with (n+1) + aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount+1) + ")"); + } + } + aLocalFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0600); + } + catch (e) { + dump("*** exception in validateLeafName: " + e + "\n"); + + if (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED) + throw e; + + if (aLocalFile.leafName == "" || aLocalFile.isDirectory()) { + aLocalFile.append("unnamed"); + if (aLocalFile.exists()) + aLocalFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600); + } + } + }, + + isUsableDirectory: function hald_isUsableDirectory(aDirectory) { + return aDirectory.exists() && aDirectory.isDirectory() && aDirectory.isWritable(); + }, + + _notify: function hald_notify(aLauncher, aCallback) { + let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); + + let notifier = Cc[aCallback ? "@mozilla.org/alerts-service;1" : "@mozilla.org/toaster-alerts-service;1"].getService(Ci.nsIAlertsService); + notifier.showAlertNotification(URI_GENERIC_ICON_DOWNLOAD, + bundle.GetStringFromName("alertDownloads"), + bundle.GetStringFromName("alertCantOpenDownload"), + true, "", aCallback, "downloadopen-fail"); + } +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([HelperAppLauncherDialog]); diff --git a/mobile/android/components/LoginManagerPrompter.js b/mobile/android/components/LoginManagerPrompter.js new file mode 100644 index 00000000000..3928443744a --- /dev/null +++ b/mobile/android/components/LoginManagerPrompter.js @@ -0,0 +1,655 @@ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Justin Dolske (original author) + * Ehsan Akhgari + * Wes Johnston + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); + +/* ==================== LoginManagerPrompter ==================== */ +/* + * LoginManagerPrompter + * + * Implements interfaces for prompting the user to enter/save/change auth info. + * + * nsILoginManagerPrompter: Used by Login Manager for saving/changing logins + * found in HTML forms. + */ +function LoginManagerPrompter() { +} + +LoginManagerPrompter.prototype = { + + classID : Components.ID("97d12931-abe2-11df-94e2-0800200c9a66"), + QueryInterface : XPCOMUtils.generateQI([Ci.nsILoginManagerPrompter]), + + _factory : null, + _window : null, + _debug : false, // mirrors signon.debug + + __pwmgr : null, // Password Manager service + get _pwmgr() { + if (!this.__pwmgr) + this.__pwmgr = Cc["@mozilla.org/login-manager;1"]. + getService(Ci.nsILoginManager); + return this.__pwmgr; + }, + + __promptService : null, // Prompt service for user interaction + get _promptService() { + if (!this.__promptService) + this.__promptService = + Cc["@mozilla.org/embedcomp/prompt-service;1"]. + getService(Ci.nsIPromptService2); + return this.__promptService; + }, + + __strBundle : null, // String bundle for L10N + get _strBundle() { + if (!this.__strBundle) { + var bunService = Cc["@mozilla.org/intl/stringbundle;1"]. + getService(Ci.nsIStringBundleService); + this.__strBundle = bunService.createBundle( + "chrome://passwordmgr/locale/passwordmgr.properties"); + if (!this.__strBundle) + throw "String bundle for Login Manager not present!"; + } + + return this.__strBundle; + }, + + __brandBundle : null, // String bundle for L10N + get _brandBundle() { + if (!this.__brandBundle) { + var bunService = Cc["@mozilla.org/intl/stringbundle;1"]. + getService(Ci.nsIStringBundleService); + this.__brandBundle = bunService.createBundle( + "chrome://branding/locale/brand.properties"); + if (!this.__brandBundle) + throw "Branding string bundle not present!"; + } + + return this.__brandBundle; + }, + + + __ellipsis : null, + get _ellipsis() { + if (!this.__ellipsis) { + this.__ellipsis = "\u2026"; + try { + this.__ellipsis = Services.prefs.getComplexValue( + "intl.ellipsis", Ci.nsIPrefLocalizedString).data; + } catch (e) { } + } + return this.__ellipsis; + }, + + + /* + * log + * + * Internal function for logging debug messages to the Error Console window. + */ + log : function (message) { + if (!this._debug) + return; + + dump("Pwmgr Prompter: " + message + "\n"); + Services.console.logStringMessage("Pwmgr Prompter: " + message); + }, + + + /* ---------- nsILoginManagerPrompter prompts ---------- */ + + + + + /* + * init + * + */ + init : function (aWindow, aFactory) { + this._window = aWindow; + this._factory = aFactory || null; + + var prefBranch = Services.prefs.getBranch("signon."); + this._debug = prefBranch.getBoolPref("debug"); + this.log("===== initialized ====="); + }, + + + /* + * promptToSavePassword + * + */ + promptToSavePassword : function (aLogin) { + var nativeWindow = this._getNativeWindow(); + + if (nativeWindow) + this._showSaveLoginNotification(nativeWindow, aLogin); + else + this._showSaveLoginDialog(aLogin); + }, + + + /* + * _showLoginNotification + * + * Displays a notification doorhanger. + * + */ + _showLoginNotification : function (aNativeWindow, aName, aText, aButtons) { + this.log("Adding new " + aName + " notification bar"); + let notifyWin = this._window.top; + let chromeWin = this._getChromeWindow(notifyWin).wrappedJSObject; + let browser = chromeWin.BrowserApp.getBrowserForWindow(notifyWin); + let tabID = chromeWin.BrowserApp.getTabForBrowser(browser).id; + + // The page we're going to hasn't loaded yet, so we want to persist + // across the first location change. + + // Sites like Gmail perform a funky redirect dance before you end up + // at the post-authentication page. I don't see a good way to + // heuristically determine when to ignore such location changes, so + // we'll try ignoring location changes based on a time interval. + + let options = { + persistence: 1, + timeout: Date.now() + 20000 + } + + aNativeWindow.doorhanger.show(aText, aName, aButtons, tabID, options); + }, + + + /* + * _showSaveLoginNotification + * + * Displays a notification doorhanger (rather than a popup), to allow the user to + * save the specified login. This allows the user to see the results of + * their login, and only save a login which they know worked. + * + */ + _showSaveLoginNotification : function (aNativeWindow, aLogin) { + + // Ugh. We can't use the strings from the popup window, because they + // have the access key marked in the string (eg "Mo&zilla"), along + // with some weird rules for handling access keys that do not occur + // in the string, for L10N. See commonDialog.js's setLabelForNode(). + var neverButtonText = + this._getLocalizedString("notifyBarNeverForSiteButtonText"); + var neverButtonAccessKey = + this._getLocalizedString("notifyBarNeverForSiteButtonAccessKey"); + var rememberButtonText = + this._getLocalizedString("notifyBarRememberButtonText"); + var rememberButtonAccessKey = + this._getLocalizedString("notifyBarRememberButtonAccessKey"); + var notNowButtonText = + this._getLocalizedString("notifyBarNotNowButtonText"); + var notNowButtonAccessKey = + this._getLocalizedString("notifyBarNotNowButtonAccessKey"); + + var brandShortName = + this._brandBundle.GetStringFromName("brandShortName"); + var displayHost = this._getShortDisplayHost(aLogin.hostname); + var notificationText; + if (aLogin.username) { + var displayUser = this._sanitizeUsername(aLogin.username); + notificationText = this._getLocalizedString( + "saveLoginText", + [brandShortName, displayUser, displayHost]); + } else { + notificationText = this._getLocalizedString( + "saveLoginTextNoUsername", + [brandShortName, displayHost]); + } + + // The callbacks in |buttons| have a closure to access the variables + // in scope here; set one to |this._pwmgr| so we can get back to pwmgr + // without a getService() call. + var pwmgr = this._pwmgr; + + + var buttons = [ + // "Remember" button + { + label: rememberButtonText, + accessKey: rememberButtonAccessKey, + popup: null, + callback: function(aNotificationBar, aButton) { + pwmgr.addLogin(aLogin); + } + }, + + // "Never for this site" button + { + label: neverButtonText, + accessKey: neverButtonAccessKey, + popup: null, + callback: function(aNotificationBar, aButton) { + pwmgr.setLoginSavingEnabled(aLogin.hostname, false); + } + }, + + // "Not now" button + { + label: notNowButtonText, + accessKey: notNowButtonAccessKey, + popup: null, + callback: function() { /* NOP */ } + } + ]; + + this._showLoginNotification(aNativeWindow, "password-save", + notificationText, buttons); + }, + + + /* + * _showSaveLoginDialog + * + * Called when we detect a new login in a form submission, + * asks the user what to do. + * + */ + _showSaveLoginDialog : function (aLogin) { + const buttonFlags = Ci.nsIPrompt.BUTTON_POS_1_DEFAULT + + (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) + + (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1) + + (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_2); + + var brandShortName = + this._brandBundle.GetStringFromName("brandShortName"); + var displayHost = this._getShortDisplayHost(aLogin.hostname); + + var dialogText; + if (aLogin.username) { + var displayUser = this._sanitizeUsername(aLogin.username); + dialogText = this._getLocalizedString( + "saveLoginText", + [brandShortName, displayUser, displayHost]); + } else { + dialogText = this._getLocalizedString( + "saveLoginTextNoUsername", + [brandShortName, displayHost]); + } + var dialogTitle = this._getLocalizedString( + "savePasswordTitle"); + var neverButtonText = this._getLocalizedString( + "promptNeverForSiteButtonText"); + var rememberButtonText = this._getLocalizedString( + "promptRememberButtonText"); + var notNowButtonText = this._getLocalizedString( + "promptNotNowButtonText"); + + this.log("Prompting user to save/ignore login"); + var userChoice = this._promptService.confirmEx(null, + dialogTitle, dialogText, + buttonFlags, rememberButtonText, + notNowButtonText, neverButtonText, + null, {}); + // Returns: + // 0 - Save the login + // 1 - Ignore the login this time + // 2 - Never save logins for this site + if (userChoice == 2) { + this.log("Disabling " + aLogin.hostname + " logins by request."); + this._pwmgr.setLoginSavingEnabled(aLogin.hostname, false); + } else if (userChoice == 0) { + this.log("Saving login for " + aLogin.hostname); + this._pwmgr.addLogin(aLogin); + } else { + // userChoice == 1 --> just ignore the login. + this.log("Ignoring login."); + } + }, + + /* + * promptToChangePassword + * + * Called when we think we detect a password change for an existing + * login, when the form being submitted contains multiple password + * fields. + * + */ + promptToChangePassword : function (aOldLogin, aNewLogin) { + var nativeWindow = this._getNativeWindow(); + + if (nativeWindow) + this._showChangeLoginNotification(nativeWindow, aOldLogin, aNewLogin.password); + else + this._showChangeLoginDialog(aOldLogin, aNewLogin.password); + }, + + /* + * _showChangeLoginNotification + * + * Shows the Change Password notification doorhanger. + * + */ + _showChangeLoginNotification : function (aNativeWindow, aOldLogin, aNewPassword) { + var notificationText; + if (aOldLogin.username) + notificationText = this._getLocalizedString( + "passwordChangeText", + [aOldLogin.username]); + else + notificationText = this._getLocalizedString( + "passwordChangeTextNoUser"); + + var changeButtonText = + this._getLocalizedString("notifyBarChangeButtonText"); + var changeButtonAccessKey = + this._getLocalizedString("notifyBarChangeButtonAccessKey"); + var dontChangeButtonText = + this._getLocalizedString("notifyBarDontChangeButtonText"); + var dontChangeButtonAccessKey = + this._getLocalizedString("notifyBarDontChangeButtonAccessKey"); + + // The callbacks in |buttons| have a closure to access the variables + // in scope here; set one to |this._pwmgr| so we can get back to pwmgr + // without a getService() call. + var self = this; + + var buttons = [ + // "Yes" button + { + label: changeButtonText, + accessKey: changeButtonAccessKey, + popup: null, + callback: function(aNotificationBar, aButton) { + self._updateLogin(aOldLogin, aNewPassword); + } + }, + + // "No" button + { + label: dontChangeButtonText, + accessKey: dontChangeButtonAccessKey, + popup: null, + callback: function(aNotificationBar, aButton) { + // do nothing + } + } + ]; + + this._showLoginNotification(aNativeWindow, "password-change", + notificationText, buttons); + }, + + /* + * _showChangeLoginDialog + * + * Shows the Change Password dialog. + * + */ + _showChangeLoginDialog : function (aOldLogin, aNewPassword) { + const buttonFlags = Ci.nsIPrompt.STD_YES_NO_BUTTONS; + + var dialogText; + if (aOldLogin.username) + dialogText = this._getLocalizedString( + "passwordChangeText", + [aOldLogin.username]); + else + dialogText = this._getLocalizedString( + "passwordChangeTextNoUser"); + + var dialogTitle = this._getLocalizedString( + "passwordChangeTitle"); + + // returns 0 for yes, 1 for no. + var ok = !this._promptService.confirmEx(null, + dialogTitle, dialogText, buttonFlags, + null, null, null, + null, {}); + if (ok) { + this.log("Updating password for user " + aOldLogin.username); + this._updateLogin(aOldLogin, aNewPassword); + } + }, + + + /* + * promptToChangePasswordWithUsernames + * + * Called when we detect a password change in a form submission, but we + * don't know which existing login (username) it's for. Asks the user + * to select a username and confirm the password change. + * + * Note: The caller doesn't know the username for aNewLogin, so this + * function fills in .username and .usernameField with the values + * from the login selected by the user. + * + * Note; XPCOM stupidity: |count| is just |logins.length|. + */ + promptToChangePasswordWithUsernames : function (logins, count, aNewLogin) { + const buttonFlags = Ci.nsIPrompt.STD_YES_NO_BUTTONS; + + var usernames = logins.map(function (l) l.username); + var dialogText = this._getLocalizedString("userSelectText"); + var dialogTitle = this._getLocalizedString("passwordChangeTitle"); + var selectedIndex = { value: null }; + + // If user selects ok, outparam.value is set to the index + // of the selected username. + var ok = this._promptService.select(null, + dialogTitle, dialogText, + usernames.length, usernames, + selectedIndex); + if (ok) { + // Now that we know which login to use, modify its password. + var selectedLogin = logins[selectedIndex.value]; + this.log("Updating password for user " + selectedLogin.username); + this._updateLogin(selectedLogin, aNewLogin.password); + } + }, + + + + + /* ---------- Internal Methods ---------- */ + + + + + /* + * _updateLogin + */ + _updateLogin : function (login, newPassword) { + var now = Date.now(); + var propBag = Cc["@mozilla.org/hash-property-bag;1"]. + createInstance(Ci.nsIWritablePropertyBag); + if (newPassword) { + propBag.setProperty("password", newPassword); + // Explicitly set the password change time here (even though it would + // be changed automatically), to ensure that it's exactly the same + // value as timeLastUsed. + propBag.setProperty("timePasswordChanged", now); + } + propBag.setProperty("timeLastUsed", now); + propBag.setProperty("timesUsedIncrement", 1); + this._pwmgr.modifyLogin(login, propBag); + }, + + /* + * _getChromeWindow + * + * Given a content DOM window, returns the chrome window it's in. + */ + _getChromeWindow: function (aWindow) { + var chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .chromeEventHandler.ownerDocument.defaultView; + return chromeWin; + }, + + /* + * _getNativeWindow + * + * Returns the NativeWindow to this prompter, or null if there isn't + * a NativeWindow available. + */ + _getNativeWindow : function () { + let nativeWindow = null; + try { + let notifyWin = this._window.top; + let chromeWin = this._getChromeWindow(notifyWin).wrappedJSObject; + if (chromeWin.NativeWindow) { + nativeWindow = chromeWin.NativeWindow; + } else { + this.log("NativeWindow not available on window"); + } + + } catch (e) { + // If any errors happen, just assume no native window helper. + this.log("No NativeWindow available: " + e) + } + return nativeWindow; + }, + + + /* + * _getLocalizedString + * + * Can be called as: + * _getLocalizedString("key1"); + * _getLocalizedString("key2", ["arg1"]); + * _getLocalizedString("key3", ["arg1", "arg2"]); + * (etc) + * + * Returns the localized string for the specified key, + * formatted if required. + * + */ + _getLocalizedString : function (key, formatArgs) { + if (formatArgs) + return this._strBundle.formatStringFromName( + key, formatArgs, formatArgs.length); + else + return this._strBundle.GetStringFromName(key); + }, + + + /* + * _sanitizeUsername + * + * Sanitizes the specified username, by stripping quotes and truncating if + * it's too long. This helps prevent an evil site from messing with the + * "save password?" prompt too much. + */ + _sanitizeUsername : function (username) { + if (username.length > 30) { + username = username.substring(0, 30); + username += this._ellipsis; + } + return username.replace(/['"]/g, ""); + }, + + + /* + * _getFormattedHostname + * + * The aURI parameter may either be a string uri, or an nsIURI instance. + * + * Returns the hostname to use in a nsILoginInfo object (for example, + * "http://example.com"). + */ + _getFormattedHostname : function (aURI) { + var uri; + if (aURI instanceof Ci.nsIURI) { + uri = aURI; + } else { + uri = Services.io.newURI(aURI, null, null); + } + var scheme = uri.scheme; + + var hostname = scheme + "://" + uri.host; + + // If the URI explicitly specified a port, only include it when + // it's not the default. (We never want "http://foo.com:80") + port = uri.port; + if (port != -1) { + var handler = Services.io.getProtocolHandler(scheme); + if (port != handler.defaultPort) + hostname += ":" + port; + } + + return hostname; + }, + + + /* + * _getShortDisplayHost + * + * Converts a login's hostname field (a URL) to a short string for + * prompting purposes. Eg, "http://foo.com" --> "foo.com", or + * "ftp://www.site.co.uk" --> "site.co.uk". + */ + _getShortDisplayHost: function (aURIString) { + var displayHost; + + var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"]. + getService(Ci.nsIEffectiveTLDService); + var idnService = Cc["@mozilla.org/network/idn-service;1"]. + getService(Ci.nsIIDNService); + try { + var uri = Services.io.newURI(aURIString, null, null); + var baseDomain = eTLDService.getBaseDomain(uri); + displayHost = idnService.convertToDisplayIDN(baseDomain, {}); + } catch (e) { + this.log("_getShortDisplayHost couldn't process " + aURIString); + } + + if (!displayHost) + displayHost = aURIString; + + return displayHost; + }, + +}; // end of LoginManagerPrompter implementation + + +var component = [LoginManagerPrompter]; +var NSGetFactory = XPCOMUtils.generateNSGetFactory(component); + diff --git a/mobile/android/components/Makefile.in b/mobile/android/components/Makefile.in new file mode 100644 index 00000000000..d444bb398fe --- /dev/null +++ b/mobile/android/components/Makefile.in @@ -0,0 +1,86 @@ +# ***** 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 . +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Finkle +# Nino D'Aversa +# +# 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 + +MODULE = MobileComponents +XPIDL_MODULE = MobileComponents + +# disabled (bug 696203) +#XPIDLSRCS = \ +# SessionStore.idl \ +# $(NULL) + +EXTRA_PP_COMPONENTS = \ + MobileComponents.manifest \ + AboutRedirector.js \ + BrowserCLH.js \ + DirectoryProvider.js\ + HelperAppDialog.js \ + Sidebar.js \ + $(NULL SessionStore.js is disabled - bug 696203) \ + $(NULL) + +EXTRA_COMPONENTS = \ + AlertsService.js \ + ContentPermissionPrompt.js \ + XPIDialogService.js \ + DownloadManagerUI.js \ + PromptService.js \ + ContentDispatchChooser.js \ + AddonUpdateService.js \ + FormAutoComplete.js \ + LoginManagerPrompter.js \ + BlocklistPrompt.js \ + CapturePicker.js \ + $(NULL) + +ifdef MOZ_SAFE_BROWSING +EXTRA_COMPONENTS += SafeBrowsing.js +endif + +ifdef MOZ_UPDATER +EXTRA_COMPONENTS += UpdatePrompt.js +endif + +include $(topsrcdir)/config/rules.mk diff --git a/mobile/android/components/MobileComponents.manifest b/mobile/android/components/MobileComponents.manifest new file mode 100644 index 00000000000..158c1eeca8c --- /dev/null +++ b/mobile/android/components/MobileComponents.manifest @@ -0,0 +1,115 @@ +# AboutRedirector.js +component {433d2d75-5923-49b0-854d-f37267b03dc7} AboutRedirector.js +contract @mozilla.org/network/protocol/about;1?what=empty {433d2d75-5923-49b0-854d-f37267b03dc7} +component {842a6d11-b369-4610-ba66-c3b5217e82be} AboutRedirector.js +contract @mozilla.org/network/protocol/about;1?what=fennec {842a6d11-b369-4610-ba66-c3b5217e82be} +component {dd40c467-d206-4f22-9215-8fcc74c74e38} AboutRedirector.js +contract @mozilla.org/network/protocol/about;1?what=firefox {dd40c467-d206-4f22-9215-8fcc74c74e38} +component {3b988fbf-ec97-4e1c-a5e4-573d999edc9c} AboutRedirector.js +contract @mozilla.org/network/protocol/about;1?what=rights {3b988fbf-ec97-4e1c-a5e4-573d999edc9c} +component {972efe64-8ac0-4e91-bdb0-22835d987815} AboutRedirector.js +contract @mozilla.org/network/protocol/about;1?what=certerror {972efe64-8ac0-4e91-bdb0-22835d987815} +component {b071364f-ab68-4669-a9db-33fca168271a} AboutRedirector.js +contract @mozilla.org/network/protocol/about;1?what=home {b071364f-ab68-4669-a9db-33fca168271a} +component {7490b75b-0ed4-4b2f-b80c-75e7f9c75682} AboutRedirector.js +contract @mozilla.org/network/protocol/about;1?what=dougt {7490b75b-0ed4-4b2f-b80c-75e7f9c75682} +#ifdef MOZ_SAFE_BROWSING +component {88fd40b6-c5c2-4120-9238-f2cb9ff98928} AboutRedirector.js +contract @mozilla.org/network/protocol/about;1?what=blocked {88fd40b6-c5c2-4120-9238-f2cb9ff98928} +#endif + +# DirectoryProvider.js +component {ef0f7a87-c1ee-45a8-8d67-26f586e46a4b} DirectoryProvider.js +contract @mozilla.org/browser/directory-provider;1 {ef0f7a87-c1ee-45a8-8d67-26f586e46a4b} +category xpcom-directory-providers browser-directory-provider @mozilla.org/browser/directory-provider;1 + +# Sidebar.js +component {22117140-9c6e-11d3-aaf1-00805f8a4905} Sidebar.js +contract @mozilla.org/sidebar;1 {22117140-9c6e-11d3-aaf1-00805f8a4905} +category JavaScript-global-property sidebar @mozilla.org/sidebar;1 +category JavaScript-global-property external @mozilla.org/sidebar;1 +category wakeup-request Sidebar @mozilla.org/sidebar;1,nsISidebarExternal,getService,Sidebar:AddSearchProvider + +# SessionStore.js - temporarily disabled (bug 696203) +# component {8c1f07d6-cba3-4226-a315-8bd43d67d032} SessionStore.js +# contract @mozilla.org/browser/sessionstore;1 {8c1f07d6-cba3-4226-a315-8bd43d67d032} +# category app-startup SessionStore service,@mozilla.org/browser/sessionstore;1 + +# stylesheets +category agent-style-sheets browser-content-stylesheet chrome://browser/skin/content.css +category agent-style-sheets browser-cursor-stylesheet chrome://browser/content/cursor.css + +# ContentPermissionPrompt.js +component {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5} ContentPermissionPrompt.js +contract @mozilla.org/content-permission/prompt;1 {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5} + +# AlertsService.js +component {fe33c107-82a4-41d6-8c64-5353267e04c9} AlertsService.js +#ifndef ANDROID +contract @mozilla.org/system-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9} +#endif + +# ToasterAlertsService : alias to AlertsService +contract @mozilla.org/toaster-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9} + +# XPIDialogService.js +component {c1242012-27d8-477e-a0f1-0b098ffc329b} XPIDialogService.js +contract @mozilla.org/addons/web-install-prompt;1 {c1242012-27d8-477e-a0f1-0b098ffc329b} + +# DownloadManagerUI.js +component {93db15b1-b408-453e-9a2b-6619e168324a} DownloadManagerUI.js +contract @mozilla.org/download-manager-ui;1 {93db15b1-b408-453e-9a2b-6619e168324a} + +# HelperAppDialog.js +component {e9d277a0-268a-4ec2-bb8c-10fdf3e44611} HelperAppDialog.js +contract @mozilla.org/helperapplauncherdialog;1 {e9d277a0-268a-4ec2-bb8c-10fdf3e44611} + +# PromptService.js +component {9a61149b-2276-4a0a-b79c-be994ad106cf} PromptService.js +contract @mozilla.org/prompter;1 {9a61149b-2276-4a0a-b79c-be994ad106cf} +contract @mozilla.org/embedcomp/prompt-service;1 {9a61149b-2276-4a0a-b79c-be994ad106cf} +category wakeup-request PromptService @mozilla.org/embedcomp/prompt-service;1,nsIPromptService,getService,Prompt:Call + +# BrowserCLH.js +component {be623d20-d305-11de-8a39-0800200c9a66} BrowserCLH.js application={aa3c5121-dab2-40e2-81ca-7ea25febc110} +contract @mozilla.org/browser/browser-clh;1 {be623d20-d305-11de-8a39-0800200c9a66} +category command-line-handler x-browser @mozilla.org/browser/browser-clh;1 + +# ContentDispatchChooser.js +component {5a072a22-1e66-4100-afc1-07aed8b62fc5} ContentDispatchChooser.js +contract @mozilla.org/content-dispatch-chooser;1 {5a072a22-1e66-4100-afc1-07aed8b62fc5} + +# AddonUpdateService.js +component {93c8824c-9b87-45ae-bc90-5b82a1e4d877} AddonUpdateService.js +contract @mozilla.org/browser/addon-update-service;1 {93c8824c-9b87-45ae-bc90-5b82a1e4d877} +category update-timer AddonUpdateService @mozilla.org/browser/addon-update-service;1,getService,auto-addon-background-update-timer,extensions.autoupdate.interval,86400 + +# FormAutoComplete.js +component {cccd414c-3ec2-4cc5-9dc4-36c87cc3c4fe} FormAutoComplete.js +contract @mozilla.org/satchel/form-autocomplete;1 {cccd414c-3ec2-4cc5-9dc4-36c87cc3c4fe} + +# LoginManagerPrompter.js +component {97d12931-abe2-11df-94e2-0800200c9a66} LoginManagerPrompter.js +contract @mozilla.org/login-manager/prompter;1 {97d12931-abe2-11df-94e2-0800200c9a66} + +# BlocklistPrompt.js +component {4e6ea350-b09a-11df-94e2-0800200c9a66} BlocklistPrompt.js +contract @mozilla.org/addons/blocklist-prompt;1 {4e6ea350-b09a-11df-94e2-0800200c9a66} + +#ifdef MOZ_SAFE_BROWSING +# SafeBrowsing.js +component {aadaed90-6c03-42d0-924a-fc61198ff283} SafeBrowsing.js +contract @mozilla.org/safebrowsing/application;1 {aadaed90-6c03-42d0-924a-fc61198ff283} +category app-startup SafeBrowsing service,@mozilla.org/safebrowsing/application;1 +#endif + +#ifdef MOZ_UPDATER +# UpdatePrompt.js +component {88b3eb21-d072-4e3b-886d-f89d8c49fe59} UpdatePrompt.js +contract @mozilla.org/updates/update-prompt;1 {88b3eb21-d072-4e3b-886d-f89d8c49fe59} +#endif + +# CapturePicker.js +component {cb5a47f0-b58c-4fc3-b61a-358ee95f8238} CapturePicker.js +contract @mozilla.org/capturepicker;1 {cb5a47f0-b58c-4fc3-b61a-358ee95f8238} + diff --git a/mobile/android/components/PromptService.js b/mobile/android/components/PromptService.js new file mode 100644 index 00000000000..6f261f27284 --- /dev/null +++ b/mobile/android/components/PromptService.js @@ -0,0 +1,798 @@ +/* ***** 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. + * + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Fabrice Desré , Original author + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +// Whitelist of methods we remote - to check against malicious data. +// For example, it would be dangerous to allow content to show auth prompts. +const REMOTABLE_METHODS = { + alert: { outParams: [] }, + alertCheck: { outParams: [4] }, + confirm: { outParams: [] }, + prompt: { outParams: [3, 5] }, + confirmEx: { outParams: [8] }, + confirmCheck: { outParams: [4] }, + select: { outParams: [5] } +}; + +var gPromptService = null; + +function PromptService() { + gPromptService = this; +} + +PromptService.prototype = { + classID: Components.ID("{9a61149b-2276-4a0a-b79c-be994ad106cf}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptFactory, Ci.nsIPromptService, Ci.nsIPromptService2]), + + /* ---------- nsIPromptFactory ---------- */ + // XXX Copied from nsPrompter.js. + getPrompt: function getPrompt(domWin, iid) { + let doc = this.getDocument(); + if (!doc) { + let fallback = this._getFallbackService(); + return fallback.getPrompt(domWin, iid); + } + + let p = new Prompt(domWin, doc); + p.QueryInterface(iid); + return p; + }, + + /* ---------- private memebers ---------- */ + + _getFallbackService: function _getFallbackService() { + return Components.classesByID["{7ad1b327-6dfa-46ec-9234-f2a620ea7e00}"] + .getService(Ci.nsIPromptService); + }, + + getDocument: function getDocument() { + let win = Services.wm.getMostRecentWindow("navigator:browser"); + return win ? win.document : null; + }, + + // nsIPromptService and nsIPromptService2 methods proxy to our Prompt class + // if we can show in-document popups, or to the fallback service otherwise. + callProxy: function(aMethod, aArguments) { + let prompt; + let doc = this.getDocument(); + if (!doc) { + let fallback = this._getFallbackService(); + return fallback[aMethod].apply(fallback, aArguments); + } + let domWin = aArguments[0]; + prompt = new Prompt(domWin, doc); + return prompt[aMethod].apply(prompt, Array.prototype.slice.call(aArguments, 1)); + }, + + /* ---------- nsIPromptService ---------- */ + + alert: function() { + return this.callProxy("alert", arguments); + }, + alertCheck: function() { + return this.callProxy("alertCheck", arguments); + }, + confirm: function() { + return this.callProxy("confirm", arguments); + }, + confirmCheck: function() { + return this.callProxy("confirmCheck", arguments); + }, + confirmEx: function() { + return this.callProxy("confirmEx", arguments); + }, + prompt: function() { + return this.callProxy("prompt", arguments); + }, + promptUsernameAndPassword: function() { + return this.callProxy("promptUsernameAndPassword", arguments); + }, + promptPassword: function() { + return this.callProxy("promptPassword", arguments); + }, + select: function() { + return this.callProxy("select", arguments); + }, + + /* ---------- nsIPromptService2 ---------- */ + promptAuth: function() { + return this.callProxy("promptAuth", arguments); + }, + asyncPromptAuth: function() { + return this.callProxy("asyncPromptAuth", arguments); + } +}; + +function Prompt(aDomWin, aDocument) { + this._domWin = aDomWin; + this._doc = aDocument; +} + +Prompt.prototype = { + _domWin: null, + _doc: null, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt, Ci.nsIAuthPrompt, Ci.nsIAuthPrompt2]), + + /* ---------- internal methods ---------- */ + commonPrompt: function commonPrompt(aTitle, aText, aButtons, aCheckMsg, aCheckState, aInputs) { + if (aCheckMsg) + aInputs.push({ type: "checkbox", label: aCheckMsg, checked: aCheckState.value }); + + let msg = { type: "Prompt:Show" }; + if (aTitle) msg.title = aTitle; + if (aText) msg.text = aText; + msg.buttons = aButtons || [ + { label: PromptUtils.getLocaleString("OK") }, + { label: PromptUtils.getLocaleString("Cancel") } + ]; + msg.inputs = aInputs; + return PromptUtils.sendMessageToJava(msg); + }, + + // + // Copied from chrome://global/content/commonDialog.js + // + setLabelForNode: function setLabelForNode(aNode, aLabel) { + // This is for labels which may contain embedded access keys. + // If we end in (&X) where X represents the access key, optionally preceded + // by spaces and/or followed by the ':' character, store the access key and + // remove the access key placeholder + leading spaces from the label. + // Otherwise a character preceded by one but not two &s is the access key. + // Store it and remove the &. + + // Note that if you change the following code, see the comment of + // nsTextBoxFrame::UpdateAccessTitle. + + if (!aLabel) + return; + + var accessKey = null; + if (/ *\(\&([^&])\)(:)?$/.test(aLabel)) { + aLabel = RegExp.leftContext + RegExp.$2; + accessKey = RegExp.$1; + } else if (/^(.*[^&])?\&(([^&]).*$)/.test(aLabel)) { + aLabel = RegExp.$1 + RegExp.$2; + accessKey = RegExp.$3; + } + + // && is the magic sequence to embed an & in your label. + aLabel = aLabel.replace(/\&\&/g, "&"); + if (aNode instanceof Ci.nsIDOMXULLabelElement) { + aNode.setAttribute("value", aLabel); + } else if (aNode instanceof Ci.nsIDOMXULDescriptionElement) { + let text = aNode.ownerDocument.createTextNode(aLabel); + aNode.appendChild(text); + } else { // Set text for other xul elements + aNode.setAttribute("label", aLabel); + } + + // XXXjag bug 325251 + // Need to set this after aNode.setAttribute("value", aLabel); + if (accessKey) + aNode.setAttribute("accesskey", accessKey); + }, + + /* + * ---------- interface disambiguation ---------- + * + * XXX Copied from nsPrompter.js. + * + * nsIPrompt and nsIAuthPrompt share 3 method names with slightly + * different arguments. All but prompt() have the same number of + * arguments, so look at the arg types to figure out how we're being + * called. :-( + */ + prompt: function prompt() { + if (gPromptService.inContentProcess) + return gPromptService.callProxy("prompt", [null].concat(Array.prototype.slice.call(arguments))); + + // also, the nsIPrompt flavor has 5 args instead of 6. + if (typeof arguments[2] == "object") + return this.nsIPrompt_prompt.apply(this, arguments); + else + return this.nsIAuthPrompt_prompt.apply(this, arguments); + }, + + promptUsernameAndPassword: function promptUsernameAndPassword() { + // Both have 6 args, so use types. + if (typeof arguments[2] == "object") + return this.nsIPrompt_promptUsernameAndPassword.apply(this, arguments); + else + return this.nsIAuthPrompt_promptUsernameAndPassword.apply(this, arguments); + }, + + promptPassword: function promptPassword() { + // Both have 5 args, so use types. + if (typeof arguments[2] == "object") + return this.nsIPrompt_promptPassword.apply(this, arguments); + else + return this.nsIAuthPrompt_promptPassword.apply(this, arguments); + }, + + /* ---------- nsIPrompt ---------- */ + + alert: function alert(aTitle, aText) { + this.commonPrompt(aTitle, aText, [{ label: PromptUtils.getLocaleString("OK") }], "", {value: false}, []); + }, + + alertCheck: function alertCheck(aTitle, aText, aCheckMsg, aCheckState) { + let data = this.commonPrompt(aTitle, aText, [{ label: PromptUtils.getLocaleString("OK") }], aCheckMsg, aCheckState, []); + if (aCheckMsg) + aCheckState.value = data.checkbox == "true"; + }, + + confirm: function confirm(aTitle, aText) { + let data = this.commonPrompt(aTitle, aText, null, "", {value: false}, []); + return (data.button == 0); + }, + + confirmCheck: function confirmCheck(aTitle, aText, aCheckMsg, aCheckState) { + let data = this.commonPrompt(aTitle, aText, null, aCheckMsg, aCheckState, []); + if (aCheckMsg) + aCheckState.value = data.checkbox == "true"; + return (data.button == 0); + }, + + confirmEx: function confirmEx(aTitle, aText, aButtonFlags, aButton0, + aButton1, aButton2, aCheckMsg, aCheckState) { + let buttons = []; + let titles = [aButton0, aButton1, aButton2]; + for (let i = 0; i < 3; i++) { + let bTitle = null; + switch (aButtonFlags & 0xff) { + case Ci.nsIPromptService.BUTTON_TITLE_OK : + bTitle = PromptUtils.getLocaleString("OK"); + break; + case Ci.nsIPromptService.BUTTON_TITLE_CANCEL : + bTitle = PromptUtils.getLocaleString("Cancel"); + break; + case Ci.nsIPromptService.BUTTON_TITLE_YES : + bTitle = PromptUtils.getLocaleString("Yes"); + break; + case Ci.nsIPromptService.BUTTON_TITLE_NO : + bTitle = PromptUtils.getLocaleString("No"); + break; + case Ci.nsIPromptService.BUTTON_TITLE_SAVE : + bTitle = PromptUtils.getLocaleString("Save"); + break; + case Ci.nsIPromptService.BUTTON_TITLE_DONT_SAVE : + bTitle = PromptUtils.getLocaleString("DontSave"); + break; + case Ci.nsIPromptService.BUTTON_TITLE_REVERT : + bTitle = PromptUtils.getLocaleString("Revert"); + break; + case Ci.nsIPromptService.BUTTON_TITLE_IS_STRING : + bTitle = titles[i]; + break; + } + + if (bTitle) + buttons.push({label:bTitle}); + + aButtonFlags >>= 8; + } + + let data = this.commonPrompt(aTitle, aText, buttons, aCheckMsg, aCheckState, []); + aCheckState.value = data.checkbox == "true"; + return data.button; + }, + + nsIPrompt_prompt: function nsIPrompt_prompt(aTitle, aText, aValue, aCheckMsg, aCheckState) { + let inputs = [{ type: "textbox", value: aValue.value }]; + let data = this.commonPrompt(aTitle, aText, null, aCheckMsg, aCheckState, inputs); + + if (aCheckMsg) + aCheckState.value = data.checkbox == "true"; + if (data.textbox) + aValue.value = data.textbox; + return (data.button == 0); + }, + + nsIPrompt_promptPassword: function nsIPrompt_promptPassword( + aTitle, aText, aPassword, aCheckMsg, aCheckState) { + let inputs = [{ type: "password", hint: "Password", value: aPassword.value }]; + let data = this.commonPrompt(aTitle, aText, null, aCheckMsg, aCheckState, inputs); + + if (aCheckMsg) + aCheckState.value = data.checkbox == "true"; + if (data.password) + aPassword.value = data.password; + return (data.button == 0); + }, + + nsIPrompt_promptUsernameAndPassword: function nsIPrompt_promptUsernameAndPassword( + aTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState) { + let inputs = [{ type: "textbox", hint: PromptUtils.getLocaleString("username", "passwdmgr"), value: aUsername.value }, + { type: "password", hint: PromptUtils.getLocaleString("password", "passwdmgr"), value: aPassword.value }]; + let data = this.commonPrompt(aTitle, aText, null, aCheckMsg, aCheckState, inputs); + if (aCheckMsg) + aCheckState.value = data.checkbox == "true"; + if (data.textbox) + aUsername.value = data.textbox; + if (data.password) + aPassword.value = data.password; + return (data.button == 0); + }, + + select: function select(aTitle, aText, aCount, aSelectList, aOutSelection) { + let data = this.commonPrompt(aTitle, aText, [ + { label: PromptUtils.getLocaleString("OK") } + ], "", {value: false}, [ + { type: "menulist", values: aSelectList }, + ]); + if (data.menulist) + aOutSelection.value = data.menulist; + return (data.button == 0); + }, + + /* ---------- nsIAuthPrompt ---------- */ + + nsIAuthPrompt_prompt : function (title, text, passwordRealm, savePassword, defaultText, result) { + // TODO: Port functions from nsLoginManagerPrompter.js to here + if (defaultText) + result.value = defaultText; + return this.nsIPrompt_prompt(title, text, result, null, {}); + }, + + nsIAuthPrompt_promptUsernameAndPassword : function (aTitle, aText, aPasswordRealm, aSavePassword, aUser, aPass) { + return nsIAuthPrompt_loginPrompt(aTitle, aText, aPasswordRealm, aSavePassword, aUser, aPass); + }, + + nsIAuthPrompt_promptPassword : function (aTitle, aText, aPasswordRealm, aSavePassword, aPass) { + return nsIAuthPrompt_loginPrompt(aTitle, aText, aPasswordRealm, aSavePassword, null, aPass); + }, + + nsIAuthPrompt_loginPrompt: function(aTitle, aPasswordRealm, aSavePassword, aUser, aPass) { + let checkMsg = null; + let check = { value: false }; + let [hostname, realm, aUser] = PromptUtils.getHostnameAndRealm(aPasswordRealm); + + let canSave = PromptUtils.canSaveLogin(hostname, aSavePassword); + if (canSave) { + // Look for existing logins. + let foundLogins = PromptUtils.pwmgr.findLogins({}, hostname, null, realm); + [checkMsg, check] = PromptUtils.getUsernameAndPassword(foundLogins, aUser, aPass); + } + + let ok = false; + if (aUser) + ok = this.nsIPrompt_promptUsernameAndPassword(aTitle, aText, aUser, aPass, checkMsg, check); + else + ok = this.nsIPrompt_promptPassword(aTitle, aText, aPass, checkMsg, check); + + if (ok && canSave && check.value) + PromptUtils.savePassword(hostname, realm, aUser, aPass); + + return ok; }, + + /* ---------- nsIAuthPrompt2 ---------- */ + + promptAuth: function promptAuth(aChannel, aLevel, aAuthInfo) { + let checkMsg = null; + let check = { value: false }; + let message = PromptUtils.makeDialogText(aChannel, aAuthInfo); + let [username, password] = PromptUtils.getAuthInfo(aAuthInfo); + let [hostname, httpRealm] = PromptUtils.getAuthTarget(aChannel, aAuthInfo); + let foundLogins = PromptUtils.pwmgr.findLogins({}, hostname, null, httpRealm); + + let canSave = PromptUtils.canSaveLogin(hostname, null); + if (canSave) + [checkMsg, check] = PromptUtils.getUsernameAndPassword(foundLogins, username, password); + + if (username.value && password.value) { + PromptUtils.setAuthInfo(aAuthInfo, username.value, password.value); + } + + let canAutologin = false; + if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY && + !(aAuthInfo.flags & Ci.nsIAuthInformation.PREVIOUS_FAILED) && + Services.prefs.getBoolPref("signon.autologin.proxy")) + canAutologin = true; + + let ok = canAutologin; + if (!ok && aAuthInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD) + ok = this.nsIPrompt_promptPassword(null, message, password, checkMsg, check); + else if (!ok) + ok = this.nsIPrompt_promptUsernameAndPassword(null, message, username, password, checkMsg, check); + + PromptUtils.setAuthInfo(aAuthInfo, username.value, password.value); + + if (ok && canSave && check.value) + PromptUtils.savePassword(foundLogins, username, password, hostname, httpRealm); + + return ok; + }, + + _asyncPrompts: {}, + _asyncPromptInProgress: false, + + _doAsyncPrompt : function() { + if (this._asyncPromptInProgress) + return; + + // Find the first prompt key we have in the queue + let hashKey = null; + for (hashKey in this._asyncPrompts) + break; + + if (!hashKey) + return; + + // If login manger has logins for this host, defer prompting if we're + // already waiting on a master password entry. + let prompt = this._asyncPrompts[hashKey]; + let prompter = prompt.prompter; + let [hostname, httpRealm] = PromptUtils.getAuthTarget(prompt.channel, prompt.authInfo); + let foundLogins = PromptUtils.pwmgr.findLogins({}, hostname, null, httpRealm); + if (foundLogins.length > 0 && PromptUtils.pwmgr.uiBusy) + return; + + this._asyncPromptInProgress = true; + prompt.inProgress = true; + + let self = this; + + let runnable = { + run: function() { + let ok = false; + try { + ok = prompter.promptAuth(prompt.channel, prompt.level, prompt.authInfo); + } catch (e) { + Cu.reportError("_doAsyncPrompt:run: " + e + "\n"); + } + + delete self._asyncPrompts[hashKey]; + prompt.inProgress = false; + self._asyncPromptInProgress = false; + + for each (let consumer in prompt.consumers) { + if (!consumer.callback) + // Not having a callback means that consumer didn't provide it + // or canceled the notification + continue; + + try { + if (ok) + consumer.callback.onAuthAvailable(consumer.context, prompt.authInfo); + else + consumer.callback.onAuthCancelled(consumer.context, true); + } catch (e) { /* Throw away exceptions caused by callback */ } + } + self._doAsyncPrompt(); + } + } + + Services.tm.mainThread.dispatch(runnable, Ci.nsIThread.DISPATCH_NORMAL); + }, + + asyncPromptAuth: function asyncPromptAuth(aChannel, aCallback, aContext, aLevel, aAuthInfo) { + let cancelable = null; + try { + // If the user submits a login but it fails, we need to remove the + // notification bar that was displayed. Conveniently, the user will + // be prompted for authentication again, which brings us here. + //this._removeLoginNotifications(); + + cancelable = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]), + callback: aCallback, + context: aContext, + cancel: function() { + this.callback.onAuthCancelled(this.context, false); + this.callback = null; + this.context = null; + } + }; + let [hostname, httpRealm] = PromptUtils.getAuthTarget(aChannel, aAuthInfo); + let hashKey = aLevel + "|" + hostname + "|" + httpRealm; + let asyncPrompt = this._asyncPrompts[hashKey]; + if (asyncPrompt) { + asyncPrompt.consumers.push(cancelable); + return cancelable; + } + + asyncPrompt = { + consumers: [cancelable], + channel: aChannel, + authInfo: aAuthInfo, + level: aLevel, + inProgress : false, + prompter: this + } + + this._asyncPrompts[hashKey] = asyncPrompt; + this._doAsyncPrompt(); + } catch (e) { + Cu.reportError("PromptService: " + e + "\n"); + throw e; + } + return cancelable; + } +}; + +let PromptUtils = { + getLocaleString: function pu_getLocaleString(aKey, aService) { + if (aService == "passwdmgr") + return this.passwdBundle.GetStringFromName(aKey).replace(/&/g, ""); + + return this.bundle.GetStringFromName(aKey).replace(/&/g, ""); + }, + + get pwmgr() { + delete this.pwmgr; + return this.pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); + }, + + getHostnameAndRealm: function pu_getHostnameAndRealm(aRealmString) { + let httpRealm = /^.+ \(.+\)$/; + if (httpRealm.test(aRealmString)) + return [null, null, null]; + + let uri = Services.io.newURI(aRealmString, null, null); + let pathname = ""; + + if (uri.path != "/") + pathname = uri.path; + + let formattedHostname = this._getFormattedHostname(uri); + return [formattedHostname, formattedHostname + pathname, uri.username]; + }, + + canSaveLogin: function pu_canSaveLogin(aHostname, aSavePassword) { + let canSave = !this._inPrivateBrowsing && this.pwmgr.getLoginSavingEnabled(aHostname) + if (aSavePassword) + canSave = canSave && (aSavePassword == Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY) + return canSave; + }, + + getUsernameAndPassword: function pu_getUsernameAndPassword(aFoundLogins, aUser, aPass) { + let checkLabel = null; + let check = { value: false }; + let selectedLogin; + + checkLabel = this.getLocaleString("rememberPassword", "passwdmgr"); + + // XXX Like the original code, we can't deal with multiple + // account selection. (bug 227632) + if (aFoundLogins.length > 0) { + selectedLogin = aFoundLogins[0]; + + // If the caller provided a username, try to use it. If they + // provided only a password, this will try to find a password-only + // login (or return null if none exists). + if (aUser.value) + selectedLogin = this.findLogin(aFoundLogins, "username", aUser.value); + + if (selectedLogin) { + check.value = true; + aUser.value = selectedLogin.username; + // If the caller provided a password, prefer it. + if (!aPass.value) + aPass.value = selectedLogin.password; + } + } + + return [checkLabel, check]; + }, + + findLogin: function pu_findLogin(aLogins, aName, aValue) { + for (let i = 0; i < aLogins.length; i++) + if (aLogins[i][aName] == aValue) + return aLogins[i]; + return null; + }, + + savePassword: function pu_savePassword(aLogins, aUser, aPass, aHostname, aRealm) { + let selectedLogin = this.findLogin(aLogins, "username", aUser.value); + + // If we didn't find an existing login, or if the username + // changed, save as a new login. + if (!selectedLogin) { + // add as new + var newLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo); + newLogin.init(aHostname, null, aRealm, aUser.value, aPass.value, "", ""); + this.pwmgr.addLogin(newLogin); + } else if (aPass.value != selectedLogin.password) { + // update password + this.updateLogin(selectedLogin, aPass.value); + } else { + this.updateLogin(selectedLogin); + } + }, + + updateLogin: function pu_updateLogin(aLogin, aPassword) { + let now = Date.now(); + let propBag = Cc["@mozilla.org/hash-property-bag;1"].createInstance(Ci.nsIWritablePropertyBag); + if (aPassword) { + propBag.setProperty("password", aPassword); + // Explicitly set the password change time here (even though it would + // be changed automatically), to ensure that it's exactly the same + // value as timeLastUsed. + propBag.setProperty("timePasswordChanged", now); + } + propBag.setProperty("timeLastUsed", now); + propBag.setProperty("timesUsedIncrement", 1); + + this.pwmgr.modifyLogin(aLogin, propBag); + }, + + // JS port of http://mxr.mozilla.org/mozilla-central/source/embedding/components/windowwatcher/src/nsPrompt.cpp#388 + makeDialogText: function pu_makeDialogText(aChannel, aAuthInfo) { + let isProxy = (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY); + let isPassOnly = (aAuthInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD); + + let username = aAuthInfo.username; + let [displayHost, realm] = this.getAuthTarget(aChannel, aAuthInfo); + + // Suppress "the site says: $realm" when we synthesized a missing realm. + if (!aAuthInfo.realm && !isProxy) + realm = ""; + + // Trim obnoxiously long realms. + if (realm.length > 150) { + realm = realm.substring(0, 150); + // Append "..." (or localized equivalent). + realm += this.ellipsis; + } + + let text; + if (isProxy) + text = this.bundle.formatStringFromName("EnterLoginForProxy", [realm, displayHost], 2); + else if (isPassOnly) + text = this.bundle.formatStringFromName("EnterPasswordFor", [username, displayHost], 2); + else if (!realm) + text = this.bundle.formatStringFromName("EnterUserPasswordFor", [displayHost], 1); + else + text = this.bundle.formatStringFromName("EnterLoginForRealm", [realm, displayHost], 2); + + return text; + }, + + // JS port of http://mxr.mozilla.org/mozilla-central/source/embedding/components/windowwatcher/public/nsPromptUtils.h#89 + getAuthHostPort: function pu_getAuthHostPort(aChannel, aAuthInfo) { + let uri = aChannel.URI; + let res = { host: null, port: -1 }; + if (aAuthInfo.flags & aAuthInfo.AUTH_PROXY) { + let proxy = aChannel.QueryInterface(Ci.nsIProxiedChannel); + res.host = proxy.proxyInfo.host; + res.port = proxy.proxyInfo.port; + } else { + res.host = uri.host; + res.port = uri.port; + } + return res; + }, + + getAuthTarget : function pu_getAuthTarget(aChannel, aAuthInfo) { + let hostname, realm; + // If our proxy is demanding authentication, don't use the + // channel's actual destination. + if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) { + if (!(aChannel instanceof Ci.nsIProxiedChannel)) + throw "proxy auth needs nsIProxiedChannel"; + + let info = aChannel.proxyInfo; + if (!info) + throw "proxy auth needs nsIProxyInfo"; + + // Proxies don't have a scheme, but we'll use "moz-proxy://" + // so that it's more obvious what the login is for. + let idnService = Cc["@mozilla.org/network/idn-service;1"].getService(Ci.nsIIDNService); + hostname = "moz-proxy://" + idnService.convertUTF8toACE(info.host) + ":" + info.port; + realm = aAuthInfo.realm; + if (!realm) + realm = hostname; + + return [hostname, realm]; + } + hostname = this.getFormattedHostname(aChannel.URI); + + // If a HTTP WWW-Authenticate header specified a realm, that value + // will be available here. If it wasn't set or wasn't HTTP, we'll use + // the formatted hostname instead. + realm = aAuthInfo.realm; + if (!realm) + realm = hostname; + + return [hostname, realm]; + }, + + getAuthInfo : function pu_getAuthInfo(aAuthInfo) { + let flags = aAuthInfo.flags; + let username = {value: ""}; + let password = {value: ""}; + + if (flags & Ci.nsIAuthInformation.NEED_DOMAIN && aAuthInfo.domain) + username.value = aAuthInfo.domain + "\\" + aAuthInfo.username; + else + username.value = aAuthInfo.username; + + password.value = aAuthInfo.password + + return [username, password]; + }, + + setAuthInfo : function (aAuthInfo, username, password) { + var flags = aAuthInfo.flags; + if (flags & Ci.nsIAuthInformation.NEED_DOMAIN) { + // Domain is separated from username by a backslash + var idx = username.indexOf("\\"); + if (idx == -1) { + aAuthInfo.username = username; + } else { + aAuthInfo.domain = username.substring(0, idx); + aAuthInfo.username = username.substring(idx+1); + } + } else { + aAuthInfo.username = username; + } + aAuthInfo.password = password; + }, + + getFormattedHostname : function pu_getFormattedHostname(uri) { + let scheme = uri.scheme; + let hostname = scheme + "://" + uri.host; + + // If the URI explicitly specified a port, only include it when + // it's not the default. (We never want "http://foo.com:80") + port = uri.port; + if (port != -1) { + let handler = Services.io.getProtocolHandler(scheme); + if (port != handler.defaultPort) + hostname += ":" + port; + } + return hostname; + }, + sendMessageToJava: function(aMsg) { + let data = Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge).handleGeckoMessage(JSON.stringify({ gecko: aMsg })); + return JSON.parse(data); + } +}; + +XPCOMUtils.defineLazyGetter(PromptUtils, "passwdBundle", function () { + return Services.strings.createBundle("chrome://passwordmgr/locale/passwordmgr.properties"); +}); + +XPCOMUtils.defineLazyGetter(PromptUtils, "bundle", function () { + return Services.strings.createBundle("chrome://global/locale/commonDialogs.properties"); +}); + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([PromptService]); diff --git a/mobile/android/components/SafeBrowsing.js b/mobile/android/components/SafeBrowsing.js new file mode 100644 index 00000000000..10dec701744 --- /dev/null +++ b/mobile/android/components/SafeBrowsing.js @@ -0,0 +1,200 @@ +/* ***** 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 Safe Browsing. + * + * 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): + * Mark Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +const kPhishWardenEnabledPref = "browser.safebrowsing.enabled"; +const kMalwareWardenEnabledPref = "browser.safebrowsing.malware.enabled"; + +// This XPCOM object doesn't have a public interface. It just works quietly in the background +function SafeBrowsing() { + this.listManager = null; + + // Once we register tables, their respective names will be listed here. + this.phishing = { + pref: kPhishWardenEnabledPref, + blackTables: [], + whiteTables: [] + }; + this.malware = { + pref: kMalwareWardenEnabledPref, + blackTables: [], + whiteTables: [] + }; + + // Get notifications when the phishing or malware warden enabled pref changes + Services.prefs.addObserver(kPhishWardenEnabledPref, this, true); + Services.prefs.addObserver(kMalwareWardenEnabledPref, this, true); +} + +SafeBrowsing.prototype = { + classID: Components.ID("{aadaed90-6c03-42d0-924a-fc61198ff283}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsISessionStore, + Ci.nsIDOMEventListener, + Ci.nsIObserver, + Ci.nsISupportsWeakReference]), + + observe: function sb_observe(aSubject, aTopic, aData) { + switch (aTopic) { + case "app-startup": + Services.obs.addObserver(this, "final-ui-startup", true); + Services.obs.addObserver(this, "xpcom-shutdown", true); + break; + case "final-ui-startup": + Services.obs.removeObserver(this, "final-ui-startup"); + this._startup(); + break; + case "xpcom-shutdown": + Services.obs.removeObserver(this, "xpcom-shutdown"); + this._shutdown(); + break; + case "nsPref:changed": + if (aData == kPhishWardenEnabledPref) + this.maybeToggleUpdateChecking(this.phishing); + else if (aData == kMalwareWardenEnabledPref) + this.maybeToggleUpdateChecking(this.malware); + break; + } + }, + + _startup: function sb_startup() { + this.listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].getService(Ci.nsIUrlListManager); + + // Add a test chunk to the database + let testData = "mozilla.org/firefox/its-an-attack.html"; + let testUpdate = + "n:1000\ni:test-malware-simple\nad:1\n" + + "a:1:32:" + testData.length + "\n" + + testData; + + testData = "mozilla.org/firefox/its-a-trap.html"; + testUpdate += + "n:1000\ni:test-phish-simple\nad:1\n" + + "a:1:32:" + testData.length + "\n" + + testData; + + let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"].getService(Ci.nsIUrlClassifierDBService); + + let listener = { + QueryInterface: function(aIID) { + if (aIID.equals(Ci.nsISupports) || aIID.equals(Ci.nsIUrlClassifierUpdateObserver)) + return this; + throw Cr.NS_ERROR_NO_INTERFACE; + }, + + updateUrlRequested: function(aURL) { }, + streamFinished: function(aStatus) { }, + updateError: function(aErrorCode) { }, + updateSuccess: function(aRequestedTimeout) { } + }; + + try { + dbService.beginUpdate(listener, "test-malware-simple,test-phish-simple", ""); + dbService.beginStream("", ""); + dbService.updateStream(testUpdate); + dbService.finishStream(); + dbService.finishUpdate(); + } catch(ex) {} + + this.registerBlackTable("goog-malware-shavar", this.malware); + this.maybeToggleUpdateChecking(this.malware); + + this.registerBlackTable("goog-phish-shavar", this.phishing); + this.maybeToggleUpdateChecking(this.phishing); + }, + + _shutdown: function sb_shutdown() { + Services.prefs.removeObserver(kPhishWardenEnabledPref, this); + Services.prefs.removeObserver(kMalwareWardenEnabledPref, this); + + this.listManager = null; + }, + + enableBlacklistTableUpdates: function sb_enableBlacklistTableUpdates(aWarden) { + for (let i = 0; i < aWarden.blackTables.length; ++i) { + this.listManager.enableUpdate(aWarden.blackTables[i]); + } + }, + + disableBlacklistTableUpdates: function sb_disableBlacklistTableUpdates(aWarden) { + for (let i = 0; i < aWarden.blackTables.length; ++i) { + this.listManager.disableUpdate(aWarden.blackTables[i]); + } + }, + + enableWhitelistTableUpdates: function sb_enableWhitelistTableUpdates(aWarden) { + for (let i = 0; i < this.whiteTables.length; ++i) { + this.listManager.enableUpdate(this.whiteTables[i]); + } + }, + + disableWhitelistTableUpdates: function sb_disableWhitelistTableUpdates(aWarden) { + for (let i = 0; i < aWarden.whiteTables.length; ++i) { + this.listManager.disableUpdate(aWarden.whiteTables[i]); + } + }, + + registerBlackTable: function sb_registerBlackTable(aTableName, aWarden) { + let result = this.listManager.registerTable(aTableName, false); + if (result) + aWarden.blackTables.push(aTableName); + return result; + }, + + registerWhiteTable: function sb_registerWhiteTable(aTableName, aWarden) { + let result = this.listManager.registerTable(aTableName, false); + if (result) + aWarden.whiteTables.push(aTableName); + return result; + }, + + maybeToggleUpdateChecking: function sb_maybeToggleUpdateChecking(aWarden) { + let enabled = Services.prefs.getBoolPref(aWarden.pref); + if (enabled) + this.enableBlacklistTableUpdates(aWarden); + else + this.disableBlacklistTableUpdates(aWarden); + } +} + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([SafeBrowsing]); diff --git a/mobile/android/components/SessionStore.idl b/mobile/android/components/SessionStore.idl new file mode 100644 index 00000000000..1fc61b2227c --- /dev/null +++ b/mobile/android/components/SessionStore.idl @@ -0,0 +1,116 @@ +/* ***** 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 the Session Store component. + * + * 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 + * + * 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 ***** */ + +#include "nsISupports.idl" + +interface nsIDOMWindow; +interface nsIDOMNode; + +/** + * nsISessionStore keeps track of the current browsing state. + * + * The nsISessionStore API operates mostly on browser windows and the browser + * tabs contained in them. + */ + +[scriptable, uuid(766a09c1-d21b-4bf8-9fe3-8b34b716251a)] +interface nsISessionStore : nsISupports +{ + /** + * Get the current browsing state. + * @returns a JSON string representing the session state. + */ + AString getBrowserState(); + + /** + * Get the number of restore-able tabs for a browser window + */ + unsigned long getClosedTabCount(in nsIDOMWindow aWindow); + + /** + * Get closed tab data + * + * @param aWindow is the browser window for which to get closed tab data + * @returns a JSON string representing the list of closed tabs. + */ + AString getClosedTabData(in nsIDOMWindow aWindow); + + /** + * @param aWindow is the browser window to reopen a closed tab in. + * @param aIndex is the index of the tab to be restored (FIFO ordered). + * @returns a reference to the reopened tab. + */ + nsIDOMNode undoCloseTab(in nsIDOMWindow aWindow, in unsigned long aIndex); + + /** + * @param aWindow is the browser window associated with the closed tab. + * @param aIndex is the index of the closed tab to be removed (FIFO ordered). + */ + nsIDOMNode forgetClosedTab(in nsIDOMWindow aWindow, in unsigned long aIndex); + + /** + * @param aTab is the browser tab to get the value for. + * @param aKey is the value's name. + * + * @returns A string value or an empty string if none is set. + */ + AString getTabValue(in nsIDOMNode aTab, in AString aKey); + + /** + * @param aTab is the browser tab to set the value for. + * @param aKey is the value's name. + * @param aStringValue is the value itself (use JSON.stringify/parse before setting JS objects). + */ + void setTabValue(in nsIDOMNode aTab, in AString aKey, in AString aStringValue); + + /** + * @param aTab is the browser tab to get the value for. + * @param aKey is the value's name. + */ + void deleteTabValue(in nsIDOMNode aTab, in AString aKey); + + /** + * @returns A boolean indicating we should restore previous browser session + */ + boolean shouldRestore(); + + /** + * Restores the previous browser session using a fast, lightweight strategy + * @param aBringToFront should a restored tab be brought to the foreground? + */ + void restoreLastSession(in boolean aBringToFront); +}; diff --git a/mobile/android/components/SessionStore.js b/mobile/android/components/SessionStore.js new file mode 100644 index 00000000000..0d9c7438666 --- /dev/null +++ b/mobile/android/components/SessionStore.js @@ -0,0 +1,813 @@ +/* ***** 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 Session Store. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark 'evil' Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +#ifdef MOZ_CRASHREPORTER +XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", + "@mozilla.org/xre/app-info;1", "nsICrashReporter"); +#endif + +XPCOMUtils.defineLazyGetter(this, "NetUtil", function() { + Cu.import("resource://gre/modules/NetUtil.jsm"); + return NetUtil; +}); + +// ----------------------------------------------------------------------- +// Session Store +// ----------------------------------------------------------------------- + +const STATE_STOPPED = 0; +const STATE_RUNNING = 1; +const STATE_QUITTING = -1; + +function SessionStore() { } + +SessionStore.prototype = { + classID: Components.ID("{8c1f07d6-cba3-4226-a315-8bd43d67d032}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsISessionStore, + Ci.nsIDOMEventListener, + Ci.nsIObserver, + Ci.nsISupportsWeakReference]), + + _windows: {}, + _lastSaveTime: 0, + _lastSessionTime: 0, + _interval: 10000, + _maxTabsUndo: 1, + _shouldRestore: false, + + init: function ss_init() { + // Get file references + this._sessionFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile); + this._sessionFileBackup = this._sessionFile.clone(); + this._sessionCache = this._sessionFile.clone(); + this._sessionFile.append("sessionstore.js"); + this._sessionFileBackup.append("sessionstore.bak"); + this._sessionCache.append("sessionstoreCache"); + + this._loadState = STATE_STOPPED; + + try { + if (this._sessionFileBackup.exists()) { + this._shouldRestore = true; + this._sessionFileBackup.remove(false); + } + + if (this._sessionFile.exists()) { + // Disable crash recovery if we have exceeded the timeout + this._lastSessionTime = this._sessionFile.lastModifiedTime; + let delta = Date.now() - this._lastSessionTime; + let timeout = Services.prefs.getIntPref("browser.sessionstore.resume_from_crash_timeout"); + if (delta > (timeout * 60000)) + this._shouldRestore = false; + + this._sessionFile.copyTo(null, this._sessionFileBackup.leafName); + } + + if (!this._sessionCache.exists() || !this._sessionCache.isDirectory()) + this._sessionCache.create(Ci.nsIFile.DIRECTORY_TYPE, 0700); + } catch (ex) { + Cu.reportError(ex); // file was write-locked? + } + + this._interval = Services.prefs.getIntPref("browser.sessionstore.interval"); + this._maxTabsUndo = Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo"); + + // Disable crash recovery if it has been turned off + if (!Services.prefs.getBoolPref("browser.sessionstore.resume_from_crash")) + this._shouldRestore = false; + + // Do we need to restore session just this once, in case of a restart? + if (Services.prefs.getBoolPref("browser.sessionstore.resume_session_once")) { + Services.prefs.setBoolPref("browser.sessionstore.resume_session_once", false); + this._shouldRestore = true; + } + }, + + _clearDisk: function ss_clearDisk() { + if (this._sessionFile.exists()) { + try { + this._sessionFile.remove(false); + } catch (ex) { dump(ex + '\n'); } // couldn't remove the file - what now? + } + if (this._sessionFileBackup.exists()) { + try { + this._sessionFileBackup.remove(false); + } catch (ex) { dump(ex + '\n'); } // couldn't remove the file - what now? + } + + this._clearCache(); + }, + + _clearCache: function ss_clearCache() { + // First, let's get a list of files we think should be active + let activeFiles = []; + this._forEachBrowserWindow(function(aWindow) { + let tabs = aWindow.Browser.tabs; + for (let i = 0; i < tabs.length; i++) { + let browser = tabs[i].browser; + if (browser.__SS_extdata && "thumbnail" in browser.__SS_extdata) + activeFiles.push(browser.__SS_extdata.thumbnail); + } + }); + + // Now, let's find the stale files in the cache folder + let staleFiles = []; + let cacheFiles = this._sessionCache.directoryEntries; + while (cacheFiles.hasMoreElements()) { + let file = cacheFiles.getNext().QueryInterface(Ci.nsILocalFile); + let fileURI = Services.io.newFileURI(file); + if (activeFiles.indexOf(fileURI) == -1) + staleFiles.push(file); + } + + // Remove the stale files in a separate step to keep the enumerator from + // messing up if we remove the files as we collect them. + staleFiles.forEach(function(aFile) { + aFile.remove(false); + }) + }, + + observe: function ss_observe(aSubject, aTopic, aData) { + let self = this; + let observerService = Services.obs; + switch (aTopic) { + case "app-startup": + observerService.addObserver(this, "final-ui-startup", true); + observerService.addObserver(this, "domwindowopened", true); + observerService.addObserver(this, "domwindowclosed", true); + observerService.addObserver(this, "browser-lastwindow-close-granted", true); + observerService.addObserver(this, "browser:purge-session-history", true); + observerService.addObserver(this, "quit-application-requested", true); + observerService.addObserver(this, "quit-application-granted", true); + observerService.addObserver(this, "quit-application", true); + break; + case "final-ui-startup": + observerService.removeObserver(this, "final-ui-startup"); + this.init(); + break; + case "domwindowopened": + let window = aSubject; + window.addEventListener("load", function() { + self.onWindowOpen(window); + window.removeEventListener("load", arguments.callee, false); + }, false); + break; + case "domwindowclosed": // catch closed windows + this.onWindowClose(aSubject); + break; + case "browser-lastwindow-close-granted": + // If a save has been queued, kill the timer and save state now + if (this._saveTimer) { + this._saveTimer.cancel(); + this._saveTimer = null; + this.saveState(); + } + + // Freeze the data at what we've got (ignoring closing windows) + this._loadState = STATE_QUITTING; + break; + case "quit-application-requested": + // Get a current snapshot of all windows + this._forEachBrowserWindow(function(aWindow) { + self._collectWindowData(aWindow); + }); + break; + case "quit-application-granted": + // Get a current snapshot of all windows + this._forEachBrowserWindow(function(aWindow) { + self._collectWindowData(aWindow); + }); + + // Freeze the data at what we've got (ignoring closing windows) + this._loadState = STATE_QUITTING; + break; + case "quit-application": + // If we are restarting, lets restore the tabs + if (aData == "restart") { + Services.prefs.setBoolPref("browser.sessionstore.resume_session_once", true); + + // Ignore purges when restarting. The notification is fired after "quit-application". + Services.obs.removeObserver(this, "browser:purge-session-history"); + } + + // Freeze the data at what we've got (ignoring closing windows) + this._loadState = STATE_QUITTING; + + // No need for this back up, we are shutting down just fine + if (this._sessionFileBackup.exists()) + this._sessionFileBackup.remove(false); + + observerService.removeObserver(this, "domwindowopened"); + observerService.removeObserver(this, "domwindowclosed"); + observerService.removeObserver(this, "browser-lastwindow-close-granted"); + observerService.removeObserver(this, "quit-application-requested"); + observerService.removeObserver(this, "quit-application-granted"); + observerService.removeObserver(this, "quit-application"); + + // If a save has been queued, kill the timer and save state now + if (this._saveTimer) { + this._saveTimer.cancel(); + this._saveTimer = null; + this.saveState(); + } + break; + case "browser:purge-session-history": // catch sanitization + this._clearDisk(); + + // If the browser is shutting down, simply return after clearing the + // session data on disk as this notification fires after the + // quit-application notification so the browser is about to exit. + if (this._loadState == STATE_QUITTING) + return; + + // Clear all data about closed tabs + for (let [ssid, win] in Iterator(this._windows)) + win.closedTabs = []; + + if (this._loadState == STATE_RUNNING) { + // Save the purged state immediately + this.saveStateNow(); + } + break; + case "timer-callback": + // Timer call back for delayed saving + this._saveTimer = null; + this.saveState(); + break; + } + }, + + handleEvent: function ss_handleEvent(aEvent) { + let window = aEvent.currentTarget.ownerDocument.defaultView; + switch (aEvent.type) { + case "TabOpen": + case "TabClose": { + let browser = aEvent.originalTarget.linkedBrowser; + if (aEvent.type == "TabOpen") { + this.onTabAdd(window, browser); + } + else { + this.onTabClose(window, browser); + this.onTabRemove(window, browser); + } + break; + } + case "TabSelect": { + let browser = aEvent.originalTarget.linkedBrowser; + this.onTabSelect(window, browser); + break; + } + } + }, + + receiveMessage: function ss_receiveMessage(aMessage) { + let window = aMessage.target.ownerDocument.defaultView; + this.onTabLoad(window, aMessage.target, aMessage); + }, + + onWindowOpen: function ss_onWindowOpen(aWindow) { + // Return if window has already been initialized + if (aWindow && aWindow.__SSID && this._windows[aWindow.__SSID]) + return; + + // Ignore non-browser windows and windows opened while shutting down + if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" || this._loadState == STATE_QUITTING) + return; + + // Assign it a unique identifier (timestamp) and create its data object + aWindow.__SSID = "window" + Date.now(); + this._windows[aWindow.__SSID] = { tabs: [], selected: 0, closedTabs: [] }; + + // Perform additional initialization when the first window is loading + if (this._loadState == STATE_STOPPED) { + this._loadState = STATE_RUNNING; + this._lastSaveTime = Date.now(); + + // Nothing to restore, notify observers things are complete + if (!this._shouldRestore) { + this._clearCache(); + Services.obs.notifyObservers(null, "sessionstore-windows-restored", ""); + } + } + + // Add tab change listeners to all already existing tabs + let tabs = aWindow.Browser.tabs; + for (let i = 0; i < tabs.length; i++) + this.onTabAdd(aWindow, tabs[i].browser, true); + + // Notification of tab add/remove/selection + let tabContainer = aWindow.document.getElementById("tabs"); + tabContainer.addEventListener("TabOpen", this, true); + tabContainer.addEventListener("TabClose", this, true); + tabContainer.addEventListener("TabSelect", this, true); + }, + + onWindowClose: function ss_onWindowClose(aWindow) { + // Ignore windows not tracked by SessionStore + if (!aWindow.__SSID || !this._windows[aWindow.__SSID]) + return; + + let tabContainer = aWindow.document.getElementById("tabs"); + tabContainer.removeEventListener("TabOpen", this, true); + tabContainer.removeEventListener("TabClose", this, true); + tabContainer.removeEventListener("TabSelect", this, true); + + if (this._loadState == STATE_RUNNING) { + // Update all window data for a last time + this._collectWindowData(aWindow); + + // Clear this window from the list + delete this._windows[aWindow.__SSID]; + + // Save the state without this window to disk + this.saveStateDelayed(); + } + + let tabs = aWindow.Browser.tabs; + for (let i = 0; i < tabs.length; i++) + this.onTabRemove(aWindow, tabs[i].browser, true); + + delete aWindow.__SSID; + }, + + onTabAdd: function ss_onTabAdd(aWindow, aBrowser, aNoNotification) { + aBrowser.messageManager.addMessageListener("pageshow", this); + aBrowser.messageManager.addMessageListener("Content:SessionHistory", this); + + if (!aNoNotification) + this.saveStateDelayed(); + this._updateCrashReportURL(aWindow); + }, + + onTabRemove: function ss_onTabRemove(aWindow, aBrowser, aNoNotification) { + aBrowser.messageManager.removeMessageListener("pageshow", this); + aBrowser.messageManager.removeMessageListener("Content:SessionHistory", this); + + // If this browser is being restored, skip any session save activity + if (aBrowser.__SS_restore) + return; + + delete aBrowser.__SS_data; + + if (!aNoNotification) + this.saveStateDelayed(); + }, + + onTabClose: function ss_onTabClose(aWindow, aBrowser) { + if (this._maxTabsUndo == 0) + return; + + if (aWindow.Browser.tabs.length > 0) { + // Bundle this browser's data and extra data and save in the closedTabs + // window property + let data = aBrowser.__SS_data; + data.extData = aBrowser.__SS_extdata; + + this._windows[aWindow.__SSID].closedTabs.unshift(data); + let length = this._windows[aWindow.__SSID].closedTabs.length; + if (length > this._maxTabsUndo) + this._windows[aWindow.__SSID].closedTabs.splice(this._maxTabsUndo, length - this._maxTabsUndo); + } + }, + + onTabLoad: function ss_onTabLoad(aWindow, aBrowser, aMessage) { + // If this browser is being restored, skip any session save activity + if (aBrowser.__SS_restore) + return; + + // Ignore a transient "about:blank" + if (!aBrowser.canGoBack && aBrowser.currentURI.spec == "about:blank") + return; + + if (aMessage.name == "Content:SessionHistory") { + delete aBrowser.__SS_data; + this._collectTabData(aBrowser, aMessage.json); + } + + // Save out the state as quickly as possible + if (aMessage.name == "pageshow") + this.saveStateNow(); + + this._updateCrashReportURL(aWindow); + }, + + onTabSelect: function ss_onTabSelect(aWindow, aBrowser) { + if (this._loadState != STATE_RUNNING) + return; + + let index = aWindow.Elements.browsers.selectedIndex; + this._windows[aWindow.__SSID].selected = parseInt(index) + 1; // 1-based + + // Restore the resurrected browser + if (aBrowser.__SS_restore) { + let data = aBrowser.__SS_data; + if (data.entries.length > 0) { + let json = { + uri: data.entries[data.index - 1].url, + flags: null, + entries: data.entries, + index: data.index + }; + aBrowser.messageManager.sendAsyncMessage("WebNavigation:LoadURI", json); + } + + delete aBrowser.__SS_restore; + } + + this._updateCrashReportURL(aWindow); + }, + + saveStateDelayed: function ss_saveStateDelayed() { + if (!this._saveTimer) { + // Interval until the next disk operation is allowed + let minimalDelay = this._lastSaveTime + this._interval - Date.now(); + + // If we have to wait, set a timer, otherwise saveState directly + let delay = Math.max(minimalDelay, 2000); + if (delay > 0) { + this._saveTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + this._saveTimer.init(this, delay, Ci.nsITimer.TYPE_ONE_SHOT); + } else { + this.saveState(); + } + } + }, + + saveStateNow: function ss_saveStateNow() { + // Kill any queued timer and save immediately + if (this._saveTimer) { + this._saveTimer.cancel(); + this._saveTimer = null; + } + this.saveState(); + }, + + saveState: function ss_saveState() { + let data = this._getCurrentState(); + this._writeFile(this._sessionFile, JSON.stringify(data)); + + this._lastSaveTime = Date.now(); + }, + + _getCurrentState: function ss_getCurrentState() { + let self = this; + this._forEachBrowserWindow(function(aWindow) { + self._collectWindowData(aWindow); + }); + + let data = { windows: [] }; + let index; + for (index in this._windows) + data.windows.push(this._windows[index]); + return data; + }, + + _collectTabData: function ss__collectTabData(aBrowser, aHistory) { + // If this browser is being restored, skip any session save activity + if (aBrowser.__SS_restore) + return; + + let aHistory = aHistory || { entries: [{ url: aBrowser.currentURI.spec, title: aBrowser.contentTitle }], index: 1 }; + + let tabData = {}; + tabData.entries = aHistory.entries; + tabData.index = aHistory.index; + tabData.attributes = { image: aBrowser.mIconURL }; + + aBrowser.__SS_data = tabData; + }, + + _collectWindowData: function ss__collectWindowData(aWindow) { + // Ignore windows not tracked by SessionStore + if (!aWindow.__SSID || !this._windows[aWindow.__SSID]) + return; + + let winData = this._windows[aWindow.__SSID]; + winData.tabs = []; + + let index = aWindow.Elements.browsers.selectedIndex; + winData.selected = parseInt(index) + 1; // 1-based + + let tabs = aWindow.Browser.tabs; + for (let i = 0; i < tabs.length; i++) { + let browser = tabs[i].browser; + if (browser.__SS_data) { + let tabData = browser.__SS_data; + if (browser.__SS_extdata) + tabData.extData = browser.__SS_extdata; + winData.tabs.push(tabData); + } + } + }, + + _forEachBrowserWindow: function ss_forEachBrowserWindow(aFunc) { + let windowsEnum = Services.wm.getEnumerator("navigator:browser"); + while (windowsEnum.hasMoreElements()) { + let window = windowsEnum.getNext(); + if (window.__SSID && !window.closed) + aFunc.call(this, window); + } + }, + + _writeFile: function ss_writeFile(aFile, aData) { + let stateString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); + stateString.data = aData; + Services.obs.notifyObservers(stateString, "sessionstore-state-write", ""); + + // Don't touch the file if an observer has deleted all state data + if (!stateString.data) + return; + + // Initialize the file output stream. + let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); + ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN); + + // Obtain a converter to convert our data to a UTF-8 encoded input stream. + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + + // Asynchronously copy the data to the file. + let istream = converter.convertToInputStream(aData); + NetUtil.asyncCopy(istream, ostream, function(rc) { + if (Components.isSuccessCode(rc)) { + Services.obs.notifyObservers(null, "sessionstore-state-write-complete", ""); + } + }); + }, + + _updateCrashReportURL: function ss_updateCrashReportURL(aWindow) { +#ifdef MOZ_CRASHREPORTER + try { + let currentURI = aWindow.Browser.selectedBrowser.currentURI.clone(); + // if the current URI contains a username/password, remove it + try { + currentURI.userPass = ""; + } + catch (ex) { } // ignore failures on about: URIs + + CrashReporter.annotateCrashReport("URL", currentURI.spec); + } + catch (ex) { + // don't make noise when crashreporter is built but not enabled + if (ex.result != Components.results.NS_ERROR_NOT_INITIALIZED) + Components.utils.reportError("SessionStore:" + ex); + } +#endif + }, + + getBrowserState: function ss_getBrowserState() { + let data = this._getCurrentState(); + return JSON.stringify(data); + }, + + getClosedTabCount: function ss_getClosedTabCount(aWindow) { + if (!aWindow || !aWindow.__SSID) + return 0; // not a browser window, or not otherwise tracked by SS. + + return this._windows[aWindow.__SSID].closedTabs.length; + }, + + getClosedTabData: function ss_getClosedTabData(aWindow) { + if (!aWindow.__SSID) + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + + return JSON.stringify(this._windows[aWindow.__SSID].closedTabs); + }, + + undoCloseTab: function ss_undoCloseTab(aWindow, aIndex) { + if (!aWindow.__SSID) + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + + let closedTabs = this._windows[aWindow.__SSID].closedTabs; + if (!closedTabs) + return null; + + // default to the most-recently closed tab + aIndex = aIndex || 0; + if (!(aIndex in closedTabs)) + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + + // fetch the data of closed tab, while removing it from the array + let closedTab = closedTabs.splice(aIndex, 1).shift(); + + // create a new tab and bring to front + let tab = aWindow.Browser.addTab(closedTab.entries[closedTab.index - 1].url, true); + + tab.browser.messageManager.sendAsyncMessage("WebNavigation:LoadURI", { + uri: closedTab.entries[closedTab.index - 1].url, + flags: null, + entries: closedTab.entries, + index: closedTab.index + }); + + // Put back the extra data + tab.browser.__SS_extdata = closedTab.extData; + + return tab.chromeTab; + }, + + forgetClosedTab: function ss_forgetClosedTab(aWindow, aIndex) { + if (!aWindow.__SSID) + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + + let closedTabs = this._windows[aWindow.__SSID].closedTabs; + + // default to the most-recently closed tab + aIndex = aIndex || 0; + if (!(aIndex in closedTabs)) + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + + // remove closed tab from the array + closedTabs.splice(aIndex, 1); + }, + + getTabValue: function ss_getTabValue(aTab, aKey) { + let browser = aTab.linkedBrowser; + let data = browser.__SS_extdata || {}; + return data[aKey] || ""; + }, + + setTabValue: function ss_setTabValue(aTab, aKey, aStringValue) { + let browser = aTab.linkedBrowser; + + // Thumbnails are actually stored in the cache, so do the save and update the URI + if (aKey == "thumbnail") { + let file = this._sessionCache.clone(); + file.append("thumbnail-" + browser.contentWindowId); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600); + + let source = Services.io.newURI(aStringValue, "UTF8", null); + let target = Services.io.newFileURI(file) + + let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist); + persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION; + persist.saveURI(source, null, null, null, null, file); + + aStringValue = target.spec; + } + + if (!browser.__SS_extdata) + browser.__SS_extdata = {}; + browser.__SS_extdata[aKey] = aStringValue; + this.saveStateDelayed(); + }, + + deleteTabValue: function ss_deleteTabValue(aTab, aKey) { + let browser = aTab.linkedBrowser; + if (browser.__SS_extdata && browser.__SS_extdata[aKey]) + delete browser.__SS_extdata[aKey]; + else + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + }, + + shouldRestore: function ss_shouldRestore() { + return this._shouldRestore; + }, + + restoreLastSession: function ss_restoreLastSession(aBringToFront) { + let self = this; + function notifyObservers(aMessage) { + self._clearCache(); + Services.obs.notifyObservers(null, "sessionstore-windows-restored", aMessage || ""); + } + + // The previous session data has already been renamed to the backup file + if (!this._sessionFileBackup.exists()) { + notifyObservers("fail") + return; + } + + try { + let channel = NetUtil.newChannel(this._sessionFileBackup); + channel.contentType = "application/json"; + NetUtil.asyncFetch(channel, function(aStream, aResult) { + if (!Components.isSuccessCode(aResult)) { + Cu.reportError("SessionStore: Could not read from sessionstore.bak file"); + notifyObservers("fail"); + return; + } + + // Read session state file into a string and let observers modify the state before it's being used + let state = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); + state.data = NetUtil.readInputStreamToString(aStream, aStream.available()) || ""; + aStream.close(); + + Services.obs.notifyObservers(state, "sessionstore-state-read", ""); + + let data = null; + try { + data = JSON.parse(state.data); + } catch (ex) { + Cu.reportError("SessionStore: Could not parse JSON: " + ex); + } + + if (!data || data.windows.length == 0) { + notifyObservers("fail"); + return; + } + + let window = Services.wm.getMostRecentWindow("navigator:browser"); + + let tabs = data.windows[0].tabs; + let selected = data.windows[0].selected; + if (selected > tabs.length) // Clamp the selected index if it's bogus + selected = 1; + + for (let i=0; i +# Robert John Churchill +# David Hyatt +# Christopher A. Aillon +# Myk Melez +# Pamela Greene +# Gavin Sharp +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +const SIDEBAR_CID = Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}"); +const SIDEBAR_CONTRACTID = "@mozilla.org/sidebar;1"; + +function Sidebar() { + // Depending on if we are in the parent or child, prepare to remote + // certain calls + var appInfo = Cc["@mozilla.org/xre/app-info;1"]; + if (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { + // Parent process + + this.inContentProcess = false; + + // Used for wakeups service. FIXME: clean up with bug 593407 + this.wrappedJSObject = this; + + // Setup listener for child messages. We don't need to call + // addMessageListener as the wakeup service will do that for us. + this.receiveMessage = function(aMessage) { + switch (aMessage.name) { + case "Sidebar:AddSearchProvider": + this.AddSearchProvider(aMessage.json.descriptionURL); + } + }; + } else { + // Child process + + this.inContentProcess = true; + this.messageManager = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender); + } +} + +Sidebar.prototype = { + // =========================== utility code =========================== + _validateSearchEngine: function validateSearchEngine(engineURL, iconURL) { + try { + // Make sure we're using HTTP, HTTPS, or FTP. + if (! /^(https?|ftp):\/\//i.test(engineURL)) + throw "Unsupported search engine URL"; + + // Make sure we're using HTTP, HTTPS, or FTP and refering to a + // .gif/.jpg/.jpeg/.png/.ico file for the icon. + if (iconURL && + ! /^(https?|ftp):\/\/.+\.(gif|jpg|jpeg|png|ico)$/i.test(iconURL)) + throw "Unsupported search icon URL."; + } catch(ex) { + Cu.reportError("Invalid argument passed to window.sidebar.addSearchEngine: " + ex); + + var searchBundle = Services.strings.createBundle("chrome://global/locale/search/search.properties"); + var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties"); + var brandName = brandBundle.GetStringFromName("brandShortName"); + var title = searchBundle.GetStringFromName("error_invalid_engine_title"); + var msg = searchBundle.formatStringFromName("error_invalid_engine_msg", + [brandName], 1); + Services.prompt.alert(null, title, msg); + return false; + } + + return true; + }, + + // =========================== nsISidebar =========================== + addPanel: function addPanel(aTitle, aContentURL, aCustomizeURL) { + // not supported + }, + + addPersistentPanel: function addPersistentPanel(aTitle, aContentURL, aCustomizeURL) { + // not supported + }, + + // The suggestedTitle and suggestedCategory parameters are ignored, but remain + // for backward compatibility. + addSearchEngine: function addSearchEngine(engineURL, iconURL, suggestedTitle, + suggestedCategory) { + if (!this._validateSearchEngine(engineURL, iconURL)) + return; + + // File extension for Sherlock search plugin description files + const SHERLOCK_FILE_EXT_REGEXP = /\.src$/i; + + // OpenSearch files will likely be far more common than Sherlock files, and + // have less consistent suffixes, so we assume that ".src" is a Sherlock + // (text) file, and anything else is OpenSearch (XML). + var dataType; + if (SHERLOCK_FILE_EXT_REGEXP.test(engineURL)) + dataType = Ci.nsISearchEngine.DATA_TEXT; + else + dataType = Ci.nsISearchEngine.DATA_XML; + + Services.search.addEngine(engineURL, dataType, iconURL, true); + }, + + // =========================== nsISidebarExternal =========================== + // This function exists to implement window.external.AddSearchProvider(), + // to match other browsers' APIs. The capitalization, although nonstandard here, + // is therefore important. + AddSearchProvider: function AddSearchProvider(aDescriptionURL) { + if (!this._validateSearchEngine(aDescriptionURL, "")) + return; + + if (this.inContentProcess) { + this.messageManager.sendAsyncMessage("Sidebar:AddSearchProvider", + { descriptionURL: aDescriptionURL }); + return; + } + + const typeXML = Ci.nsISearchEngine.DATA_XML; + Services.search.addEngine(aDescriptionURL, typeXML, "", true); + }, + + // This function exists to implement window.external.IsSearchProviderInstalled(), + // for compatibility with other browsers. It will return an integer value + // indicating whether the given engine is installed for the current user. + // However, it is currently stubbed out due to security/privacy concerns + // stemming from difficulties in determining what domain issued the request. + // See bug 340604 and + // http://msdn.microsoft.com/en-us/library/aa342526%28VS.85%29.aspx . + // XXX Implement this! + IsSearchProviderInstalled: function IsSearchProviderInstalled(aSearchURL) { + return 0; + }, + + // =========================== nsIClassInfo =========================== + classInfo: XPCOMUtils.generateCI({classID: SIDEBAR_CID, + contractID: SIDEBAR_CONTRACTID, + interfaces: [Ci.nsISidebar, + Ci.nsISidebarExternal], + flags: Ci.nsIClassInfo.DOM_OBJECT, + classDescription: "Sidebar"}), + + // =========================== nsISupports =========================== + QueryInterface: XPCOMUtils.generateQI([Ci.nsISidebar, + Ci.nsISidebarExternal]), + + // XPCOMUtils stuff + classID: SIDEBAR_CID, +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([Sidebar]); diff --git a/mobile/android/components/UpdatePrompt.js b/mobile/android/components/UpdatePrompt.js new file mode 100644 index 00000000000..262744bcb4e --- /dev/null +++ b/mobile/android/components/UpdatePrompt.js @@ -0,0 +1,341 @@ +/* ***** 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 Update Prompt. + * + * 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): + * Mark Finkle + * Alex Pakhotin + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +const UPDATE_NOTIFICATION_NAME = "update-app"; +const UPDATE_NOTIFICATION_ICON = "drawable://alert_download_progress"; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + + +XPCOMUtils.defineLazyGetter(this, "gUpdateBundle", function aus_gUpdateBundle() { + return Services.strings.createBundle("chrome://mozapps/locale/update/updates.properties"); +}); + +XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function aus_gBrandBundle() { + return Services.strings.createBundle("chrome://branding/locale/brand.properties"); +}); + +XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function aus_gBrowserBundle() { + return Services.strings.createBundle("chrome://browser/locale/browser.properties"); +}); + +XPCOMUtils.defineLazyGetter(this, "AddonManager", function() { + Cu.import("resource://gre/modules/AddonManager.jsm"); + return AddonManager; +}); + +XPCOMUtils.defineLazyGetter(this, "LocaleRepository", function() { + Cu.import("resource://gre/modules/LocaleRepository.jsm"); + return LocaleRepository; +}); + +function getPref(func, preference, defaultValue) { + try { + return Services.prefs[func](preference); + } catch (e) {} + return defaultValue; +} + +// ----------------------------------------------------------------------- +// Update Prompt +// ----------------------------------------------------------------------- + +function UpdatePrompt() { } + +UpdatePrompt.prototype = { + classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt, Ci.nsIRequestObserver, Ci.nsIProgressEventSink]), + + get _enabled() { + return !getPref("getBoolPref", "app.update.silent", false); + }, + + _showNotification: function UP__showNotif(aUpdate, aTitle, aText, aImageUrl, aMode) { + let observer = { + updatePrompt: this, + observe: function (aSubject, aTopic, aData) { + switch (aTopic) { + case "alertclickcallback": + this.updatePrompt._handleUpdate(aUpdate, aMode); + break; + } + } + }; + + let notifier = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService); + notifier.showAlertNotification(aImageUrl, aTitle, aText, true, "", observer, UPDATE_NOTIFICATION_NAME); + }, + + _handleUpdate: function UP__handleUpdate(aUpdate, aMode) { + if (aMode == "available") { + let window = Services.wm.getMostRecentWindow("navigator:browser"); + let title = gUpdateBundle.GetStringFromName("updatesfound_" + aUpdate.type + ".title"); + let brandName = gBrandBundle.GetStringFromName("brandShortName"); + + // Unconditionally use the "major" type here as for now it is always a new version + // without additional description required for a minor update message + let message = gUpdateBundle.formatStringFromName("intro_major", [brandName, aUpdate.displayVersion], 2); + let button0 = gUpdateBundle.GetStringFromName("okButton"); + let button1 = gUpdateBundle.GetStringFromName("askLaterButton"); + let prompt = Services.prompt; + let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_IS_STRING + prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_IS_STRING; + + let download = (prompt.confirmEx(window, title, message, flags, button0, button1, null, null, {value: false}) == 0); + if (download) { + // Start downloading the update in the background + let aus = Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService); + if (aus.downloadUpdate(aUpdate, true) != "failed") { + let title = gBrowserBundle.formatStringFromName("alertDownloadsStart", [aUpdate.name], 1); + this._showNotification(aUpdate, title, "", UPDATE_NOTIFICATION_ICON, "download"); + + // Add this UI as a listener for active downloads + aus.addDownloadListener(this); + } + } + } else if(aMode == "downloaded") { + // 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, restart 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); + } + } + }, + + _updateDownloadProgress: function UP__updateDownloadProgress(aProgress, aTotal) { + let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService); + let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener); + if (progressListener) + progressListener.onProgress(UPDATE_NOTIFICATION_NAME, aProgress, aTotal); + }, + + // ------------------------- + // nsIUpdatePrompt interface + // ------------------------- + + // Right now this is used only to check for updates in progress + checkForUpdates: function UP_checkForUpdates() { + if (!this._enabled) + return; + + let aus = Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService); + if (!aus.isDownloading) + return; + + let updateManager = Cc["@mozilla.org/updates/update-manager;1"].getService(Ci.nsIUpdateManager); + + let updateName = updateManager.activeUpdate ? updateManager.activeUpdate.name : gBrandBundle.GetStringFromName("brandShortName"); + let title = gBrowserBundle.formatStringFromName("alertDownloadsStart", [updateName], 1); + + this._showNotification(updateManager.activeUpdate, title, "", UPDATE_NOTIFICATION_ICON, "downloading"); + + aus.removeDownloadListener(this); // just in case it's already added + aus.addDownloadListener(this); + }, + + showUpdateAvailable: function UP_showUpdateAvailable(aUpdate) { + if (!this._enabled) + return; + + const PREF_APP_UPDATE_SKIPNOTIFICATION = "app.update.skipNotification"; + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SKIPNOTIFICATION) && + Services.prefs.getBoolPref(PREF_APP_UPDATE_SKIPNOTIFICATION)) { + Services.prefs.setBoolPref(PREF_APP_UPDATE_SKIPNOTIFICATION, false); + + // Notification was already displayed and clicked, so jump to the next step: + // ask the user about downloading update + this._handleUpdate(aUpdate, "available"); + return; + } + + let stringsPrefix = "updateAvailable_" + aUpdate.type + "."; + let title = gUpdateBundle.formatStringFromName(stringsPrefix + "title", [aUpdate.name], 1); + let text = gUpdateBundle.GetStringFromName(stringsPrefix + "text"); + let imageUrl = ""; + this._showNotification(aUpdate, title, text, imageUrl, "available"); + }, + + showUpdateDownloaded: function UP_showUpdateDownloaded(aUpdate, aBackground) { + if (!this._enabled) + return; + + // uninstall all installed locales + AddonManager.getAddonsByTypes(["locale"], (function (aAddons) { + if (aAddons.length > 0) { + let listener = this.getAddonListener(aUpdate, this); + AddonManager.addAddonListener(listener); + aAddons.forEach(function(aAddon) { + listener._uninstalling.push(aAddon.id); + aAddon.uninstall(); + }, this); + } else { + this._showDownloadedNotification(aUpdate); + } + }).bind(this)); + }, + + _showDownloadedNotification: function UP_showDlNotification(aUpdate) { + let stringsPrefix = "updateDownloaded_" + aUpdate.type + "."; + let title = gUpdateBundle.formatStringFromName(stringsPrefix + "title", [aUpdate.name], 1); + let text = gUpdateBundle.GetStringFromName(stringsPrefix + "text"); + let imageUrl = ""; + this._showNotification(aUpdate, title, text, imageUrl, "downloaded"); + }, + + _uninstalling: [], + _installing: [], + _currentUpdate: null, + + _reinstallLocales: function UP_reinstallLocales(aUpdate, aListener, aPending) { + LocaleRepository.getLocales((function(aLocales) { + aLocales.forEach(function(aLocale, aIndex, aArray) { + let index = aPending.indexOf(aLocale.addon.id); + if (index > -1) { + aListener._installing.push(aLocale.addon.id); + aLocale.addon.install.install(); + } + }, this); + // store the buildid of these locales so that we can disable locales when the + // user updates through a non-updater channel + Services.prefs.setCharPref("extensions.compatability.locales.buildid", aUpdate.buildID); + }).bind(this), { buildID: aUpdate.buildID }); + }, + + showUpdateInstalled: function UP_showUpdateInstalled() { + if (!this._enabled || !getPref("getBoolPref", "app.update.showInstalledUI", false)) + return; + + let title = gBrandBundle.GetStringFromName("brandShortName"); + let text = gUpdateBundle.GetStringFromName("installSuccess"); + let imageUrl = ""; + this._showNotification(aUpdate, title, text, imageUrl, "installed"); + }, + + showUpdateError: function UP_showUpdateError(aUpdate) { + if (!this._enabled) + return; + + if (aUpdate.state == "failed") { + var title = gBrandBundle.GetStringFromName("brandShortName"); + let text = gUpdateBundle.GetStringFromName("updaterIOErrorTitle"); + let imageUrl = ""; + this._showNotification(aUpdate, title, text, imageUrl, "error"); + } + }, + + showUpdateHistory: function UP_showUpdateHistory(aParent) { + // NOT IMPL + }, + + // ---------------------------- + // nsIRequestObserver interface + // ---------------------------- + + // When the data transfer begins + onStartRequest: function(request, context) { + // NOT IMPL + }, + + // When the data transfer ends + onStopRequest: function(request, context, status) { + let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService); + let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener); + if (progressListener) + progressListener.onCancel(UPDATE_NOTIFICATION_NAME); + + + let aus = Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService); + aus.removeDownloadListener(this); + }, + + // ------------------------------ + // nsIProgressEventSink interface + // ------------------------------ + + // When new data has been downloaded + onProgress: function(request, context, progress, maxProgress) { + this._updateDownloadProgress(progress, maxProgress); + }, + + // When we have new status text + onStatus: function(request, context, status, statusText) { + // NOT IMPL + }, + + // ------------------------------- + // AddonListener + // ------------------------------- + getAddonListener: function(aUpdate, aUpdatePrompt) { + return { + _installing: [], + _uninstalling: [], + onInstalling: function(aAddon, aNeedsRestart) { + let index = this._installing.indexOf(aAddon.id); + if (index > -1) + this._installing.splice(index, 1); + + if (this._installing.length == 0) { + aUpdatePrompt._showDownloadedNotification(aUpdate); + AddonManager.removeAddonListener(this); + } + }, + + onUninstalling: function(aAddon, aNeedsRestart) { + let pending = []; + let index = this._uninstalling.indexOf(aAddon.id); + if (index > -1) { + pending.push(aAddon.id); + this._uninstalling.splice(index, 1); + } + if (this._uninstalling.length == 0) + aUpdatePrompt._reinstallLocales(aUpdate, this, pending); + } + } + } + +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([UpdatePrompt]); diff --git a/mobile/android/components/XPIDialogService.js b/mobile/android/components/XPIDialogService.js new file mode 100644 index 00000000000..796abad325f --- /dev/null +++ b/mobile/android/components/XPIDialogService.js @@ -0,0 +1,71 @@ +/* ***** 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 XPI Dialog Service. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +// ----------------------------------------------------------------------- +// Web Install Prompt service +// ----------------------------------------------------------------------- + +function WebInstallPrompt() { } + +WebInstallPrompt.prototype = { + classID: Components.ID("{c1242012-27d8-477e-a0f1-0b098ffc329b}"), + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallPrompt]), + + confirm: function(aWindow, aURL, aInstalls) { + let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); + + let prompt = Services.prompt; + let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_IS_STRING + prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL; + let title = bundle.GetStringFromName("addonsConfirmInstall.title"); + let button = bundle.GetStringFromName("addonsConfirmInstall.install"); + + aInstalls.forEach(function(install) { + let result = (prompt.confirmEx(aWindow, title, install.name, flags, button, null, null, null, {value: false}) == 0); + if (result) + install.install(); + else + install.cancel(); + }); + } +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([WebInstallPrompt]); diff --git a/mobile/android/components/build/Makefile.in b/mobile/android/components/build/Makefile.in new file mode 100644 index 00000000000..d1b510e7759 --- /dev/null +++ b/mobile/android/components/build/Makefile.in @@ -0,0 +1,80 @@ +# ***** 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 Minimo Tel Protocol Handler. +# +# The Initial Developer of the Original Code is +# the Mozilla Foundation . +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Doug Turner . +# Nino D'Aversa +# +# 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 + +MODULE_NAME = nsBrowserCompsModule +MODULE = browsercomps +LIBRARY_NAME = browsercomps +LIBXUL_LIBRARY = 1 + +IS_COMPONENT = 1 +EXPORT_LIBRARY = 1 + +EXPORTS = nsBrowserComponents.h + +REQUIRES = \ + xpcom \ + string \ + pref \ + $(NULL) + +XPIDL_MODULE = browsercomps + +XPIDLSRCS = nsIShellService.idl + +CPPSRCS = \ + nsBrowserModule.cpp \ + nsShellService.cpp \ + $(NULL) + +ifeq ($(MOZ_PLATFORM_MAEMO),5) +LOCAL_INCLUDES += $(MOZ_DBUS_GLIB_CFLAGS) +endif + +ifneq (,$(filter $(MOZ_WIDGET_TOOLKIT),qt)) +LOCAL_INCLUDES += $(MOZ_QT_CFLAGS) +endif + +include $(topsrcdir)/config/rules.mk + diff --git a/mobile/android/components/build/nsBrowserComponents.h b/mobile/android/components/build/nsBrowserComponents.h new file mode 100644 index 00000000000..1a85c7e7d89 --- /dev/null +++ b/mobile/android/components/build/nsBrowserComponents.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * ***** 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 Mobile Browser. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * 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 ***** */ + +// Needed for building our components as part of libxul +#define APP_COMPONENT_MODULES MODULE(nsBrowserCompsModule) diff --git a/mobile/android/components/build/nsBrowserModule.cpp b/mobile/android/components/build/nsBrowserModule.cpp new file mode 100644 index 00000000000..d986efa20c4 --- /dev/null +++ b/mobile/android/components/build/nsBrowserModule.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * ***** 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 Mobile Browser. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * 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 ***** */ + +#include "mozilla/ModuleUtils.h" + +#include "nsShellService.h" + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsShellService) +NS_DEFINE_NAMED_CID(nsShellService_CID); + +static const mozilla::Module::CIDEntry kBrowserCIDs[] = { + { &knsShellService_CID, false, NULL, nsShellServiceConstructor }, + { NULL } +}; + +static const mozilla::Module::ContractIDEntry kBrowserContracts[] = { + { nsShellService_ContractID, &knsShellService_CID }, + { NULL } +}; + +static const mozilla::Module kBrowserModule = { + mozilla::Module::kVersion, + kBrowserCIDs, + kBrowserContracts +}; + +NSMODULE_DEFN(nsBrowserCompsModule) = &kBrowserModule; diff --git a/mobile/android/components/build/nsIShellService.idl b/mobile/android/components/build/nsIShellService.idl new file mode 100644 index 00000000000..fa5059997fb --- /dev/null +++ b/mobile/android/components/build/nsIShellService.idl @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * ***** 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 Minimo Tel Protocol Handler. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Nino D'Aversa + * + * 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 ***** */ + +#include "nsISupports.idl" + +[scriptable, uuid(fd2450a3-966b-44a9-a8eb-316256bb80b4)] +interface nsIShellService : nsISupports +{ + /** + * This method displays a UI to switch to (or launch) a different task + */ + void switchTask(); + + /** + * This method creates a shortcut on a desktop or homescreen that opens in + * the our application. + * + * @param aTitle the user-friendly name of the shortcut. + * @param aURI the URI to open. + * @param aIconData a base64 encoded representation of the shortcut's icon. + * @param aIntent how the URI should be opened. Examples: "default", "bookmark" and "webapp" + */ + void createShortcut(in AString aTitle, in AString aURI, in AString aIconData, in AString aIntent); +}; diff --git a/mobile/android/components/build/nsShellService.cpp b/mobile/android/components/build/nsShellService.cpp new file mode 100644 index 00000000000..477976477d4 --- /dev/null +++ b/mobile/android/components/build/nsShellService.cpp @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * ***** 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 Minimo Tel Protocol Handler. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Nino D'Aversa + * Alex Pakhotin + * + * 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 ***** */ + +#if (MOZ_PLATFORM_MAEMO == 5) +#include +#endif + +#ifdef MOZ_WIDGET_QT +#include +#include +#endif + +#ifdef MOZ_WIDGET_ANDROID +#include "AndroidBridge.h" +#endif + +#include "nsShellService.h" +#include "nsString.h" + +NS_IMPL_ISUPPORTS1(nsShellService, nsIShellService) + +NS_IMETHODIMP +nsShellService::SwitchTask() +{ +#if (MOZ_PLATFORM_MAEMO == 5) + DBusError error; + dbus_error_init(&error); + + DBusConnection *conn = dbus_bus_get(DBUS_BUS_SESSION, &error); + + DBusMessage *msg = dbus_message_new_signal("/com/nokia/hildon_desktop", + "com.nokia.hildon_desktop", + "exit_app_view"); + + if (msg) { + dbus_connection_send(conn, msg, NULL); + dbus_message_unref(msg); + dbus_connection_flush(conn); + } + return NS_OK; +#elif MOZ_WIDGET_QT + QWidget * window = QApplication::activeWindow(); + if (window) + window->showMinimized(); + return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +NS_IMETHODIMP +nsShellService::CreateShortcut(const nsAString& aTitle, const nsAString& aURI, const nsAString& aIconData, const nsAString& aIntent) +{ + if (!aTitle.Length() || !aURI.Length() || !aIconData.Length()) + return NS_ERROR_FAILURE; + +#if MOZ_WIDGET_ANDROID + mozilla::AndroidBridge::Bridge()->CreateShortcut(aTitle, aURI, aIconData, aIntent); + return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} diff --git a/mobile/android/components/build/nsShellService.h b/mobile/android/components/build/nsShellService.h new file mode 100644 index 00000000000..a77b9f78d1c --- /dev/null +++ b/mobile/android/components/build/nsShellService.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * ***** 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 Minimo Tel Protocol Handler. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Nino D'Aversa + * Alex Pakhotin + * + * 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 ***** */ + +#ifndef __NS_SHELLSERVICE_H__ +#define __NS_SHELLSERVICE_H__ + +#include "nsIShellService.h" + +class nsShellService : public nsIShellService +{ +public: + + NS_DECL_ISUPPORTS + NS_DECL_NSISHELLSERVICE + + nsShellService() {}; + ~nsShellService() {}; + +}; + +#define nsShellService_CID \ +{0xae9ebe1c, 0x61e9, 0x45fa, {0x8f, 0x34, 0xc1, 0x07, 0x80, 0x3a, 0x5b, 0x44}} + +#define nsShellService_ContractID "@mozilla.org/browser/shell-service;1" + +#endif diff --git a/mobile/android/config/mozconfigs/android/debug b/mobile/android/config/mozconfigs/android/debug new file mode 100644 index 00000000000..09933855668 --- /dev/null +++ b/mobile/android/config/mozconfigs/android/debug @@ -0,0 +1,21 @@ +# Global options +mk_add_options MOZ_MAKE_FLAGS=-j4 +ac_add_options --enable-debug + +# Build Fennec +ac_add_options --enable-application=mobile/android + +# Android +ac_add_options --target=arm-linux-androideabi +ac_add_options --with-endian=little +ac_add_options --with-android-ndk="/tools/android-ndk-r5c" +ac_add_options --with-android-sdk="/tools/android-sdk-r13/platforms/android-13" +ac_add_options --with-android-tools="/tools/android-sdk-r13/tools" +ac_add_options --with-android-toolchain=/tools/android-ndk-r5c/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86 +ac_add_options --with-android-platform=/tools/android-ndk-r5c/platforms/android-5/arch-arm +ac_add_options --with-system-zlib + +export JAVA_HOME=/tools/jdk6 +export MOZILLA_OFFICIAL=1 + +ac_add_options --with-branding=mobile/android/branding/nightly diff --git a/mobile/android/config/mozconfigs/android/nightly b/mobile/android/config/mozconfigs/android/nightly new file mode 100644 index 00000000000..b766f04ba11 --- /dev/null +++ b/mobile/android/config/mozconfigs/android/nightly @@ -0,0 +1,21 @@ +# Global options +mk_add_options MOZ_MAKE_FLAGS=-j4 + +# Build Fennec +ac_add_options --enable-application=mobile/android + +# Android +ac_add_options --target=arm-linux-androideabi +ac_add_options --with-endian=little +ac_add_options --with-android-ndk="/tools/android-ndk-r5c" +ac_add_options --with-android-sdk="/tools/android-sdk-r13/platforms/android-13" +ac_add_options --with-android-tools="/tools/android-sdk-r13/tools" +ac_add_options --with-android-toolchain=/tools/android-ndk-r5c/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86 +ac_add_options --with-android-platform=/tools/android-ndk-r5c/platforms/android-5/arch-arm +ac_add_options --with-system-zlib +ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} + +export JAVA_HOME=/tools/jdk6 +export MOZILLA_OFFICIAL=1 + +ac_add_options --with-branding=mobile/android/branding/nightly diff --git a/mobile/android/config/mozconfigs/linux-desktop/l10n-mozconfig b/mobile/android/config/mozconfigs/linux-desktop/l10n-mozconfig new file mode 100644 index 00000000000..ae620448594 --- /dev/null +++ b/mobile/android/config/mozconfigs/linux-desktop/l10n-mozconfig @@ -0,0 +1,5 @@ +mk_add_options MOZ_PKG_FORMAT=BZ2 + +ac_add_options --with-l10n-base=../../l10n-central +ac_add_options --enable-application=mobile/android +ac_add_options --disable-compile-environment diff --git a/mobile/android/config/mozconfigs/linux-desktop/nightly b/mobile/android/config/mozconfigs/linux-desktop/nightly new file mode 100644 index 00000000000..ef68f21ae1c --- /dev/null +++ b/mobile/android/config/mozconfigs/linux-desktop/nightly @@ -0,0 +1,12 @@ +mk_add_options MOZ_PKG_FORMAT=BZ2 +ac_add_options --enable-application=mobile/android + +# Nightlies only since this has a cost in performance +ac_add_options --enable-js-diagnostics + +CC=/tools/gcc-4.5/bin/gcc +CXX=/tools/gcc-4.5/bin/g++ +# Avoid dependency on libstdc++ 4.5 +ac_add_options --enable-stdcxx-compat + +export MOZILLA_OFFICIAL=1 diff --git a/mobile/android/config/mozconfigs/macosx-desktop/l10n-mozconfig b/mobile/android/config/mozconfigs/macosx-desktop/l10n-mozconfig new file mode 100644 index 00000000000..b8eb22b07fc --- /dev/null +++ b/mobile/android/config/mozconfigs/macosx-desktop/l10n-mozconfig @@ -0,0 +1,3 @@ +ac_add_options --with-l10n-base=../../l10n-central +ac_add_options --enable-application=mobile/android +ac_add_options --disable-compile-environment diff --git a/mobile/android/config/mozconfigs/macosx-desktop/nightly b/mobile/android/config/mozconfigs/macosx-desktop/nightly new file mode 100644 index 00000000000..2cf0bfc42db --- /dev/null +++ b/mobile/android/config/mozconfigs/macosx-desktop/nightly @@ -0,0 +1,15 @@ +# Options for client.mk. +mk_add_options AUTOCONF=autoconf213 + +# Global options +. $topsrcdir/build/macosx/mozconfig.leopard +ac_cv_visibility_pragma=no + +ac_add_options --disable-install-strip +ac_add_options --disable-installer +ac_add_options --enable-application=mobile/android + +# Nightlies only since this has a cost in performance +ac_add_options --enable-js-diagnostics + +export MOZILLA_OFFICIAL=1 diff --git a/mobile/android/config/mozconfigs/win32-desktop/l10n-mozconfig b/mobile/android/config/mozconfigs/win32-desktop/l10n-mozconfig new file mode 100644 index 00000000000..905c633852a --- /dev/null +++ b/mobile/android/config/mozconfigs/win32-desktop/l10n-mozconfig @@ -0,0 +1,6 @@ +mk_add_options MOZ_PKG_FORMAT=ZIP + +ac_add_options --with-l10n-base=../../l10n-central +ac_add_options --enable-application=mobile/android +ac_add_options --disable-compile-environment +ac_add_options --disable-angle diff --git a/mobile/android/config/mozconfigs/win32-desktop/nightly b/mobile/android/config/mozconfigs/win32-desktop/nightly new file mode 100644 index 00000000000..f37480434cc --- /dev/null +++ b/mobile/android/config/mozconfigs/win32-desktop/nightly @@ -0,0 +1,13 @@ +# Options for client.mk. +mk_add_options MOZ_PKG_FORMAT=ZIP + +export WIN32_REDIST_DIR=/d/msvs8/VC/redist/x86/Microsoft.VC80.CRT + +ac_add_options --enable-jemalloc +ac_add_options --enable-application=mobile/android +ac_add_options --disable-webm + +# Nightlies only since this has a cost in performance +ac_add_options --enable-js-diagnostics + +export MOZILLA_OFFICIAL=1 diff --git a/mobile/android/confvars.sh b/mobile/android/confvars.sh new file mode 100644 index 00000000000..8737693ba49 --- /dev/null +++ b/mobile/android/confvars.sh @@ -0,0 +1,76 @@ +# ***** 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 . +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Finkle +# +# 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 ***** + +MOZ_APP_BASENAME=Fennec +MOZ_APP_VENDOR=Mozilla + +MOZ_APP_VERSION=11.0a1 + +MOZ_BRANDING_DIRECTORY=mobile/android/branding/unofficial +MOZ_OFFICIAL_BRANDING_DIRECTORY=mobile/android/branding/official +# MOZ_APP_DISPLAYNAME is set by branding/configure.sh + +MOZ_SAFE_BROWSING= +MOZ_SERVICES_SYNC=1 + +MOZ_DISABLE_DOMCRYPTO=1 + +if test "$LIBXUL_SDK"; then +MOZ_XULRUNNER=1 +else +MOZ_XULRUNNER= +MOZ_PLACES=1 +fi + +if test "$OS_TARGET" = "Android"; then +MOZ_CAPTURE=1 +MOZ_RAW=1 +fi + +# Needed for building our components as part of libxul +MOZ_APP_COMPONENT_LIBS="browsercomps" +MOZ_APP_COMPONENT_INCLUDE=nsBrowserComponents.h + +# use custom widget for html:select +MOZ_USE_NATIVE_POPUP_WINDOWS=1 + +MOZ_APP_ID={aa3c5121-dab2-40e2-81ca-7ea25febc110} + +MOZ_JAVA_COMPOSITOR=1 +MOZ_EXTENSION_MANAGER=1 +MOZ_APP_STATIC_INI=1 + diff --git a/mobile/android/installer/Makefile.in b/mobile/android/installer/Makefile.in new file mode 100644 index 00000000000..9c14db85320 --- /dev/null +++ b/mobile/android/installer/Makefile.in @@ -0,0 +1,257 @@ +# ***** 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 . +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Finkle +# Ben Combee +# +# 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 + +# overwrite mobile-l10n.js with a matchOS=true one for multi-locale builds +ifeq ($(AB_CD),multi) +PREF_JS_EXPORTS = $(srcdir)/mobile-l10n.js +endif + +include $(topsrcdir)/config/rules.mk + +MOZ_PKG_REMOVALS = $(srcdir)/removed-files.in + +MOZ_PKG_MANIFEST_P = $(srcdir)/package-manifest.in + +MOZ_NONLOCALIZED_PKG_LIST = \ + xpcom \ + browser \ + mobile \ + $(NULL) + +MOZ_LOCALIZED_PKG_LIST = $(AB_CD) multilocale + +DEFINES += \ + -DAB_CD=$(AB_CD) \ + -DMOZ_APP_NAME=$(MOZ_APP_NAME) \ + -DPREF_DIR=$(PREF_DIR) \ + $(NULL) + +ifeq ($(MOZ_CHROME_FILE_FORMAT),jar) +JAREXT=.jar +else +JAREXT= +endif +DEFINES += -DJAREXT=$(JAREXT) + +include $(topsrcdir)/ipc/app/defs.mk +DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME) + +ifdef MOZ_PKG_MANIFEST_P +MOZ_PKG_MANIFEST = package-manifest +endif + +MOZ_POST_STAGING_CMD = find chrome -type f -name *.properties -exec sed -i '/^\#/d' {} \; + +include $(topsrcdir)/toolkit/mozapps/installer/packager.mk + +ifeq (bundle, $(MOZ_FS_LAYOUT)) +BINPATH = $(_BINPATH) +DEFINES += -DAPPNAME=$(_APPNAME) +else +# Every other platform just winds up in dist/bin +BINPATH = bin +endif +DEFINES += -DBINPATH=$(BINPATH) + +ifdef MOZ_PKG_MANIFEST_P +$(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) FORCE + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@ +ifdef MOZ_CHROME_MULTILOCALE + printf "\n[multilocale]\n" >> $@ + for LOCALE in en-US $(MOZ_CHROME_MULTILOCALE) ;\ + do \ + printf "$(BINPATH)/chrome/$$LOCALE$(JAREXT)\n" >> $@; \ + printf "$(BINPATH)/chrome/$$LOCALE.manifest\n" >> $@; \ + done +endif + +GARBAGE += $(MOZ_PKG_MANIFEST) +endif + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +PACKAGE_XULRUNNER = +UNPACKAGE = +else +PACKAGE_XULRUNNER = package-xulrunner +UNPACKAGE = $(LIBXUL_DIST)/xulrunner*$(PKG_SUFFIX) +endif + +ifdef LIBXUL_SDK +MOZ_GRE_PKG_DIR=$(MOZ_PKG_DIR)/xulrunner +else +MOZ_GRE_PKG_DIR=$(MOZ_PKG_DIR) +endif + +package-xulrunner: +ifdef LIBXUL_SDK +ifndef SYSTEM_LIBXUL + @echo "Packaging xulrunner..." + @rm -rf $(LIBXUL_DIST)/xulrunner* + @$(MAKE) -C $(LIBXUL_DIST)/.. package || echo "Perhaps you're trying to package a prebuilt SDK. See 'https://wiki.mozilla.org/Mobile/Build/Fennec#Build' for more information." + @cd $(DIST)/$(MOZ_PKG_DIR); $(UNMAKE_PACKAGE) + @echo "Removing unpackaged files... (the ones xulrunner/installer keeps)" + @cd $(DIST)/$(MOZ_PKG_DIR)/xulrunner; rm -rf $(NO_PKG_FILES) +else + @echo "Using system xulrunner..." +endif +endif + +ifeq ($(OS_TARGET),Linux) +GRE_MILESTONE = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBXUL_DIST)/bin/platform.ini Build Milestone) +GRE_BUILDID = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBXUL_DIST)/bin/platform.ini Build BuildID) +ABS_OBJDIR=`cd $(DEPTH); pwd` +ABS_TOPSRCDIR=$(shell cd $(topsrcdir); pwd) +BASE64_ICON = dist/branding/fennec_maemo_icon26.txt +MOZ_DEB_TIMESTAMP = "$(shell date +"%a, %d %b %Y %T %z" )" + +DEB_PKG_VERSION = $(shell echo $(MOZ_APP_VERSION) | $(PERL) -pe 's/pre/~$(GRE_BUILDID)/; s/^([0-9.]+)([a-z][0-9]+)/$$1~$$2/') + +DEB_BUILD_ARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH) +# package name should match mobile/installer/debian/changelog.in +DEB_PKG_NAME = $(MOZ_PKG_APPNAME)_$(DEB_PKG_VERSION)_$(DEB_BUILD_ARCH).deb + +DEFINES += \ + -DGRE_MILESTONE=$(GRE_MILESTONE) \ + -DGRE_BUILDID=$(GRE_BUILDID) \ + -Dinstalldir=$(installdir) \ + -DMOZ_APP_DISPLAYNAME="$(MOZ_APP_DISPLAYNAME)" \ + -DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \ + -DABS_OBJDIR=$(ABS_OBJDIR) \ + -DBASE64_ICON=$(BASE64_ICON) \ + -DMOZ_DEB_TIMESTAMP=$(MOZ_DEB_TIMESTAMP) \ + -DDEB_PKG_VERSION=$(DEB_PKG_VERSION) \ + $(NULL) + +DEBDESTDIR=debian/$(MOZ_APP_NAME) + +PP_DEB_FILES = debian/control \ + debian/changelog \ + debian/$(MOZ_APP_NAME).desktop \ + debian/$(MOZ_APP_NAME).links \ + debian/$(MOZ_APP_NAME).service \ + debian/compat \ + debian/files \ + debian/menu \ + debian/fennec.preinst \ + debian/fennec.prerm \ + debian/fennec.postinst \ + $(NULL) + +ifeq ($(MOZ_PLATFORM_MAEMO),6) +PP_DEB_FILES += debian/fennec.aegis \ + debian/backup \ + debian/restore \ + debian/fennec.conf \ + debian/fennec-cud.sh \ + debian/fennec-rfs.sh \ + debian/fennec.policy \ + $(NULL) +endif + +$(PP_DEB_FILES): + @$(EXIT_ON_ERROR) \ + for f in $(PP_DEB_FILES); do \ + src=$(srcdir)/debian/`basename $$f`.in; \ + echo $$src ">" $$f ;\ + $(RM) -f $$f; \ + mkdir -p debian; \ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $$src > $$f; \ + done + +deb: $(PP_DEB_FILES) $(DIST)/branding/$(MOZ_APP_NAME)_scalable.png \ + $(DIST)/branding/$(MOZ_APP_NAME)_26x26.png \ + $(DIST)/branding/$(MOZ_APP_NAME)_40x40.png + rm -rf $(DEBDESTDIR)/$(installdir)/* + $(NSINSTALL) -D $(DEBDESTDIR)/$(installdir) + cp -pRL $(DIST)/$(MOZ_APP_NAME)/* $(DEBDESTDIR)/$(installdir) +ifeq ($(MOZ_PLATFORM_MAEMO),6) + $(NSINSTALL) debian/$(MOZ_APP_NAME).desktop $(DEBDESTDIR)/usr/share/applications/ + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/dbus-1/services/ + cp debian/$(MOZ_APP_NAME).service $(DEBDESTDIR)/usr/share/dbus-1/services/org.mozilla.$(MOZ_APP_NAME).service + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/themes/blanco/meegotouch/icons/ + cp $(DIST)/branding/$(MOZ_APP_NAME)_scalable.png $(DEBDESTDIR)/usr/share/themes/blanco/meegotouch/icons/$(MOZ_APP_NAME).png + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/backup-framework/applications + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/$(MOZ_APP_NAME) + $(NSINSTALL) -D $(DEBDESTDIR)/etc/osso-cud-scripts + $(NSINSTALL) -D $(DEBDESTDIR)/etc/osso-rfs-scripts + $(NSINSTALL) -m 755 debian/backup $(DEBDESTDIR)/usr/share/$(MOZ_APP_NAME)/ + $(NSINSTALL) -m 755 debian/restore $(DEBDESTDIR)/usr/share/$(MOZ_APP_NAME)/ + cp debian/$(MOZ_APP_NAME).conf $(DEBDESTDIR)/usr/share/backup-framework/applications/$(MOZ_APP_NAME).conf + cp debian/$(MOZ_APP_NAME)-cud.sh $(DEBDESTDIR)/etc/osso-cud-scripts/$(MOZ_APP_NAME)-cud.sh + cp debian/$(MOZ_APP_NAME)-rfs.sh $(DEBDESTDIR)/etc/osso-rfs-scripts/$(MOZ_APP_NAME)-rfs.sh + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/policy/etc/syspart.conf.d + cp debian/$(MOZ_APP_NAME).policy $(DEBDESTDIR)/usr/share/policy/etc/syspart.conf.d/$(MOZ_APP_NAME) +else + $(NSINSTALL) debian/$(MOZ_APP_NAME).desktop $(DEBDESTDIR)/usr/share/applications/hildon/ + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/dbus-1/services/ + cp debian/$(MOZ_APP_NAME).service $(DEBDESTDIR)/usr/share/dbus-1/services/org.mozilla.$(MOZ_APP_NAME).service + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/icons/hicolor/scalable/hildon/ + cp $(DIST)/branding/$(MOZ_APP_NAME)_scalable.png $(DEBDESTDIR)/usr/share/icons/hicolor/scalable/hildon/$(MOZ_APP_NAME).png + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/icons/hicolor/26x26/hildon/ + cp $(DIST)/branding/$(MOZ_APP_NAME)_26x26.png $(DEBDESTDIR)/usr/share/icons/hicolor/26x26/hildon/$(MOZ_APP_NAME).png + $(NSINSTALL) -D $(DEBDESTDIR)/usr/share/icons/hicolor/40x40/hildon/ + cp $(DIST)/branding/$(MOZ_APP_NAME)_40x40.png $(DEBDESTDIR)/usr/share/icons/hicolor/40x40/hildon/$(MOZ_APP_NAME).png +endif + fakeroot dh_link; fakeroot dh_fixperms; fakeroot dh_installdeb; fakeroot dh_shlibdeps; fakeroot dh_gencontrol; fakeroot dh_md5sums; fakeroot dh_builddeb; + +# a defined CONTENTMANAGER implicitly means MOZ_PLATFORM_MAEMO is equals 6 +# in case you use CONTENTMANGER you need to sign your package to gain tracker access. +ifeq ($(MOZ_PLATFORM_MAEMO),6) + if test -e "/usr/bin/aegis-deb-add"; then \ + fakeroot aegis-deb-add -control $(DEBDESTDIR)/DEBIAN/control .. debian/fennec.aegis=_aegis; \ + else \ + echo aegis-builder not found, security signing failed!; \ + fi +endif + + echo $(DEB_PKG_NAME) > $(DIST)/deb_name.txt + +installer: deb + @echo Installer DEB created! + +# relative to $(DIST) +UPLOAD_EXTRA_FILES += ../mobile/$(DEB_PKG_NAME) deb_name.txt +endif diff --git a/mobile/android/installer/debian/backup.in b/mobile/android/installer/debian/backup.in new file mode 100644 index 00000000000..520820e14f2 --- /dev/null +++ b/mobile/android/installer/debian/backup.in @@ -0,0 +1,20 @@ +#filter substitution +#!/bin/sh + +# We do not care about parameters yet + +FENNEC_HOME=$HOME/.mozilla/@MOZ_APP_NAME@ +BACKUP=$HOME/.mozilla/backup + +rm -rf $BACKUP || exit 2 + +# do the backup only if there already is a profile +if [ -d $FENNEC_HOME ]; then + cp -a $FENNEC_HOME $BACKUP || exit 2 + find $BACKUP -name "*.dat" \ + -o -name "*.mfasl" \ + -o -name "Cache" \ + -o -name "OfflineCache" | xargs rm -rf || exit 2 +fi + +exit 0 diff --git a/mobile/android/installer/debian/changelog.in b/mobile/android/installer/debian/changelog.in new file mode 100644 index 00000000000..25f1a359130 --- /dev/null +++ b/mobile/android/installer/debian/changelog.in @@ -0,0 +1,10 @@ +#filter substitution +#ifdef MOZ_OFFICIAL_BRANDING +fennec (@DEB_PKG_VERSION@) stable; urgency=low +#else +fennec (@DEB_PKG_VERSION@) unstable; urgency=low +#endif + + * Mozilla Nightly (Closes: #nnnn) + + -- Mobile Feedback @MOZ_DEB_TIMESTAMP@ diff --git a/mobile/android/installer/debian/compat.in b/mobile/android/installer/debian/compat.in new file mode 100644 index 00000000000..b8626c4cff2 --- /dev/null +++ b/mobile/android/installer/debian/compat.in @@ -0,0 +1 @@ +4 diff --git a/mobile/android/installer/debian/control.in b/mobile/android/installer/debian/control.in new file mode 100644 index 00000000000..bdb40ef8bfb --- /dev/null +++ b/mobile/android/installer/debian/control.in @@ -0,0 +1,19 @@ +#filter substitution +Source: fennec +Section: user/network +Priority: extra +Maintainer: Mobile Feedback +Build-Depends: debhelper (>= 4) +Standards-Version: 3.7.2 + +Package: fennec +Architecture: any +Depends: ${shlibs:Depends} +Description: Web browser built by the Mozilla community + The Firefox Web browser puts you in control of your Web experience with easy navigation, support for add-ons and synchronizes with Firefox on your PC. +XB-Maemo-Display-Name: @MOZ_APP_DISPLAYNAME@ +#if MOZ_PLATFORM_MAEMO == 6 +XB-Maemo-Flags: visible +#endif +XB-Maemo-Icon-26: +#includesubst @ABS_OBJDIR@/@BASE64_ICON@ diff --git a/mobile/android/installer/debian/fennec-cud.sh.in b/mobile/android/installer/debian/fennec-cud.sh.in new file mode 100644 index 00000000000..533d73bc7ef --- /dev/null +++ b/mobile/android/installer/debian/fennec-cud.sh.in @@ -0,0 +1,3 @@ +#filter substitution +#!/bin/sh +rm -rf $HOME/.mozilla/@MOZ_APP_NAME@ diff --git a/mobile/android/installer/debian/fennec-rfs.sh.in b/mobile/android/installer/debian/fennec-rfs.sh.in new file mode 100644 index 00000000000..4e732e6f3ea --- /dev/null +++ b/mobile/android/installer/debian/fennec-rfs.sh.in @@ -0,0 +1,4 @@ +#filter substitution +#!/bin/sh +rm -rf $HOME/.mozilla/@MOZ_APP_NAME@ +gconftool-2 --recursive-unset /apps/@MOZ_APP_NAME@ diff --git a/mobile/android/installer/debian/fennec.aegis.in b/mobile/android/installer/debian/fennec.aegis.in new file mode 100644 index 00000000000..370cd385efe --- /dev/null +++ b/mobile/android/installer/debian/fennec.aegis.in @@ -0,0 +1,11 @@ +#filter substitution + + + + + + + + + + diff --git a/mobile/android/installer/debian/fennec.conf.in b/mobile/android/installer/debian/fennec.conf.in new file mode 100644 index 00000000000..a03dbc8ceaf --- /dev/null +++ b/mobile/android/installer/debian/fennec.conf.in @@ -0,0 +1,21 @@ +#filter substitution + + nokia + @MOZ_APP_NAME@ + backup-scripts + + + + /usr/share/@MOZ_APP_NAME@/backup + + + /usr/share/@MOZ_APP_NAME@/restore + + + + + + $HOME/.mozilla/backup + + + diff --git a/mobile/android/installer/debian/fennec.desktop.in b/mobile/android/installer/debian/fennec.desktop.in new file mode 100644 index 00000000000..ff7e9d67754 --- /dev/null +++ b/mobile/android/installer/debian/fennec.desktop.in @@ -0,0 +1,38 @@ +#filter substitution +[Desktop Entry] +Version=0.1 +Encoding=UTF-8 +Name=@MOZ_APP_DISPLAYNAME@ +Comment=@MOZ_APP_DISPLAYNAME@ mobile browser +StartupWMClass=Navigator +StartupNotify=true +Terminal=false +Type=Application +Categories=Application;Network; +#if MOZ_PLATFORM_MAEMO == 6 +Exec=@installdir@/fennec %U +Icon=/usr/share/themes/blanco/meegotouch/icons/@MOZ_APP_NAME@.png +Categories=X-MeeGo; +OnlyShownIn=X-MeeGo; +MimeType=x-maemo-urischeme/http;x-maemo-urischeme/https;x-maemo-urischeme/ftp;x-maemo-urischeme/file;text/html;x-maemo-highlight/ftp-url;x-maemo-highlight/http-url; +#else +Exec=@installdir@/fennec +Icon=@MOZ_APP_NAME@ +X-Icon-Path=/usr/share/icons +X-Window-Icon=@MOZ_APP_NAME@ +X-Window-Icon-dimmed=@MOZ_APP_NAME@ +X-Osso-Service=mozilla.@MOZ_APP_NAME@ +MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/vnd.mozilla.xul+xml;application/rss+xml;application/rdf+xml;image/gif;image/jpeg;image/png; +#endif +X-Osso-Type=application/x-executable + +[X-Osso-URI-Actions] +http=X-Osso-URI-Action-Open +https=X-Osso-URI-Action-Open +ftp=X-Osso-URI-Action-Open +file=X-Osso-URI-Action-Open + +[X-Osso-URI-Action-Open] +Method=load_url +Name=uri_link_open_link +TranslationDomain=osso-uri diff --git a/mobile/android/installer/debian/fennec.links.in b/mobile/android/installer/debian/fennec.links.in new file mode 100644 index 00000000000..3b91bd5fc3d --- /dev/null +++ b/mobile/android/installer/debian/fennec.links.in @@ -0,0 +1,5 @@ +#filter substitution +@installdir@/fennec /usr/bin/fennec +/usr/share/applications/hildon/fennec.desktop etc/others-menu/0112_fennec.desktop + + diff --git a/mobile/android/installer/debian/fennec.policy.in b/mobile/android/installer/debian/fennec.policy.in new file mode 100644 index 00000000000..98912d51881 --- /dev/null +++ b/mobile/android/installer/debian/fennec.policy.in @@ -0,0 +1,4 @@ +#filter substitution +[classify browser] +@installdir@/@MOZ_APP_NAME@ +@installdir@/plugin-container diff --git a/mobile/android/installer/debian/fennec.postinst.in b/mobile/android/installer/debian/fennec.postinst.in new file mode 100644 index 00000000000..99e301719b3 --- /dev/null +++ b/mobile/android/installer/debian/fennec.postinst.in @@ -0,0 +1,37 @@ +#filter substitution +#literal #! /bin/sh +# postinst script for fennec +# +# see: dh_installdeb(1) + +set -e + +case "$1" in + configure) + # for faster initial startup +#ifdef MOZ_PLATFORM_MAEMO + /bin/su -l user -c "/usr/bin/fennec -silent" > /dev/null 2>&1 || echo -n "" +#endif +#if MOZ_PLATFORM_MAEMO == 5 + # for fennec icons + gtk-update-icon-cache -f /usr/share/icons/hicolor +#endif + # select where to install fennec menu + if [ "$2" == "" ]; then + + if [ -x /usr/bin/update-desktop-database ]; then + update-desktop-database /usr/share/applications + fi + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/mobile/android/installer/debian/fennec.preinst.in b/mobile/android/installer/debian/fennec.preinst.in new file mode 100644 index 00000000000..446c6b5eef5 --- /dev/null +++ b/mobile/android/installer/debian/fennec.preinst.in @@ -0,0 +1,26 @@ +#literal #! /bin/sh + +set -e + +RUNNING=`ps | grep "fennec.*/fennec" | grep -v grep | wc -l` + +if [ $RUNNING -gt 0 ]; +then + dbus-send --system --type=method_call --dest=mozilla.fennec /mozilla/fennec/request mozilla.fennec.quit + x=0 + while [ $x -lt 10 ] + do + sleep 1 + RUNNING=`ps | grep "fennec.*/fennec" | grep -v grep | wc -l` + + if [ $RUNNING -eq 0 ]; + then + break + fi + + x=`expr $x + 1` + done + + pkill -9 fennec + sleep 1 +fi diff --git a/mobile/android/installer/debian/fennec.prerm.in b/mobile/android/installer/debian/fennec.prerm.in new file mode 100644 index 00000000000..446c6b5eef5 --- /dev/null +++ b/mobile/android/installer/debian/fennec.prerm.in @@ -0,0 +1,26 @@ +#literal #! /bin/sh + +set -e + +RUNNING=`ps | grep "fennec.*/fennec" | grep -v grep | wc -l` + +if [ $RUNNING -gt 0 ]; +then + dbus-send --system --type=method_call --dest=mozilla.fennec /mozilla/fennec/request mozilla.fennec.quit + x=0 + while [ $x -lt 10 ] + do + sleep 1 + RUNNING=`ps | grep "fennec.*/fennec" | grep -v grep | wc -l` + + if [ $RUNNING -eq 0 ]; + then + break + fi + + x=`expr $x + 1` + done + + pkill -9 fennec + sleep 1 +fi diff --git a/mobile/android/installer/debian/fennec.service.in b/mobile/android/installer/debian/fennec.service.in new file mode 100644 index 00000000000..ca6bb3df2da --- /dev/null +++ b/mobile/android/installer/debian/fennec.service.in @@ -0,0 +1,5 @@ +#filter substitution +[D-BUS Service] +Name=mozilla.@MOZ_APP_NAME@ +Exec=@installdir@/fennec + diff --git a/mobile/android/installer/debian/files.in b/mobile/android/installer/debian/files.in new file mode 100644 index 00000000000..fa287b5b43d --- /dev/null +++ b/mobile/android/installer/debian/files.in @@ -0,0 +1,2 @@ +#filter substitution +@MOZ_APP_NAME@_@DEB_PKG_VERSION@_armel.deb user/network extra diff --git a/mobile/android/installer/debian/menu.in b/mobile/android/installer/debian/menu.in new file mode 100644 index 00000000000..391ecc69904 --- /dev/null +++ b/mobile/android/installer/debian/menu.in @@ -0,0 +1,2 @@ +?package(fennec):needs="X11|text|vc|wm" section="Apps/Internet"\ + title="fennec" command="/usr/bin/fennec" diff --git a/mobile/android/installer/debian/restore.in b/mobile/android/installer/debian/restore.in new file mode 100644 index 00000000000..baf0a03faa4 --- /dev/null +++ b/mobile/android/installer/debian/restore.in @@ -0,0 +1,15 @@ +#filter substitution +#!/bin/sh + +# We do not care about parameters yet + +FENNEC_HOME=$HOME/.mozilla/@MOZ_APP_NAME@ +BACKUP=$HOME/.mozilla/backup + +rm -rf $FENNEC_HOME || exit 2 + +# Fennec profile +cp -a $BACKUP $FENNEC_HOME || exit 2 + +exit 0 + diff --git a/mobile/android/installer/mobile-l10n.js b/mobile/android/installer/mobile-l10n.js new file mode 100644 index 00000000000..1835f1ded11 --- /dev/null +++ b/mobile/android/installer/mobile-l10n.js @@ -0,0 +1,2 @@ +// Inherit locale from the OS, used for multi-locale builds +pref("intl.locale.matchOS", true); diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in new file mode 100644 index 00000000000..e19c8a4e04c --- /dev/null +++ b/mobile/android/installer/package-manifest.in @@ -0,0 +1,620 @@ +; Package file for the Fennec build. +; +; File format: +; +; [] designates a toplevel component. Example: [xpcom] +; - in front of a file specifies it to be removed from the destination +; * wildcard support to recursively copy the entire directory +; ; file comment +; + +#filter substitution + +#ifdef XP_MACOSX +; Mac bundle stuff +@APPNAME@/Contents/Info.plist +@APPNAME@/Contents/PkgInfo +@APPNAME@/Contents/Plug-Ins/ +@APPNAME@/Contents/Resources/ +#endif + +[@AB_CD@] +@BINPATH@/chrome/@AB_CD@@JAREXT@ +@BINPATH@/chrome/@AB_CD@.manifest +@BINPATH@/@PREF_DIR@/mobile-l10n.js +@BINPATH@/searchplugins/* +@BINPATH@/defaults/profile/bookmarks.html +@BINPATH@/defaults/profile/localstore.rdf +@BINPATH@/defaults/profile/mimeTypes.rdf +@BINPATH@/defaults/profile/chrome/* +#ifdef MOZ_UPDATER +@BINPATH@/update.locale +@BINPATH@/updater.ini +#endif +@BINPATH@/dictionaries/* +@BINPATH@/hyphenation/* +#ifdef XP_WIN32 +@BINPATH@/uninstall/helper.exe +#endif + +[xpcom] +@BINPATH@/dependentlibs.list +#ifndef MOZ_STATIC_JS +@BINPATH@/@DLL_PREFIX@mozjs@DLL_SUFFIX@ +#endif +@BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@xpcom@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@mozutils@DLL_SUFFIX@ +#ifdef XP_MACOSX +@BINPATH@/XUL +#else +@BINPATH@/@DLL_PREFIX@xul@DLL_SUFFIX@ +#endif +#ifdef XP_MACOSX +@BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/ +#else +@BINPATH@/@MOZ_CHILD_PROCESS_NAME@ +#endif +#ifdef XP_WIN32 +#if _MSC_VER == 1400 +@BINPATH@/Microsoft.VC80.CRT.manifest +@BINPATH@/msvcm80.dll +@BINPATH@/msvcp80.dll +@BINPATH@/msvcr80.dll +#elif _MSC_VER == 1500 +@BINPATH@/Microsoft.VC90.CRT.manifest +@BINPATH@/msvcm90.dll +@BINPATH@/msvcp90.dll +@BINPATH@/msvcr90.dll +#elif _MSC_VER == 1600 +@BINPATH@/msvcp100.dll +@BINPATH@/msvcr100.dll +#elif _MSC_VER == 1700 +@BINPATH@/msvcp110.dll +@BINPATH@/msvcr110.dll +#endif + +#endif + +#ifdef ANDROID +@BINPATH@/AndroidManifest.xml +@BINPATH@/resources.arsc +@BINPATH@/package-name.txt +@BINPATH@/classes.dex +@BINPATH@/@DLL_PREFIX@mozutils@DLL_SUFFIX@ +@BINPATH@/res/drawable +@BINPATH@/res/drawable-hdpi +@BINPATH@/res/layout +#endif + +#ifdef MOZ_PLATFORM_MAEMO +@BINPATH@/res/drawable +#endif + +[browser] +; [Base Browser Files] +#ifndef XP_UNIX +@BINPATH@/@MOZ_APP_NAME@.exe +#else +@BINPATH@/@MOZ_APP_NAME@-bin +@BINPATH@/@MOZ_APP_NAME@ +#endif +@BINPATH@/application.ini +@BINPATH@/platform.ini +#ifndef XP_OS2 +@BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@ +#else +@BINPATH@/mozsqlt3@DLL_SUFFIX@ +#endif +@BINPATH@/blocklist.xml +#ifdef XP_UNIX +@BINPATH@/run-mozilla.sh +#ifndef XP_MACOSX +@BINPATH@/mozilla-xremote-client +#endif +#endif + +; [Components] +@BINPATH@/components/components.manifest +@BINPATH@/components/alerts.xpt +#ifdef ACCESSIBILITY +#ifdef XP_WIN32 +@BINPATH@/AccessibleMarshal.dll +@BINPATH@/components/accessibility-msaa.xpt +#endif +@BINPATH@/components/accessibility.xpt +#endif +@BINPATH@/components/appshell.xpt +@BINPATH@/components/appstartup.xpt +@BINPATH@/components/autocomplete.xpt +@BINPATH@/components/autoconfig.xpt +@BINPATH@/components/browsercompsbase.xpt +@BINPATH@/components/browser-feeds.xpt +@BINPATH@/components/caps.xpt +@BINPATH@/components/chardet.xpt +@BINPATH@/components/chrome.xpt +@BINPATH@/components/commandhandler.xpt +@BINPATH@/components/commandlines.xpt +@BINPATH@/components/composer.xpt +@BINPATH@/components/content_base.xpt +@BINPATH@/components/content_events.xpt +@BINPATH@/components/content_canvas.xpt +@BINPATH@/components/content_htmldoc.xpt +@BINPATH@/components/content_html.xpt +@BINPATH@/components/content_xslt.xpt +@BINPATH@/components/content_xtf.xpt +@BINPATH@/components/cookie.xpt +@BINPATH@/components/directory.xpt +@BINPATH@/components/docshell.xpt +@BINPATH@/components/dom.xpt +@BINPATH@/components/dom_base.xpt +@BINPATH@/components/dom_battery.xpt +@BINPATH@/components/dom_canvas.xpt +@BINPATH@/components/dom_core.xpt +@BINPATH@/components/dom_css.xpt +@BINPATH@/components/dom_events.xpt +@BINPATH@/components/dom_geolocation.xpt +@BINPATH@/components/dom_notification.xpt +@BINPATH@/components/dom_html.xpt +@BINPATH@/components/dom_indexeddb.xpt +@BINPATH@/components/dom_offline.xpt +@BINPATH@/components/dom_json.xpt +@BINPATH@/components/dom_range.xpt +@BINPATH@/components/dom_sidebar.xpt +@BINPATH@/components/dom_storage.xpt +@BINPATH@/components/dom_stylesheets.xpt +@BINPATH@/components/dom_threads.xpt +@BINPATH@/components/dom_traversal.xpt +@BINPATH@/components/dom_views.xpt +@BINPATH@/components/dom_xbl.xpt +@BINPATH@/components/dom_xpath.xpt +@BINPATH@/components/dom_xul.xpt +@BINPATH@/components/dom_loadsave.xpt +@BINPATH@/components/downloads.xpt +@BINPATH@/components/editor.xpt +@BINPATH@/components/embed_base.xpt +@BINPATH@/components/extensions.xpt +@BINPATH@/components/exthandler.xpt +@BINPATH@/components/exthelper.xpt +@BINPATH@/components/fastfind.xpt +@BINPATH@/components/feeds.xpt +#ifdef MOZ_GTK2 +@BINPATH@/components/filepicker.xpt +#endif +@BINPATH@/components/find.xpt +@BINPATH@/components/fuel.xpt +@BINPATH@/components/gfx.xpt +@BINPATH@/components/htmlparser.xpt +@BINPATH@/components/imglib2.xpt +@BINPATH@/components/imgicon.xpt +@BINPATH@/components/inspector.xpt +@BINPATH@/components/intl.xpt +@BINPATH@/components/jar.xpt +@BINPATH@/components/jetpack.xpt +@BINPATH@/components/jsdservice.xpt +@BINPATH@/components/layout_base.xpt +@BINPATH@/components/layout_forms.xpt +#ifdef NS_PRINTING +@BINPATH@/components/layout_printing.xpt +#endif +@BINPATH@/components/layout_xul_tree.xpt +@BINPATH@/components/layout_xul.xpt +@BINPATH@/components/locale.xpt +@BINPATH@/components/lwbrk.xpt +@BINPATH@/components/migration.xpt +@BINPATH@/components/mimetype.xpt +@BINPATH@/components/mozfind.xpt +@BINPATH@/components/necko_about.xpt +@BINPATH@/components/necko_cache.xpt +@BINPATH@/components/necko_cookie.xpt +@BINPATH@/components/necko_dns.xpt +@BINPATH@/components/necko_file.xpt +@BINPATH@/components/necko_ftp.xpt +@BINPATH@/components/necko_http.xpt +@BINPATH@/components/necko_res.xpt +@BINPATH@/components/necko_socket.xpt +@BINPATH@/components/necko_strconv.xpt +@BINPATH@/components/necko_viewsource.xpt +@BINPATH@/components/necko_wifi.xpt +@BINPATH@/components/necko_wyciwyg.xpt +@BINPATH@/components/necko.xpt +@BINPATH@/components/loginmgr.xpt +@BINPATH@/components/parentalcontrols.xpt +@BINPATH@/components/places.xpt +@BINPATH@/components/plugin.xpt +@BINPATH@/components/pref.xpt +@BINPATH@/components/prefetch.xpt +@BINPATH@/components/profile.xpt +@BINPATH@/components/proxyObject.xpt +@BINPATH@/components/rdf.xpt +@BINPATH@/components/satchel.xpt +@BINPATH@/components/saxparser.xpt +@BINPATH@/components/sessionstore.xpt +#ifdef MOZ_SERVICES_SYNC +@BINPATH@/components/services-crypto.xpt +#endif +@BINPATH@/components/services-crypto-component.xpt +@BINPATH@/components/shellservice.xpt +@BINPATH@/components/shistory.xpt +@BINPATH@/components/spellchecker.xpt +@BINPATH@/components/storage.xpt +@BINPATH@/components/telemetry.xpt +@BINPATH@/components/toolkitprofile.xpt +#ifdef MOZ_ENABLE_XREMOTE +@BINPATH@/components/toolkitremote.xpt +#endif +@BINPATH@/components/txtsvc.xpt +@BINPATH@/components/txmgr.xpt +@BINPATH@/components/uconv.xpt +@BINPATH@/components/unicharutil.xpt +#ifdef MOZ_UPDATER +@BINPATH@/components/update.xpt +#endif +@BINPATH@/components/uriloader.xpt +@BINPATH@/components/urlformatter.xpt +@BINPATH@/components/webBrowser_core.xpt +@BINPATH@/components/webbrowserpersist.xpt +@BINPATH@/components/webshell_idls.xpt +@BINPATH@/components/widget.xpt +#ifdef XP_MACOSX +@BINPATH@/components/widget_cocoa.xpt +#endif +#ifdef ANDROID +@BINPATH@/components/widget_android.xpt +#endif +@BINPATH@/components/windowds.xpt +@BINPATH@/components/windowwatcher.xpt +@BINPATH@/components/xpcom_base.xpt +@BINPATH@/components/xpcom_system.xpt +@BINPATH@/components/xpcom_components.xpt +@BINPATH@/components/xpcom_ds.xpt +@BINPATH@/components/xpcom_io.xpt +@BINPATH@/components/xpcom_threads.xpt +@BINPATH@/components/xpcom_xpti.xpt +@BINPATH@/components/xpconnect.xpt +@BINPATH@/components/xulapp.xpt +@BINPATH@/components/xul.xpt +@BINPATH@/components/xuldoc.xpt +@BINPATH@/components/xultmpl.xpt +@BINPATH@/components/zipwriter.xpt +@BINPATH@/components/openwebapps.xpt + +; JavaScript components +@BINPATH@/components/ConsoleAPI.manifest +@BINPATH@/components/ConsoleAPI.js +@BINPATH@/components/FeedProcessor.manifest +@BINPATH@/components/FeedProcessor.js +@BINPATH@/components/BrowserFeeds.manifest +@BINPATH@/components/FeedConverter.js +@BINPATH@/components/FeedWriter.js +@BINPATH@/components/fuelApplication.manifest +@BINPATH@/components/fuelApplication.js +@BINPATH@/components/WebContentConverter.js +@BINPATH@/components/BrowserComponents.manifest +@BINPATH@/components/nsBrowserContentHandler.js +@BINPATH@/components/nsBrowserGlue.js +@BINPATH@/components/nsSetDefaultBrowser.manifest +@BINPATH@/components/nsSetDefaultBrowser.js +@BINPATH@/components/BrowserPlaces.manifest +@BINPATH@/components/nsPrivateBrowsingService.manifest +@BINPATH@/components/nsPrivateBrowsingService.js +@BINPATH@/components/toolkitsearch.manifest +@BINPATH@/components/nsSearchService.js +@BINPATH@/components/nsSearchSuggestions.js +@BINPATH@/components/passwordmgr.manifest +@BINPATH@/components/nsLoginInfo.js +@BINPATH@/components/nsLoginManager.js +@BINPATH@/components/nsLoginManagerPrompter.js +@BINPATH@/components/storage-Legacy.js +@BINPATH@/components/storage-mozStorage.js +@BINPATH@/components/crypto-SDR.js +@BINPATH@/components/jsconsole-clhandler.manifest +@BINPATH@/components/jsconsole-clhandler.js +#ifdef MOZ_GTK2 +@BINPATH@/components/nsFilePicker.manifest +@BINPATH@/components/nsFilePicker.js +#endif +@BINPATH@/components/nsHelperAppDlg.manifest +@BINPATH@/components/nsHelperAppDlg.js +@BINPATH@/components/nsDownloadManagerUI.manifest +@BINPATH@/components/nsDownloadManagerUI.js +@BINPATH@/components/nsProxyAutoConfig.manifest +@BINPATH@/components/nsProxyAutoConfig.js +@BINPATH@/components/NetworkGeolocationProvider.manifest +@BINPATH@/components/NetworkGeolocationProvider.js +@BINPATH@/components/GPSDGeolocationProvider.manifest +@BINPATH@/components/GPSDGeolocationProvider.js +@BINPATH@/components/nsSidebar.manifest +@BINPATH@/components/nsSidebar.js +@BINPATH@/components/extensions.manifest +@BINPATH@/components/addonManager.js +@BINPATH@/components/amContentHandler.js +@BINPATH@/components/amWebInstallListener.js +@BINPATH@/components/nsBlocklistService.js +@BINPATH@/components/OpenWebapps.manifest + +#ifdef MOZ_UPDATER +@BINPATH@/components/nsUpdateService.manifest +@BINPATH@/components/nsUpdateService.js +@BINPATH@/components/nsUpdateServiceStub.js +#endif +@BINPATH@/components/nsUpdateTimerManager.manifest +@BINPATH@/components/nsUpdateTimerManager.js +@BINPATH@/components/pluginGlue.manifest +@BINPATH@/components/nsSessionStore.manifest +@BINPATH@/components/nsSessionStartup.js +@BINPATH@/components/nsSessionStore.js +@BINPATH@/components/nsURLFormatter.manifest +@BINPATH@/components/nsURLFormatter.js +#ifndef XP_OS2 +@BINPATH@/components/@DLL_PREFIX@browsercomps@DLL_SUFFIX@ +#else +@BINPATH@/components/brwsrcmp@DLL_SUFFIX@ +#endif +@BINPATH@/components/txEXSLTRegExFunctions.manifest +@BINPATH@/components/txEXSLTRegExFunctions.js +@BINPATH@/components/toolkitplaces.manifest +@BINPATH@/components/nsLivemarkService.js +@BINPATH@/components/nsTaggingService.js +@BINPATH@/components/nsPlacesDBFlush.js +@BINPATH@/components/nsPlacesAutoComplete.manifest +@BINPATH@/components/nsPlacesAutoComplete.js +@BINPATH@/components/nsPlacesExpiration.js +@BINPATH@/components/PlacesProtocolHandler.js +@BINPATH@/components/PlacesCategoriesStarter.js +@BINPATH@/components/nsDefaultCLH.manifest +@BINPATH@/components/nsDefaultCLH.js +@BINPATH@/components/nsContentPrefService.manifest +@BINPATH@/components/nsContentPrefService.js +@BINPATH@/components/nsContentDispatchChooser.manifest +@BINPATH@/components/nsContentDispatchChooser.js +@BINPATH@/components/nsHandlerService.manifest +@BINPATH@/components/nsHandlerService.js +@BINPATH@/components/nsWebHandlerApp.manifest +@BINPATH@/components/nsWebHandlerApp.js +@BINPATH@/components/nsBadCertHandler.manifest +@BINPATH@/components/nsBadCertHandler.js +@BINPATH@/components/satchel.manifest +@BINPATH@/components/nsFormAutoComplete.js +@BINPATH@/components/nsFormHistory.js +@BINPATH@/components/nsInputListAutoComplete.js +@BINPATH@/components/contentSecurityPolicy.manifest +@BINPATH@/components/contentSecurityPolicy.js +@BINPATH@/components/contentAreaDropListener.manifest +@BINPATH@/components/contentAreaDropListener.js +@BINPATH@/components/messageWakeupService.js +@BINPATH@/components/messageWakeupService.manifest +@BINPATH@/components/nsFilePicker.js +@BINPATH@/components/nsFilePicker.manifest +#ifdef XP_MACOSX +@BINPATH@/components/libalerts_s.dylib +#endif +#ifdef MOZ_ENABLE_DBUS +@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@ +#endif +@BINPATH@/components/nsINIProcessor.manifest +@BINPATH@/components/nsINIProcessor.js +@BINPATH@/components/nsPrompter.manifest +@BINPATH@/components/nsPrompter.js +#ifdef MOZ_SERVICES_SYNC +@BINPATH@/components/SyncComponents.manifest +@BINPATH@/components/Weave.js +@BINPATH@/components/WeaveCrypto.manifest +@BINPATH@/components/WeaveCrypto.js +#endif +@BINPATH@/components/TelemetryPing.js +@BINPATH@/components/TelemetryPing.manifest + +; Modules +@BINPATH@/modules/* + +; Safe Browsing +@BINPATH@/components/nsURLClassifier.manifest +@BINPATH@/components/nsUrlClassifierHashCompleter.js +@BINPATH@/components/nsUrlClassifierListManager.js +@BINPATH@/components/nsUrlClassifierLib.js +@BINPATH@/components/url-classifier.xpt + +; GNOME hooks +#ifdef MOZ_ENABLE_GNOME_COMPONENT +@BINPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@ +#endif + +; ANGLE on Win32 +#ifdef XP_WIN32 +#ifndef HAVE_64BIT_OS +@BINPATH@/libEGL.dll +@BINPATH@/libGLESv2.dll +#endif +#endif + +; [Browser Chrome Files] +@BINPATH@/chrome/browser@JAREXT@ +@BINPATH@/chrome/browser.manifest +@BINPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf +@BINPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/icon.png +@BINPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/preview.png +#if MOZ_UPDATE_CHANNEL == beta +@BINPATH@/extensions/testpilot@labs.mozilla.com/* +#endif +@BINPATH@/chrome/toolkit@JAREXT@ +@BINPATH@/chrome/toolkit.manifest +#ifdef XP_UNIX +#ifndef XP_MACOSX +@BINPATH@/chrome/icons/default/default16.png +@BINPATH@/chrome/icons/default/default32.png +@BINPATH@/chrome/icons/default/default48.png +#endif +#endif + + +; shell icons +#ifdef XP_UNIX +#ifndef XP_MACOSX +@BINPATH@/icons/*.xpm +@BINPATH@/icons/*.png +#endif +#endif + +; [Default Preferences] +; All the pref files must be part of base to prevent migration bugs +@BINPATH@/@PREF_DIR@/mobile.js +@BINPATH@/@PREF_DIR@/mobile-branding.js +@BINPATH@/@PREF_DIR@/channel-prefs.js +#ifdef MOZ_SERVICES_SYNC +@BINPATH@/@PREF_DIR@/services-sync.js +#endif +@BINPATH@/greprefs.js +@BINPATH@/defaults/autoconfig/platform.js +@BINPATH@/defaults/autoconfig/prefcalls.js +@BINPATH@/defaults/profile/prefs.js + +; [Layout Engine Resources] +; Style Sheets, Graphics and other Resources used by the layout engine. +@BINPATH@/res/EditorOverride.css +@BINPATH@/res/contenteditable.css +@BINPATH@/res/designmode.css +@BINPATH@/res/table-add-column-after-active.gif +@BINPATH@/res/table-add-column-after-hover.gif +@BINPATH@/res/table-add-column-after.gif +@BINPATH@/res/table-add-column-before-active.gif +@BINPATH@/res/table-add-column-before-hover.gif +@BINPATH@/res/table-add-column-before.gif +@BINPATH@/res/table-add-row-after-active.gif +@BINPATH@/res/table-add-row-after-hover.gif +@BINPATH@/res/table-add-row-after.gif +@BINPATH@/res/table-add-row-before-active.gif +@BINPATH@/res/table-add-row-before-hover.gif +@BINPATH@/res/table-add-row-before.gif +@BINPATH@/res/table-remove-column-active.gif +@BINPATH@/res/table-remove-column-hover.gif +@BINPATH@/res/table-remove-column.gif +@BINPATH@/res/table-remove-row-active.gif +@BINPATH@/res/table-remove-row-hover.gif +@BINPATH@/res/table-remove-row.gif +@BINPATH@/res/grabber.gif +#ifdef XP_MACOSX +@BINPATH@/res/cursors/* +#endif +@BINPATH@/res/fonts/* +@BINPATH@/res/dtd/* +@BINPATH@/res/html/* +@BINPATH@/res/langGroups.properties +@BINPATH@/res/language.properties +@BINPATH@/res/entityTables/* +#ifdef XP_MACOSX +@BINPATH@/res/MainMenu.nib/ +#endif + +; svg +@BINPATH@/res/svg.css +@BINPATH@/components/dom_svg.xpt +@BINPATH@/components/dom_smil.xpt + +; [Personal Security Manager] +; +@BINPATH@/@DLL_PREFIX@nssckbi@DLL_SUFFIX@ +@BINPATH@/components/pipboot.xpt +@BINPATH@/components/pipnss.xpt +@BINPATH@/components/pippki.xpt +@BINPATH@/@DLL_PREFIX@nss3@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@nssutil3@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@smime3@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@softokn3@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@freebl3@DLL_SUFFIX@ +@BINPATH@/@DLL_PREFIX@ssl3@DLL_SUFFIX@ +#ifndef CROSS_COMPILE +@BINPATH@/@DLL_PREFIX@freebl3.chk +@BINPATH@/@DLL_PREFIX@softokn3.chk +#endif +#ifndef NSS_DISABLE_DBM +@BINPATH@/@DLL_PREFIX@nssdbm3@DLL_SUFFIX@ +#ifndef CROSS_COMPILE +@BINPATH@/@DLL_PREFIX@nssdbm3.chk +#endif +#endif +@BINPATH@/chrome/pippki@JAREXT@ +@BINPATH@/chrome/pippki.manifest + +; for Solaris SPARC +#ifdef SOLARIS +bin/libfreebl_32fpu_3.chk +bin/libfreebl_32fpu_3.so +bin/libfreebl_32int_3.chk +bin/libfreebl_32int_3.so +bin/libfreebl_32int64_3.chk +bin/libfreebl_32int64_3.so +#endif + +; [Updater] +; +#ifdef MOZ_UPDATER +#ifdef XP_MACOSX +@BINPATH@/updater.app/ +#else +@BINPATH@/updater@BIN_SUFFIX@ +#endif +#endif + +; [Crash Reporter] +; +#ifdef MOZ_CRASHREPORTER +#ifdef XP_MACOSX +@BINPATH@/crashreporter.app/ +#else +@BINPATH@/crashreporter@BIN_SUFFIX@ +@BINPATH@/crashreporter.crt +@BINPATH@/crashreporter.ini +#ifdef XP_UNIX +@BINPATH@/Throbber-small.gif +#endif +#endif +@BINPATH@/crashreporter-override.ini +#endif + +; [Extensions] +; +#ifdef MOZ_ENABLE_GNOMEVFS +bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@ +#endif + +; [OS/2] +#ifdef XP_OS2 +@BINPATH@/MozSounds.cmd +#endif + +[mobile] +@BINPATH@/chrome/icons/ +@BINPATH@/chrome/chrome@JAREXT@ +@BINPATH@/chrome/chrome.manifest +@BINPATH@/components/AboutRedirector.js +@BINPATH@/components/AddonUpdateService.js +@BINPATH@/components/AlertsService.js +@BINPATH@/components/BlocklistPrompt.js +@BINPATH@/components/BrowserCLH.js +@BINPATH@/components/ContentDispatchChooser.js +@BINPATH@/components/ContentPermissionPrompt.js +@BINPATH@/components/DirectoryProvider.js +@BINPATH@/components/DownloadManagerUI.js +@BINPATH@/components/FormAutoComplete.js +@BINPATH@/components/HelperAppDialog.js +@BINPATH@/components/LoginManagerPrompter.js +@BINPATH@/components/MobileComponents.manifest +@BINPATH@/components/MobileComponents.xpt +@BINPATH@/components/PromptService.js +; disabled (bug 696203) @BINPATH@/components/SessionStore.js +@BINPATH@/components/Sidebar.js +@BINPATH@/components/OpenWebapps.js +#ifdef MOZ_SAFE_BROWSING +@BINPATH@/components/SafeBrowsing.js +#endif +#ifdef MOZ_UPDATER +@BINPATH@/components/UpdatePrompt.js +#endif +@BINPATH@/components/XPIDialogService.js +@BINPATH@/components/CapturePicker.js +@BINPATH@/components/browsercomps.xpt +@BINPATH@/extensions/feedback@mobile.mozilla.org.xpi diff --git a/mobile/android/installer/removed-files.in b/mobile/android/installer/removed-files.in new file mode 100644 index 00000000000..a6a3226c069 --- /dev/null +++ b/mobile/android/installer/removed-files.in @@ -0,0 +1,30 @@ +update.locale +README.txt +components/nsTryToClose.js +#if MOZ_UPDATE_CHANNEL != beta +extensions/feedback@mobile.mozilla.org.xpi +#endif +#ifdef XP_WIN + #if _MSC_VER != 1400 + @BINPATH@/Microsoft.VC80.CRT.manifest + @BINPATH@/msvcm80.dll + @BINPATH@/msvcp80.dll + @BINPATH@/msvcr80.dll + #endif + #if _MSC_VER != 1500 + @BINPATH@/Microsoft.VC90.CRT.manifest + @BINPATH@/msvcm90.dll + @BINPATH@/msvcp90.dll + @BINPATH@/msvcr90.dll + #endif + #if _MSC_VER != 1600 + @BINPATH@/msvcp100.dll + @BINPATH@/msvcr100.dll + #endif + #if _MSC_VER != 1700 + @BINPATH@/msvcp110.dll + @BINPATH@/msvcr110.dll + #endif + mozcrt19.dll + mozcpp19.dll +#endif diff --git a/mobile/android/locales/Makefile.in b/mobile/android/locales/Makefile.in new file mode 100644 index 00000000000..a8f1d0d8a38 --- /dev/null +++ b/mobile/android/locales/Makefile.in @@ -0,0 +1,249 @@ +# ***** 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 . +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Finkle +# Axel Hecht +# +# 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@ +relativesrcdir = mobile/android/locales + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/config.mk + +ifdef LOCALE_MERGEDIR +vpath book%.inc $(LOCALE_MERGEDIR)/mobile/android/profile +endif +vpath book%.inc $(LOCALE_SRCDIR)/profile +ifdef LOCALE_MERGEDIR +vpath book%.inc @srcdir@/en-US/profile +endif + +ifdef LOCALE_MERGEDIR +vpath crashreporter%.ini $(LOCALE_MERGEDIR)/mobile/android/crashreporter +endif +vpath crashreporter%.ini $(LOCALE_SRCDIR)/crashreporter +ifdef LOCALE_MERGEDIR +vpath crashreporter%.ini @srcdir@/en-US/crashreporter +endif + +SUBMAKEFILES += \ + $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/Makefile \ + $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales/Makefile \ + $(NULL) + +MOZ_LANGPACK_EID=langpack-$(AB_CD)@firefox-mobile.mozilla.org +PREF_JS_EXPORTS = $(firstword $(wildcard $(LOCALE_SRCDIR)/mobile-l10n.js) \ + @srcdir@/en-US/mobile-l10n.js ) + +# Shouldn't := DEB_BUILD_ARCH despite the $(shell ) as deb isn't everywhere +DEB_BUILD_ARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH) +DATASTAGE = $(CURDIR)/data-stage + +SEARCH_PLUGINS = $(shell cat \ + $(firstword $(wildcard $(LOCALE_SRCDIR)/searchplugins/list.txt) \ + @srcdir@/en-US/searchplugins/list.txt ) ) + +tmp-search.jar.mn:: + printf "$(AB_CD).jar:" > $@ + printf "$(foreach plugin,$(SEARCH_PLUGINS),$(subst __PLUGIN_SUBST__,$(plugin), \n locale/$(AB_CD)/browser/searchplugins/__PLUGIN_SUBST__.xml (__PLUGIN_SUBST__.xml)))" >> $@ + @echo >> $@ + +searchplugins: tmp-search.jar.mn + $(PYTHON) $(MOZILLA_DIR)/config/JarMaker.py \ + $(QUIET) -j $(FINAL_TARGET)/chrome \ + -s $(topsrcdir)/$(relativesrcdir)/en-US/searchplugins \ + -s $(LOCALE_SRCDIR)/searchplugins \ + $(MAKE_JARS_FLAGS) tmp-search.jar.mn + +export:: searchplugins + +GARBAGE += tmp-search.jar.mn + +include $(topsrcdir)/config/rules.mk + +include $(topsrcdir)/toolkit/locales/l10n.mk + +clobber-zip: + $(RM) $(STAGEDIST)/chrome/$(AB_CD).jar \ + $(STAGEDIST)/chrome/$(AB_CD).manifest \ + $(STAGEDIST)/defaults/preferences/mobile-l10n.js + $(RM) -r $(STAGEDIST)/dictionaries \ + $(STAGEDIST)/hyphenation \ + $(STAGEDIST)/defaults/profile \ + $(STAGEDIST)/chrome/$(AB_CD) + +libs-%: + $(NSINSTALL) -D $(DIST)/install + @$(MAKE) -C ../../toolkit/locales libs-$* BOTH_MANIFESTS=1 + @$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$* BOTH_MANIFESTS=1 + @$(MAKE) -C ../../intl/locales AB_CD=$* XPI_NAME=locale-$* BOTH_MANIFESTS=1 + @$(MAKE) -B bookmarks.json AB_CD=$* + @$(MAKE) -B searchplugins AB_CD=$* XPI_NAME=locale-$* + @$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=defaults/preferences BOTH_MANIFESTS=1 + @$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$* BOTH_MANIFESTS=1 + +# Tailored target to just add the chrome processing for multi-locale builds +chrome-%: + @$(MAKE) -C $(DEPTH)/toolkit/locales chrome-$* + @$(MAKE) -C $(DEPTH)/services/sync/locales chrome AB_CD=$* + @$(MAKE) -B bookmarks.json AB_CD=$* + @$(MAKE) -B searchplugins AB_CD=$* + @$(MAKE) chrome AB_CD=$* + @$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales chrome AB_CD=$* +ifeq ($(OS_TARGET),Android) + @$(MAKE) -C $(DEPTH)/mobile/android/base chrome AB_CD=$* +endif + +# This is a generic target that will make a langpack and repack tarball +# builds. It is called from the tinderbox scripts. Alter it with caution. + +installers-%: clobber-% langpack-% repackage-zip-% + @echo "repackaging done" + +NO_JA_JP_MAC_AB_CD := $(if $(filter ja-JP-mac, $(AB_CD)),ja,$(AB_CD)) + +bookmarks.json: bookmarks.inc generic/profile/bookmarks.json.in + $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + -I $< \ + -DAB_CD=$(NO_JA_JP_MAC_AB_CD) \ + $(srcdir)/generic/profile/bookmarks.json.in \ + > $@ + +export:: bookmarks.json + +ifdef MOZ_UPDATER +ifdef LOCALE_MERGEDIR +UPDATER_INI := $(firstword $(wildcard $(LOCALE_MERGEDIR)/updater/updater.ini) \ + $(wildcard $(LOCALE_SRCDIR)/updater/updater.ini) \ + $(srcdir)/en-US/updater/updater.ini ) +else +UPDATER_INI := $(addprefix $(LOCALE_SRCDIR)/,updater/updater.ini) +endif +libs:: $(UPDATER_INI) + cat $< | \ + sed -e "s/^InfoText=/Info=/" -e "s/^TitleText=/Title=/" | \ + sed -e "s/%MOZ_APP_DISPLAYNAME%/$(MOZ_APP_DISPLAYNAME)/" > \ + $(FINAL_TARGET)/updater.ini +endif + +ifdef MOZ_CRASHREPORTER +libs:: crashreporter-override.ini + $(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET) +endif + +# When we unpack fennec on MacOS X the platform.ini and application.ini are in slightly +# different locations that on all other platforms +ifeq (Darwin, $(OS_ARCH)) +ifdef LIBXUL_SDK +GECKO_PLATFORM_INI_PATH="$(STAGEDIST)/../Frameworks/XUL.framework/Versions/$(MOZILLA_VERSION)/platform.ini" +else +GECKO_PLATFORM_INI_PATH="$(STAGEDIST)/platform.ini" +endif +FENNEC_APPLICATION_INI_PATH="$(STAGEDIST)/application.ini" +else +ifdef LIBXUL_SDK +GECKO_PLATFORM_INI_PATH="$(STAGEDIST)/xulrunner/platform.ini" +else +GECKO_PLATFORM_INI_PATH="$(STAGEDIST)/platform.ini" +endif +FENNEC_APPLICATION_INI_PATH="$(STAGEDIST)/application.ini" +endif + +ident: + @printf "gecko_revision " + @$(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(GECKO_PLATFORM_INI_PATH) Build SourceStamp + @printf "fennec_revision " + @$(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(FENNEC_APPLICATION_INI_PATH) App SourceStamp + @printf "buildid " + @$(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(FENNEC_APPLICATION_INI_PATH) App BuildID + +# special targets just to do the debian single locale packages +wget-DEB_PKG_NAME: +ifndef WGET + $(error Wget not installed) +endif +ifndef EN_US_BINARY_URL + $(error EN_US_BINARY_URL not defined) +endif + @$(WGET) -q -O - $(EN_US_BINARY_URL)/deb_name.txt + +wget-deb: +ifndef WGET + $(error Wget not installed) +endif +ifndef EN_US_BINARY_URL + $(error EN_US_BINARY_URL not defined) +endif +ifndef DEB_PKG_NAME + $(error DEB_PKG_NAME not defined) +endif + $(WGET) -nv -N $(EN_US_BINARY_URL)/$(DEB_PKG_NAME) + +$(DATASTAGE): $(DEB_PKG_NAME) + $(RM) -rf $(DATASTAGE) + $(NSINSTALL) -D $(DATASTAGE)/DEBIAN + ar -p $(DEB_PKG_NAME) data.tar.gz | $(TAR) -zx -C $(DATASTAGE) + $(MAKE) clobber-zip AB_CD=en-US STAGEDIST=$(DATASTAGE)/$(installdir) + ar -p $(DEB_PKG_NAME) control.tar.gz | $(TAR) -zx -C $(DATASTAGE)/DEBIAN +# XXX hack around multi-locale deb right now + $(RM) $(DATASTAGE)/$(installdir)/chrome/??.* + $(RM) $(DATASTAGE)/$(installdir)/chrome/??-??.* + +repackage-deb: $(DATASTAGE) + $(RM) -rf $(AB_CD) + $(NSINSTALL) -D $(AB_CD)/tmp + cd $(DIST)/xpi-stage/locale-$(AB_CD) && \ + $(TAR) --exclude=install.rdf --exclude=chrome.manifest --exclude=crashreporter.app $(TAR_CREATE_FLAGS) - * | ( cd $(DATASTAGE)/$(installdir) && $(TAR) -xf - ) + cd $(DATASTAGE) && $(TAR) $(TAR_CREATE_FLAGS) - * | (cd $(CURDIR)/$(AB_CD)/tmp && $(TAR) -xf - ) + $(MAKE) clobber-zip STAGEDIST=$(DATASTAGE)/$(installdir) + cd $(AB_CD) && dpkg-deb -b tmp $(DEB_PKG_NAME) + $(RM) -rf $(AB_CD)/tmp + +deb-%: AB_CD=$* +deb-%: clobber-% langpack-% +ifndef DEB_PKG_NAME + $(error DEB_PKG_NAME not defined) +endif + @$(MAKE) repackage-deb AB_CD=$(AB_CD) DEB_PKG_NAME=$(DEB_PKG_NAME) + +merge-%: +ifdef LOCALE_MERGEDIR + $(RM) -rf $(LOCALE_MERGEDIR) + MACOSX_DEPLOYMENT_TARGET= compare-locales -m $(LOCALE_MERGEDIR) $(srcdir)/l10n.ini $(L10NBASEDIR) $* +endif + @echo diff --git a/mobile/android/locales/all-locales b/mobile/android/locales/all-locales new file mode 100644 index 00000000000..0b604a57353 --- /dev/null +++ b/mobile/android/locales/all-locales @@ -0,0 +1,45 @@ +ar +be +ca +cs +da +de +el +es-AR +es-ES +et +eu +fa +fi +fr +fy-NL +ga-IE +gd +gl +he +hu +id +it +ja +ja-JP-mac +ko +lt +nb-NO +nl +nn-NO +pa-IN +pl +pt-BR +pt-PT +ro +ru +sk +sl +sq +sr +th +tr +uk +vi +zh-CN +zh-TW diff --git a/mobile/android/locales/en-US/chrome/about.dtd b/mobile/android/locales/en-US/chrome/about.dtd new file mode 100644 index 00000000000..02518d19f33 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/about.dtd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/mobile/android/locales/en-US/chrome/aboutAddons.dtd b/mobile/android/locales/en-US/chrome/aboutAddons.dtd new file mode 100644 index 00000000000..e018f7499bf --- /dev/null +++ b/mobile/android/locales/en-US/chrome/aboutAddons.dtd @@ -0,0 +1,2 @@ + + diff --git a/mobile/android/locales/en-US/chrome/aboutAddons.properties b/mobile/android/locales/en-US/chrome/aboutAddons.properties new file mode 100644 index 00000000000..3c4d435c0b6 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/aboutAddons.properties @@ -0,0 +1,6 @@ +addonAction.enable=Enable +addonAction.disable=Disable +addonAction.uninstall=Uninstall +addonAction.cancel=Cancel +addonAction.options=Options +addonsSearchEngine.description=Integrated Search diff --git a/mobile/android/locales/en-US/chrome/aboutCertError.dtd b/mobile/android/locales/en-US/chrome/aboutCertError.dtd new file mode 100644 index 00000000000..9f5e09922da --- /dev/null +++ b/mobile/android/locales/en-US/chrome/aboutCertError.dtd @@ -0,0 +1,34 @@ + + %brandDTD; + + + + + + + +#1, but we can't confirm that your connection is secure."> + + + + + + +Even if you trust the site, this error could mean that someone is +tampering with your connection."> + + + + + diff --git a/mobile/android/locales/en-US/chrome/aboutHome.dtd b/mobile/android/locales/en-US/chrome/aboutHome.dtd new file mode 100644 index 00000000000..55cfd046e63 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/aboutHome.dtd @@ -0,0 +1,31 @@ +&brandShortName; Start"> + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/locales/en-US/chrome/browser.dtd b/mobile/android/locales/en-US/chrome/browser.dtd new file mode 100644 index 00000000000..3bbc6e170ad --- /dev/null +++ b/mobile/android/locales/en-US/chrome/browser.dtd @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/locales/en-US/chrome/browser.properties b/mobile/android/locales/en-US/chrome/browser.properties new file mode 100644 index 00000000000..a0dea273676 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/browser.properties @@ -0,0 +1,265 @@ +# Add-on Manager +addonsLocalNone.label=No add-ons installed +addonsSearchStart.label=Searching for add-ons… +addonsSearchStart.button=Cancel +addonsSearchNone.search=No matches found +addonsSearchNone.recommended=No recommended add-ons +addonsSearchNone.button=Try Again +addonsSearchFail.label=%S couldn't retrieve add-ons +addonsSearchFail.retryButton=Retry +addonsSearchSuccess2.button=Clear Search +addonsBrowseAll.label=Browse all add-ons +addonsBrowseAll.description=addons.mozilla.org has many to explore +addonsBrowseAll.seeMore=See More Add-ons +addonsBrowseAll.browseSite=Browse Site + +# LOCALIZATION NOTE (addonsSearchMore.label): Semi-colon list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 total number of add-ons that match the search terms +addonsSearchMore.label=Show result;Show all #1 results + +# LOCALIZATION NOTE (addonsSearchMore.description): Semi-colon list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 number of search results currently visible +addonsSearchMore.description=If this result isn't what you're looking for, try this;If these #1 results aren't what you're looking for, try this + +addonsWhatAre.label=What are Add-ons? +addonsWhatAre.button=Learn More + +# LOCALIZATION NOTE (addonsWhatAre.description): +# #1 is the application name +addonsWhatAre.description=Add-ons are applications that let you personalize #1 with extra functionality or style. You can make #1 your own. + +addonsSearchEngine.description=Integrated Search + +addonsConfirmInstall.title=Installing Add-on +addonsConfirmInstall.install=Install + +addonType.2=Extension +addonType.4=Theme +addonType.8=Locale +addonType.1024=Search + +addonUpdate.checking=Checking for updates… +addonUpdate.updating=Updating to %S +addonUpdate.updated=Updated to %S +addonUpdate.compatibility=A compatibility update has been applied +addonUpdate.noupdate=No updates were found +addonUpdate.notsupported=Updates not supported +addonUpdate.disabled=Updates are disabled +addonUpdate.error=An error occurred + +addonBlocked.blocked=Blocked +addonBlocked.softBlocked=Known to cause security or stability issues +addonBlocked.outdated=Out of date + +# LOCALIZATION NOTE (addonError-1, addonError-2, addonError-3, addonError-4): +# #1 is the add-on name, #2 is the add-on host, #3 is the application name +addonError-1=The add-on could not be downloaded because of a connection failure on #2. +addonError-2=The add-on from #2 could not be installed because it does not match the add-on #3 expected. +addonError-3=The add-on downloaded from #2 could not be installed because it appears to be corrupt. +addonError-4=#1 could not be installed because #3 cannot modify the needed file. + +# LOCALIZATION NOTE (addonLocalError-1, addonLocalError-2, addonLocalError-3, addonLocalError-4, addonErrorIncompatible, addonErrorBlocklisted): +# #1 is the add-on name, #3 is the application name, #4 is the application version +addonLocalError-1=This add-on could not be installed because of a filesystem error. +addonLocalError-2=This add-on could not be installed because it does not match the add-on #3 expected. +addonLocalError-3=This add-on could not be installed because it appears to be corrupt. +addonLocalError-4=#1 could not be installed because #3 cannot modify the needed file. +addonErrorIncompatible=#1 could not be installed because it is not compatible with #3 #4. +addonErrorBlocklisted=#1 could not be installed because it has a high risk of causing stability or security problems. + +# Download Manager +# LOCALIZATION NOTE (Status): — is the "em dash" (long dash) +# #1 download size for FINISHED or download state; #2 host (e.g., eTLD + 1, IP) +downloadsStatus=#1 — #2 +# LOCALIZATION NOTE (Time): #1 left time for UNFINISHED, total time for FINISHED +downloadsTime= — #1 +downloadsUnknownSize=Unknown size +# LOCALIZATION NOTE (KnownSize): #1 size number; #2 size unit +downloadsKnownSize=#1 #2 +downloadsYesterday=Yesterday +# LOCALIZATION NOTE (MonthDate): #1 month name; #2 date number; e.g., January 22 +downloadsMonthDate=#1 #2 +downloadsEmpty=No downloads +downloadsDeleteTitle=Delete File + +# Alerts +alertAddons=Add-ons +alertAddonsDownloading=Downloading add-on +alertAddonsInstalling=Installing add-on +alertAddonsInstalled=Installation complete. Restart required. +alertAddonsInstalledNoRestart=Installation complete +alertAddonsFail=Installation failed +alertLinkBookmarked=Bookmark added +alertLockScreen=Screen Orientation +alertLockScreen.locked=Locked +alertLockScreen.unlocked=Unlocked + +# LOCALIZATION NOTE (alertAddonsDisabled): Semi-colon list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 number of add-ons +alertAddonsDisabled=#1 incompatible add-on was disabled;#1 incompatible add-ons were disabled + +alertDownloads=Downloads +alertDownloadsStart=Downloading: %S +alertDownloadsDone=%S has finished downloading +alertCantOpenDownload=Can't open file. Tap to save it. +alertDownloadsSize=Download too big +alertDownloadsNoSpace=Not enough storage space +alertDownloadsToast=Download started… + +alertFullScreenToast=Press BACK to leave full-screen mode + +downloadCancelPromptTitle=Cancel Download +downloadCancelPromptMessage=Do you want to cancel this download? + +# Notifications +notificationRestart.normal=Restart to complete changes. +notificationRestart.update=Add-ons updated. Restart to complete changes. +notificationRestart.blocked=Unsafe add-ons installed. Restart to disable. +notificationRestart.button=Restart + +# Popup Blocker +popupWarning=%S prevented this site from opening a pop-up window. +popupWarningMultiple=%S prevented this site from opening %S pop-up windows. +popupButtonAllowOnce=Show +popupButtonAlwaysAllow2=Always Show +popupButtonNeverWarn2=Never Show + +# Telemetry +telemetry.optin.message=Help improve %S by sending anonymous usage information to Mozilla? +telemetry.optin.yes=Yes +telemetry.optin.no=No + +# XPInstall +xpinstallPromptWarning2=%S prevented this site (%S) from asking you to install software on your device. +xpinstallPromptAllowButton=Allow +xpinstallDisabledMessageLocked=Software installation has been disabled by your system administrator. +xpinstallDisabledMessage2=Software installation is currently disabled. Press Enable and try again. +xpinstallDisabledButton=Enable + +# Site Identity +identity.identified.verifier=Verified by: %S +identity.identified.verified_by_you=You have added a security exception for this site +identity.identified.state_and_country=%S, %S +identity.identified.title_with_country=%S (%S) +identity.encrypted2=Encrypted +identity.unencrypted2=Not encrypted +identity.unknown.tooltip=This website does not supply identity information. +identity.ownerUnknown2=(unknown) + +# Geolocation UI +geolocation.allow=Share +geolocation.dontAllow=Don't share +geolocation.wantsTo=%S wants your location. + +# Desktop notification UI +desktopNotification.allow=Allow +desktopNotification.dontAllow=Don't allow +desktopNotification.wantsTo=%S wants to use notifications. + +# New Tab Popup +# LOCALIZATION NOTE (newtabpopup): Semi-colon list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 number of tabs +newtabpopup.opened=New tab opened;#1 new tabs opened + +# Error Console +typeError=Error: +typeWarning=Warning: + +# Offline web applications +offlineApps.available2=%S wants to store data on your device for offline use. +offlineApps.allow=Allow +offlineApps.never=Don't Allow +offlineApps.notNow=Not Now + +# New-style ContentPermissionPrompt values +offlineApps.dontAllow=Don't Allow +offlineApps.wantsTo=%S wants to store data on your device for offline use. + +# IndexedDB Quota increases +indexedDBQuota.allow=Allow +indexedDBQuota.dontAllow=Don't Allow +indexedDBQuota.wantsTo=%S wants to store a lot of data on your device for offline use. + +# Open Web Apps management API +openWebappsManage.allow=Allow +openWebappsManage.dontAllow=Don't Allow +openWebappsManage.wantsTo=%S wants to manage applications on your device. + +# Bookmark List +bookmarkList.desktop=Desktop Bookmarks + +# Closing Tabs +tabs.closeWarningTitle=Confirm close + +# LOCALIZATION NOTE (tabs.closeWarning): Semi-colon list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 number of tabs (must be greater than 1) +tabs.closeWarning=NOT USED;You are about to close #1 tabs. Continue? + +tabs.closeButton=Close tabs +tabs.closeWarningPromptMe=Warn me when I attempt to close multiple tabs + +tabs.crashWarningTitle=Sorry! +tabs.crashWarningMsg=Something went wrong while displaying a web page. +tabs.crashSubmitReport=Send Mozilla a crash report +tabs.crashClose=Close tab +tabs.crashReload=Reload tab + +# Homepage +# LOCALIZATION NOTE: homepage.custom2 is the text displayed on the selector button if +# the user selects a webpage to be the startpage. We can't display the entire URL +# or webpage title on the menulist +homepage.custom2=Custom Page + +# Page Actions +pageactions.saveas.pdf=Save As PDF +pageactions.geolocation=Location +pageactions.popup=Popups +pageactions.offline-app=Offline Storage +pageactions.password=Password +pageactions.desktop-notification=Web Notifications +pageactions.openWebappsManage=Manage Web Apps + +# Open Search +opensearch.searchWith=Search With: +opensearch.searchFor=Search for "%S" + +# Open in Another App +# LOCALIZATION NOTE: openinapp.specific is the text displayed if there is a single external app +# %S is the name of the app, like "YouTube" or "Picassa" +openinapp.specific=Open in %S App +openinapp.general=Open in Another App + +# Clear Private Data +clearPrivateData.title=Clear Private Data +clearPrivateData.message=Delete your browsing history and settings, including passwords and cookies? + +# LOCALIZATION NOTE (browser.menu.showCharacterEncoding): Set to the string +# "true" (spelled and capitalized exactly that way) to show the "Character +# Encoding" menu in the site menu. Any other value will hide it. Without this +# setting, the "Character Encoding" menu must be enabled via Preferences. +# This is not a string to translate. If users frequently use the "Character Encoding" +# menu, set this to "true". Otherwise, you can leave it as "false". +browser.menu.showCharacterEncoding=false + +# LOCALIZATION NOTE (intl.charsetmenu.browser.static): Set to a series of comma separated +# values for charsets that the user can select from in the Character Encoding menu. +intl.charsetmenu.browser.static=iso-8859-1,utf-8,x-gbk,big5,iso-2022-jp,shift_jis,euc-jp + +#Application Menu +appMenu.more=More + +#Text Selection +selectionHelper.textCopied=Text copied to clipboard + +#Context menu +contextmenu.openInNewTab=Open Link in New Tab +contextmenu.changeInputMethod=Select Input Method +contextmenu.fullScreen=Full Screen + +#Select UI +selectHelper.closeMultipleSelectDialog=Done diff --git a/mobile/android/locales/en-US/chrome/checkbox.dtd b/mobile/android/locales/en-US/chrome/checkbox.dtd new file mode 100644 index 00000000000..68c2883c516 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/checkbox.dtd @@ -0,0 +1,2 @@ + + diff --git a/mobile/android/locales/en-US/chrome/config.dtd b/mobile/android/locales/en-US/chrome/config.dtd new file mode 100644 index 00000000000..e5eb8d4ebd5 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/config.dtd @@ -0,0 +1,3 @@ + + + diff --git a/mobile/android/locales/en-US/chrome/config.properties b/mobile/android/locales/en-US/chrome/config.properties new file mode 100644 index 00000000000..89c8590cbc6 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/config.properties @@ -0,0 +1,15 @@ +addPref.title=Add +addPref.selectType=Select type: +addPref.type.string=String +addPref.type.integer=Integer +addPref.type.boolean=Boolean +addPref.enterName=Enter name: + +togglePref.label=Toggle +modifyPref.label=Modify +modifyPref.selectText=Select value for %1$S: +modifyPref.promptText=Enter value for %1$S: +modifyPref.numberErrorTitle=Invalid Value +modifyPref.numberErrorText=The text you entered was not a number + +resetPref.label=Reset diff --git a/mobile/android/locales/en-US/chrome/feedback.dtd b/mobile/android/locales/en-US/chrome/feedback.dtd new file mode 100644 index 00000000000..4cb8b90600c --- /dev/null +++ b/mobile/android/locales/en-US/chrome/feedback.dtd @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/mobile/android/locales/en-US/chrome/localepicker.properties b/mobile/android/locales/en-US/chrome/localepicker.properties new file mode 100644 index 00000000000..232e3656d97 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/localepicker.properties @@ -0,0 +1,13 @@ +title=Select a language +continueIn=Continue in %S + +# LOCALIZATION NOTE (name): The localized name of this locale. +# Do not just translate the word 'English' +name=English +choose=Choose a different language +chooseLanguage=Choose a Language +cancel=Cancel +continue=Continue +installing=Installing %S +installerror=Error installing language +loading=Loading… diff --git a/mobile/android/locales/en-US/chrome/notification.dtd b/mobile/android/locales/en-US/chrome/notification.dtd new file mode 100644 index 00000000000..0539d6c4ced --- /dev/null +++ b/mobile/android/locales/en-US/chrome/notification.dtd @@ -0,0 +1,8 @@ + + + diff --git a/mobile/android/locales/en-US/chrome/overrides/appstrings.properties b/mobile/android/locales/en-US/chrome/overrides/appstrings.properties new file mode 100644 index 00000000000..87e9538f7a6 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/overrides/appstrings.properties @@ -0,0 +1,68 @@ +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +malformedURI=The URL is not valid and cannot be loaded. +fileNotFound=Firefox can't find the file at %S. +dnsNotFound=Firefox can't find the server at %S. +protocolNotFound=Firefox doesn't know how to open this address, because the protocol (%S) isn't associated with any program. +connectionFailure=Firefox can't establish a connection to the server at %S. +netInterrupt=The connection to %S was interrupted while the page was loading. +netTimeout=The server at %S is taking too long to respond. +redirectLoop=Firefox has detected that the server is redirecting the request for this address in a way that will never complete. +## LOCALIZATION NOTE (confirmRepostPrompt): In this item, don't translate "%S" +confirmRepostPrompt=To display this page, %S must send information that will repeat any action (such as a search or order confirmation) that was performed earlier. +resendButton.label=Resend +unknownSocketType=Firefox doesn't know how to communicate with the server. +netReset=The connection to the server was reset while the page was loading. +notCached=This document is no longer available. +netOffline=Firefox is currently in offline mode and can't browse the Web. +isprinting=The document cannot change while Printing or in Print Preview. +deniedPortAccess=This address uses a network port which is normally used for purposes other than Web browsing. Firefox has canceled the request for your protection. +proxyResolveFailure=Firefox is configured to use a proxy server that can't be found. +proxyConnectFailure=Firefox is configured to use a proxy server that is refusing connections. +contentEncodingError=The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression. +unsafeContentType=The page you are trying to view cannot be shown because it is contained in a file type that may not be safe to open. Please contact the website owners to inform them of this problem. +externalProtocolTitle=External Protocol Request +externalProtocolPrompt=An external application must be launched to handle %1$S: links.\n\n\nRequested link:\n\n%2$S\n\nApplication: %3$S\n\n\nIf you were not expecting this request it may be an attempt to exploit a weakness in that other program. Cancel this request unless you are sure it is not malicious.\n +#LOCALIZATION NOTE (externalProtocolUnknown): The following string is shown if the application name can't be determined +externalProtocolUnknown= +externalProtocolChkMsg=Remember my choice for all links of this type. +externalProtocolLaunchBtn=Launch application +malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences. +phishingBlocked=The website at %S has been reported as a web forgery designed to trick users into sharing personal or financial information. +cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way. +corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected. +remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox. diff --git a/mobile/android/locales/en-US/chrome/overrides/netError.dtd b/mobile/android/locales/en-US/chrome/overrides/netError.dtd new file mode 100644 index 00000000000..10687d27559 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/overrides/netError.dtd @@ -0,0 +1,172 @@ + +%brandDTD; + + + + + + + + + + + + + + +
  • Check the address for typing errors such as + ww.example.com instead of + www.example.com
  • +
  • If you are unable to load any pages, check your device's data or Wi-Fi connection.
  • + +"> + + + +
  • Check the file name for capitalization or other typing errors.
  • +
  • Check to see if the file was moved, renamed or deleted.
  • + +"> + + + +&brandShortName; can't load this page for some reason.

    +"> + + + +
  • Web addresses are usually written like + http://www.example.com/
  • +
  • Make sure that you're using forward slashes (i.e. + /).
  • + +"> + + + + + +The requested document is not available in &brandShortName;'s cache.

    • As a security precaution, &brandShortName; does not automatically re-request sensitive documents.
    • Click Try Again to re-request the document from the website.
    "> + + + +
  • Try again. &brandShortName; will attempt to open a connection and reload the page.
  • + +"> + + + +
  • Please contact the website owners to inform them of this problem.
  • + +"> + + + +
  • Please contact the website owners to inform them of this problem.
  • + +"> + + + + + + + + + +
  • You might need to install other software to open this address.
  • + +"> + + + +
  • Check the proxy settings to make sure that they are correct.
  • +
  • Contact your network administrator to make sure the proxy server is + working.
  • + +"> + + + +
  • Check the proxy settings to make sure that they are correct.
  • +
  • Check to make sure your device has a working data or Wi-Fi connection.
  • + +"> + + + +
  • This problem can sometimes be caused by disabling or refusing to accept + cookies.
  • + +"> + + + +
  • Check to make sure your system has the Personal Security Manager + installed.
  • +
  • This might be due to a non-standard configuration on the server.
  • + +"> + + + +
  • The page you are trying to view can not be shown because the authenticity of the received data could not be verified.
  • +
  • Please contact the website owners to inform them of this problem. Alternatively, use the command found in the help menu to report this broken site.
  • + +"> + + + +
  • This could be a problem with the server's configuration, or it could be +someone trying to impersonate the server.
  • +
  • If you have connected to this server successfully in the past, the error may +be temporary, and you can try again later.
  • + +"> + + +
  • The site could be temporarily unavailable or too busy. Try again in a few moments.
  • +
  • If you are unable to load any pages, check your mobile device's data or Wi-Fi connection.
  • + +"> + + +&brandShortName; prevented this page from loading in this way because the page has a content security policy that disallows it.

    "> + + +The page you are trying to view cannot be shown because an error in the data transmission was detected.

    • Please contact the website owners to inform them of this problem.
    "> + + + + + + + +You should not add an exception if you are using an internet connection that you do not trust completely or if you are not used to seeing a warning for this server.

    + + + +"> + + +
    • Please contact the website owners to inform them of this problem.

    "> + diff --git a/mobile/android/locales/en-US/chrome/overrides/passwordmgr.properties b/mobile/android/locales/en-US/chrome/overrides/passwordmgr.properties new file mode 100644 index 00000000000..f907d4437f5 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/overrides/passwordmgr.properties @@ -0,0 +1,74 @@ +# ***** 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 Password Manager. +# +# The Initial Developer of the Original Code is +# Brian Ryner. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Brian Ryner +# Ehsan Akhgari +# +# 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 ***** + +rememberValue = Use Password Manager to remember this value. +rememberPassword = Use Password Manager to remember this password. +savePasswordTitle = Confirm +# 1st string is product name, 2nd is the username for the login, 3rd is the +# login's hostname. Note that long usernames may be truncated. +saveLoginText = Do you want %1$S to remember the password for "%2$S" on %3$S? +# 1st string is product name, 2nd is the login's hostname +saveLoginTextNoUsername = Do you want %1$S to remember this password on %2$S? +promptNotNowButtonText = Not Now +notifyBarNotNowButtonText = Not Now +notifyBarNotNowButtonAccessKey = +promptNeverForSiteButtonText = Never +notifyBarNeverForSiteButtonText = Never +notifyBarNeverForSiteButtonAccessKey = +promptRememberButtonText = Remember +notifyBarRememberButtonText = Remember +notifyBarRememberButtonAccessKey = +passwordChangeTitle = Confirm Password Change +passwordChangeText = Would you like to change the stored password for %S? +passwordChangeTextNoUser = Would you like to change the stored password for this login? +notifyBarChangeButtonText = Change +notifyBarChangeButtonAccessKey = +notifyBarDontChangeButtonText = Don't Change +notifyBarDontChangeButtonAccessKey = +userSelectText = Please confirm which user you are changing the password for +hidePasswords=Hide Passwords +hidePasswordsAccessKey=P +showPasswords=Show Passwords +showPasswordsAccessKey=P +noMasterPasswordPrompt=Are you sure you wish to show your passwords? +removeAllPasswordsPrompt=Are you sure you wish to remove all passwords? +removeAllPasswordsTitle=Remove all passwords +loginsSpielAll=Passwords for the following sites are stored on your computer: +loginsSpielFiltered=The following passwords match your search: +username=Username +password=Password diff --git a/mobile/android/locales/en-US/chrome/phishing.dtd b/mobile/android/locales/en-US/chrome/phishing.dtd new file mode 100644 index 00000000000..5299348f440 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/phishing.dtd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + has been reported as an attack page and has been blocked based on your security preferences."> +Attack pages try to install programs that steal private information, use your computer to attack others, or damage your system.

    Some attack pages intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.

    "> + + + +These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust.

    "> diff --git a/mobile/android/locales/en-US/chrome/preferences.dtd b/mobile/android/locales/en-US/chrome/preferences.dtd new file mode 100644 index 00000000000..04b2e5fe0e7 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/preferences.dtd @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/locales/en-US/chrome/prompt.dtd b/mobile/android/locales/en-US/chrome/prompt.dtd new file mode 100644 index 00000000000..c1251f1c498 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/prompt.dtd @@ -0,0 +1,2 @@ + + diff --git a/mobile/android/locales/en-US/chrome/region.properties b/mobile/android/locales/en-US/chrome/region.properties new file mode 100644 index 00000000000..2a7a85234bc --- /dev/null +++ b/mobile/android/locales/en-US/chrome/region.properties @@ -0,0 +1,32 @@ +# Default search engine +browser.search.defaultenginename=Google + +# Search engine order (order displayed in the search bar dropdown)s +browser.search.order.1=Google + +# This is the default set of web based feed handlers shown in the reader +# selection UI +browser.contentHandlers.types.0.title=My Yahoo +browser.contentHandlers.types.0.uri=http://add.my.yahoo.com/rss?url=%s +browser.contentHandlers.types.1.title=Google +browser.contentHandlers.types.1.uri=http://fusion.google.com/add?feedurl=%s + +# Keyword URL (for location bar searches) +keyword.URL=http://www.google.com/search?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q= + +# increment this number when anything gets changed in the list below. This will +# cause Firefox to re-read these prefs and inject any new handlers into the +# profile database. Note that "new" is defined as "has a different URL"; this +# means that it's not possible to update the name of existing handler, so +# don't make any spelling errors here. +gecko.handlerService.defaultHandlersVersion=2 + +# The default set of protocol handlers for webcal: +gecko.handlerService.schemes.webcal.0.name=30 Boxes +gecko.handlerService.schemes.webcal.0.uriTemplate=http://30boxes.com/external/widget?refer=ff&url=%s + +# The default set of protocol handlers for mailto: +gecko.handlerService.schemes.mailto.0.name=Yahoo! Mail +gecko.handlerService.schemes.mailto.0.uriTemplate=http://compose.mail.yahoo.com/?To=%s +gecko.handlerService.schemes.mailto.1.name=Gmail +gecko.handlerService.schemes.mailto.1.uriTemplate=https://mail.google.com/mail/?extsrc=mailto&url=%s diff --git a/mobile/android/locales/en-US/chrome/sync.dtd b/mobile/android/locales/en-US/chrome/sync.dtd new file mode 100644 index 00000000000..a532c6b10fd --- /dev/null +++ b/mobile/android/locales/en-US/chrome/sync.dtd @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/locales/en-US/chrome/sync.properties b/mobile/android/locales/en-US/chrome/sync.properties new file mode 100644 index 00000000000..541ee114465 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/sync.properties @@ -0,0 +1,29 @@ +# Mobile Sync + +# %S is the date and time at which the last sync successfully completed +lastSync2.label=Last sync: %S +lastSyncInProgress2.label=Last sync: in progress… + +# %S is the username logged in +account.label=Account: %S +notconnected.label=Not connected +connecting.label=Connecting… + +notificationDisconnect.label=Your Firefox Sync account has been removed +notificationDisconnect.button=Undo + +# LOCALIZATION NOTE (sync.clientUpdate, sync.remoteUpdate): +# #1 is the "application name" +# #2 is the "version" +sync.update.client=#1 #2 is not compatible with the latest version of Firefox Sync. Please update to the latest version. +sync.update.remote=#1 #2 is not compatible with older versions of Firefox Sync. Please update Firefox on your other computer(s). +sync.update.title=Firefox Sync +sync.update.button=Learn More +sync.update.close=Close +sync.setup.error.title=Cannot Setup Sync +sync.setup.error.network=No internet connection available +sync.setup.error.nodata=%S could not connect to Sync. Would you like to try again? +sync.setup.tryagain=Try again +sync.setup.manual=Manual setup + +sync.message.notabs=No tabs from your other computers. diff --git a/mobile/android/locales/en-US/chrome/webapps.dtd b/mobile/android/locales/en-US/chrome/webapps.dtd new file mode 100644 index 00000000000..f69f1c7a66b --- /dev/null +++ b/mobile/android/locales/en-US/chrome/webapps.dtd @@ -0,0 +1,7 @@ + + + + + + + diff --git a/mobile/android/locales/en-US/crashreporter/crashreporter-override.ini b/mobile/android/locales/en-US/crashreporter/crashreporter-override.ini new file mode 100644 index 00000000000..2ee9649d5fd --- /dev/null +++ b/mobile/android/locales/en-US/crashreporter/crashreporter-override.ini @@ -0,0 +1,10 @@ +# This file is in the UTF-8 encoding +[Strings] +# LOCALIZATION NOTE (CrashReporterProductErrorText2): %s is replaced with another string containing detailed information. +CrashReporterProductErrorText2=Firefox has crashed. Unfortunately the crash reporter is unable to submit a crash report.\n\nDetails: %s +CrashReporterDescriptionText2=Firefox has crashed. Your tabs will be listed on the Firefox Start page when you restart.\n\nPlease help us fix the problem! +# LOCALIZATION NOTE (CheckSendReport): The %s is replaced with the vendor name. +CheckSendReport=Send %s a crash report +CheckIncludeURL=Include the page address +Quit2=Quit Firefox +Restart=Restart Firefox diff --git a/mobile/android/locales/en-US/defines.inc b/mobile/android/locales/en-US/defines.inc new file mode 100644 index 00000000000..24f45813a28 --- /dev/null +++ b/mobile/android/locales/en-US/defines.inc @@ -0,0 +1,9 @@ +#filter emptyLines + +#define MOZ_LANGPACK_CREATOR mozilla.org + +# If non-English locales wish to credit multiple contributors, uncomment this +# variable definition and use the format specified. +# #define MOZ_LANGPACK_CONTRIBUTORS Joe Solon Suzy Solon + +#unfilter emptyLines diff --git a/mobile/android/locales/en-US/installer/setup.ini b/mobile/android/locales/en-US/installer/setup.ini new file mode 100644 index 00000000000..1ed7de333fd --- /dev/null +++ b/mobile/android/locales/en-US/installer/setup.ini @@ -0,0 +1,17 @@ +; This file is in the UTF-8 encoding +[Strings] +AppShortName=%MOZ_APP_DISPLAYNAME% +AppLongName=Mozilla %MOZ_APP_DISPLAYNAME% +WindowCaption=Mozilla %MOZ_APP_DISPLAYNAME% Setup +InstallTo=Install %MOZ_APP_DISPLAYNAME% to +Install=Install +Cancel=Cancel +InstalledSuccessfully=Mozilla %MOZ_APP_DISPLAYNAME% has been installed successfully. +ExtractionError=Archive extraction error: +ThereWereErrors=There were errors during installation: +CreatingUserProfile=Creating user profile. Please wait... +UninstallCaption=Mozilla %MOZ_APP_DISPLAYNAME% Uninstall +FilesWillBeRemoved=All files will be removed from +AreYouSure=Are you sure? +InstallationNotFound=Mozilla %MOZ_APP_DISPLAYNAME% installation not found. +UninstalledSuccessfully=Mozilla %MOZ_APP_DISPLAYNAME% has been uninstalled successfully. diff --git a/mobile/android/locales/en-US/mobile-l10n.js b/mobile/android/locales/en-US/mobile-l10n.js new file mode 100644 index 00000000000..e9027aaeb93 --- /dev/null +++ b/mobile/android/locales/en-US/mobile-l10n.js @@ -0,0 +1,39 @@ +# ***** 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 the Firefox browser. +# +# The Initial Developer of the Original Code is +# Benjamin Smedberg +# Portions created by the Initial Developer are Copyright (C) 2004 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# 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 + +pref("general.useragent.locale", "@AB_CD@"); diff --git a/mobile/android/locales/en-US/profile/bookmarks.inc b/mobile/android/locales/en-US/profile/bookmarks.inc new file mode 100644 index 00000000000..85091c79c04 --- /dev/null +++ b/mobile/android/locales/en-US/profile/bookmarks.inc @@ -0,0 +1,30 @@ +#filter emptyLines + +# LOCALIZATION NOTE: The 'en-US' strings in the URLs will be replaced with +# your locale code, and link to your translated pages as soon as they're +# live. + +# LOCALIZATION NOTE: Some of these URLs are currently 404s, but should be coming +# online shortly. + +# LOCALIZATION NOTE (bookmarks_title): +# title for the folder that will contains the default bookmarks +#define bookmarks_title Mobile + +# LOCALIZATION NOTE (bookmarks_aboutBrowser): +# link title for about:fennec +#define bookmarks_aboutBrowser Firefox: About your browser + +# LOCALIZATION NOTE (bookmarks_addons): +# link title for https://addons.mozilla.org/en-US/mobile +#define bookmarks_addons Firefox: Customize with add-ons + +# LOCALIZATION NOTE (bookmarks_support): +# link title for https://support.mozilla.com/mobile +#define bookmarks_support Firefox: Support + +# LOCALIZATION NOTE (bookmarks_aboutHome): +# link title for about:home +#define bookmarks_aboutHome Firefox Start + +#unfilter emptyLines diff --git a/mobile/android/locales/en-US/searchplugins/amazondotcom.xml b/mobile/android/locales/en-US/searchplugins/amazondotcom.xml new file mode 100644 index 00000000000..a58e4c46e1e --- /dev/null +++ b/mobile/android/locales/en-US/searchplugins/amazondotcom.xml @@ -0,0 +1,12 @@ + +Amazon.com +ISO-8859-1 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZJREFUeNrEV01IFGEYfndXNzq0QdalJOoUbQiBUuopD2k/GFSG/Vxyq0OHbCUjwn7AEooUzUNRkdkhS1o9JBVaUDctKqhoRQi0WjtlxG6XVtfpfb6Z2caZ2ZnZXZdeeJxvx+973+f9+775XJIkkUaWMcoYG5TxfMpvxlvGMGM8+RYEFOxn/JJyLzOMiwwv7LqUCNQwHjpxIxKJ0Gg4LABZUVhIfr+f1jLSlNuMwyCwEHoZS6xmvxoZoc6Oq+JpJoVMpOncWdpcWZkOiRIQ2MKDp1az+kIhOtV40pHG6zdvpEOixc1/VtqFvKX5gmOX0pkL2yDgsZpxt+sORaPROe8Q6ncf3tPAk8eG3Ks14lA8brsZYZ2yukBAwOfzCeMHA3WGNXrCVpLnJKeqRyhAfX5RfNmILQF4urG0VIzxBBkU5aQI9agIeU4JqNLZ0UH9ob6sDWZE4MDefSn7P1txO/FcbxypQG18nhinew/u5zYC3dyG+qLL1qjjCKDg9C21q2a3oe9zRsCsn2PR2JzfKEy9PB96Nj8E0IJm54IaGZwPZsWJOU4jY1kD2OlAQhsJjKu3bSe7yPUzifpgMPsuOBY8brtR1evmyFt0IL0IzH4fJtcCH7kK1hn2/hh71G1yKKEdz/DBBIOTkUkRemzVl1uvCGKzE4OMIaFbiv1LSX51L7mXl4kxvgeO8vMaJk0PHiHvjl4DCTWs2lMOX0L6cwD/Bxlp6hNNv2gUT9MjsLiB8koaMOxJRgCMgPijWsqvaCP3qqqUZ4JVzUASYyFyL/WTqyggPxWH4qGtBlJzagCGIYjEzJv2zHe38vOUt6mNPGv20OyPMMV7yuVwL5IjBlLmRej1UX7VLdmLt+2CMVKTiSDn0wO1NPPyBOtdLL+MyzWkTbGhC5AGsBdKkEtWAjglgjUwCq/FGjhV0ZosdOhXI5FyH0DoIIK9slB0CS8UCgr8AlpvpamwqHpttcO4WtSqA57ioKENE05IqIYSY46uD4Is0qmGG2s9RYeS7adI3Paz3K6lTMmzIdFmXp/d1Gb1YvLF7i4IzxMfu1ITYWOe1VWix7U5tlKpXkzwYycONqfVLcW+cU7lQ0jePf360DqRS4zT/+Ny+ofRxPBoL6fa6zmu5uvtbkwZyE/lev6a8VV9+VeAAQADg36zc4GRNAAAAABJRU5ErkJggg== + + + + + + +http://www.amazon.com/ + diff --git a/mobile/android/locales/en-US/searchplugins/google.xml b/mobile/android/locales/en-US/searchplugins/google.xml new file mode 100644 index 00000000000..721939748da --- /dev/null +++ b/mobile/android/locales/en-US/searchplugins/google.xml @@ -0,0 +1,15 @@ + +Google +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABvxJREFUeNqUV1tsFVUUXWdm7qMPaKEUChJekgBioFEehhJBEkUjQQkGP5QPSSDCD4nhYZAPYiQaQyTyowJRCBoxEhOx+IMi5aFG5VEIELGFUiilFFrae3sf8zjHfc7M3Dtz70VkyOYMc4ez1l57n733MCEE6FJ/yevg+T5s+qETlgOYpg0zbWJpfRV2vP4oCq/uFSsh9uxBmeCIgsOgZ8wzf1Pahn4BbM8sMtP7fZQQTAuCn76RxruH70KPx6HFYmCe7f+rF5/+fLOIQO3nu6DNfwYOy8OyAhLBNWiSyDXGhBbcsPFiEiISAQwyfyWTz94/1IFS1+Dt22gznbxkeU+CXj3gWYjA9Xs2HMFINgYuoDblJJJgOnqzAl+e7CraIDp9GlBfD5tU8Encz1Di3yECtsNh2VyttiPgSCMmihC9+v3puyVVMObPIxU0FeuHMUnCCBGgzDNNh7wWlIQCtu0QCe6SoLePXrxXkgCqq3JJVpiE/0UAhQRGVOowsxlwTVcK2FINIiFXqUZvximJL6W34YZOBkELyMwLToETsKIQzBpTBjNjEQkLFh1BZZbjKsHFfdIIyLRdow2JsDKEzCkALvwtRGDh1CqUMcclIWsAgVsUEhka0FlnojSBRNNx8lKEzrpVcG8VPPctFIKqMh0rG2rw3o+36GxrsMlrLoPPCZw7ePmJoUXgt/d+BbPtKjJ1MVxpGIqeEXG0T6iASbqb9H+NhI1RrUmMupLEpAt9iA7YOSKqPggRdqsvZWPGlrO40mOraMqYSvChMY6f3p6OaWMH5ZP2Xh++WTUfF5dUIjk6RpsKZIl0loBlumTkartrWj0TmHOkC0sOtKP6TpaqJxHoHbBEdXlICDS3J7Fi12Wcuz6gZH+JPN/22kSMHRbPvZOykvjwxAbctVtQVkZKaZzAPVAf3LtX4LYk4ZGh+zlNXXhrdwtY7apjYvfKyVg8oxb/92rrbcXWY+upCiUUeJQKpjy6pkcgGyCQtgP3niJp716dgj6ivWzHeSzb3oxz1xIPBL/S04rNR9YhpSUgDEo8jYCFC2559cIR7ioPjlB/vHvhHc9AOTR0TajS0XjmDg6d6sLYmhjG1USx6MnhWPNicQfc17wPSUGeK3B3Z9vblJRVJKhs5Ej4xj0SXBQUooig1GHugaTmhI6eFDq7+zFvSvV9io573i3h7iY7IfO840I+lySgSNi+InLlyKnjE1EhiPEsYtxEVJiQZKKUyxGyS22l6/7qmWswJFYHqlXI2kwllzQ/8+XRM7kfEo+MKFQkf6/FnDR8i6s1Q4QyOPJ7Ky5eLSZRVzkCnyz8DJMG1yOdoYSi6UKRcFwSMgGl5Um4IbF8RXwluGv68Mde2GI4FgzHVNYwpQYNk4fh+ZmjEY8wTBg9pLgF61E8N34hOvq78DclpSqxKgeE67UXBkkitxY8k8RUNxxXHcHyRdMwa+ooTB4/DA9zbZy9AdNqp2Prnx+A0VGU441qPCLvteWTcERRbpSshKH2nOmGlaZJiELDjEGIVz9e8r2dzXux88IXNDmRV0y4igS8thw3HLJKmo67ilIEuNWPVHcTMj1nkLl3DproA7M7ILI3qUMyDJq4CTVT15ck8crBlbiUuKxqg+yMjggrYAXAg401RyDdfRI951bDEB2IxsqhGzp0MUCsknDooJtZA6lUBJGRyzHyqY+LCBxuO4E3f3lHqeAw7qkALxThQhXs6qoJpG7/iq4Ti1FZYSIep2NIVU4NWHLaJdM0akoGVYAox0D71+iwdTwy96MQgWfHzUWGToQKgeb1fy8MPgleYmpV88Ct39YiTgBRXdB8S4WFE7CjQ5Y6oXYjAlStDNpcvpO6egADnX8UqSBrg+p+Xm3IqCMpVALyoimVKdPM5A3wgesEDAUsCJSTh45FZhveqqtn1PJIHY3IGki0HCyejEJd0K0L0vvQp49qDCxXjw0rQVkudPJUggj1I3eVd5sHsRSSGIEzHiGicVIiCid5u1gBb4DhKJhMEfQ6MCzKHKgYOZs2LicCpLRFkmuO6gn5WMkoUWCEQUYfKYJmAlGGyjELQuDf/3NCtWSBEsAoAc5ZPgcGjX+VwCtJ/gpiUe4aL1PENEFGq7wHryCViCxqUTF2fojAjlPfEleRl9sHksAByd2PxUAI5PvDZm1EJw0ZZuICfZHZ0Gm6Ycx3QHNDRAo4tmxTNRg8Yy2MyroceFP7WRztOAM1YyHvXdGnkAgQ8d7J1QFuJpFsaUSqtRFO32VoJCdjzJOOEtCoQnT00xhc/0YIvLmrBQv2r0Uv71dFSPVmVvg9xvKfQkE1PAJy7ZXfN6GM7jzjJRIdlWglokMnFiVdU9tZLP1uswfOVQhccFbsPWd5QtwNvlh3nP0rwACsnu1i3ddmfAAAAABJRU5ErkJggg== + + + + + + + + + +http://www.google.com/m + diff --git a/mobile/android/locales/en-US/searchplugins/list.txt b/mobile/android/locales/en-US/searchplugins/list.txt new file mode 100644 index 00000000000..f241bfebff6 --- /dev/null +++ b/mobile/android/locales/en-US/searchplugins/list.txt @@ -0,0 +1,4 @@ +amazondotcom +google +twitter +wikipedia diff --git a/mobile/android/locales/en-US/searchplugins/twitter.xml b/mobile/android/locales/en-US/searchplugins/twitter.xml new file mode 100644 index 00000000000..2609568cb3c --- /dev/null +++ b/mobile/android/locales/en-US/searchplugins/twitter.xml @@ -0,0 +1,9 @@ + + Twitter + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAADTppVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDQuMi4yLWMwNjMgNTMuMzUyNjI0LCAyMDA4LzA3LzMwLTE4OjA1OjQxICAgICAgICAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6eG1wUmlnaHRzPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvcmlnaHRzLyIKICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIKICAgIHhtbG5zOklwdGM0eG1wQ29yZT0iaHR0cDovL2lwdGMub3JnL3N0ZC9JcHRjNHhtcENvcmUvMS4wL3htbG5zLyIKICAgeG1wUmlnaHRzOldlYlN0YXRlbWVudD0iIgogICBwaG90b3Nob3A6QXV0aG9yc1Bvc2l0aW9uPSIiPgogICA8ZGM6cmlnaHRzPgogICAgPHJkZjpBbHQ+CiAgICAgPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ii8+CiAgICA8L3JkZjpBbHQ+CiAgIDwvZGM6cmlnaHRzPgogICA8ZGM6Y3JlYXRvcj4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkvPgogICAgPC9yZGY6U2VxPgogICA8L2RjOmNyZWF0b3I+CiAgIDxkYzp0aXRsZT4KICAgIDxyZGY6QWx0PgogICAgIDxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+dHdpdHRlci10LXNvbG88L3JkZjpsaT4KICAgIDwvcmRmOkFsdD4KICAgPC9kYzp0aXRsZT4KICAgPHhtcFJpZ2h0czpVc2FnZVRlcm1zPgogICAgPHJkZjpBbHQ+CiAgICAgPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ii8+CiAgICA8L3JkZjpBbHQ+CiAgIDwveG1wUmlnaHRzOlVzYWdlVGVybXM+CiAgIDxJcHRjNHhtcENvcmU6Q3JlYXRvckNvbnRhY3RJbmZvCiAgICBJcHRjNHhtcENvcmU6Q2lBZHJFeHRhZHI9IiIKICAgIElwdGM0eG1wQ29yZTpDaUFkckNpdHk9IiIKICAgIElwdGM0eG1wQ29yZTpDaUFkclJlZ2lvbj0iIgogICAgSXB0YzR4bXBDb3JlOkNpQWRyUGNvZGU9IiIKICAgIElwdGM0eG1wQ29yZTpDaUFkckN0cnk9IiIKICAgIElwdGM0eG1wQ29yZTpDaVRlbFdvcms9IiIKICAgIElwdGM0eG1wQ29yZTpDaUVtYWlsV29yaz0iIgogICAgSXB0YzR4bXBDb3JlOkNpVXJsV29yaz0iIi8+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz6sMuh4AAADGElEQVR42tRXT2jTYBT/0tR0Sek2RIvr/NMq66RTOj3sMD1UKuxg9SQep8gugruoh6nbaRfBo6CgF93NHqUgooIgKpYhLWKZ3aTVTZG6dd26Nm3WNn6vS/QjJjVtuooPHs3H95L36/v/KFEUkRoFnmXs+MeD2YmZIa7imGOh450p1ASi1ABg5QPeDrN/uIcN7LGZ+ttoipPvPmbKr6dm+VB0pfQcgwgbRgAASD7xdHngZiQ3yZcqOVGD4C6ULNwHWeX79bJSuf1aOHu1lnISBADF7+w0AsCsMIgHzC6bfEUQ0Y1IDr1fLVUvD7ab0Vi/FXUwFAKZ03stgRc/hJf4aqFRDygBOMHn8oFUDgTP49Nr6NagbUPYRoOsE8eMQ+XbizhGhHoBMGTAkcplSuTL6Guugrqtpur5iofzz62U3Uq58NL6AgaWwY/JWlljbsRsKf43AJ+DOeNT+f8jiEWFspj/nK1EIGswGNWsMaFNJLBmbyc9OHHYOu7bzpyE9G4pABLIxQPsJagtUoEz5oKJyJouOWXWQIZdns6+AS+2xAIQxJBJMkkZ5mypC8hMkjKMaXkM1KJNBwBx8M8AyEFIdlKpnRvLgvP7WOSy0TVl7KzpV7ECgqIEBQmqomEAoPzQNv2vgvJHyeIDaYZIGQZQDyWz5ci9GT6oNcD8n1kQ+lLULQstG3rBsKvtnFovULpAAH/JLdnF0dX2q6S36XU0+S6HArstuoIQvnfKaTkbTZfmMYgkGQdKAN++5ytxadBAx7oYlPjEqyoAEMDN7gXJD+lSVD74uxlkpamm9QJozfjHrRkD2DTxO7P8k6wgLsEZkI/u55rWC/QGYezxfDEoH452bUGjvVzrsgBbITqVKASlslmloV0MGuuzNuQOshdAgEOg60nDGA6W6yQIsMTdI+0bZZijG+oFMB9KQ6r2ZkQuKZh9M8ulV2ITCBYZWHrgu5qbkRaIh3P87dViZdGIcmmL+mOVo7S2Y8Wy6oWt6UIPO9S31ezdwZnc5P5QqwnJY7lWL9AFgADilmY6h3K00iDhb4vJTwEGANC+26MCs7qQAAAAAElFTkSuQmCC + + + + UTF-8 + http://mobile.twitter.com/searches + diff --git a/mobile/android/locales/en-US/searchplugins/wikipedia.xml b/mobile/android/locales/en-US/searchplugins/wikipedia.xml new file mode 100644 index 00000000000..171c0f501ae --- /dev/null +++ b/mobile/android/locales/en-US/searchplugins/wikipedia.xml @@ -0,0 +1,14 @@ + +Wikipedia +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAACXBIWXMAAAsTAAALEwEAmpwYAAADGGlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjaY2BgnuDo4uTKJMDAUFBUUuQe5BgZERmlwH6egY2BmYGBgYGBITG5uMAxIMCHgYGBIS8/L5UBFTAyMHy7xsDIwMDAcFnX0cXJlYE0wJpcUFTCwMBwgIGBwSgltTiZgYHhCwMDQ3p5SUEJAwNjDAMDg0hSdkEJAwNjAQMDg0h2SJAzAwNjCwMDE09JakUJAwMDg3N+QWVRZnpGiYKhpaWlgmNKflKqQnBlcUlqbrGCZ15yflFBflFiSWoKAwMD1A4GBgYGXpf8EgX3xMw8BSMDVQYqg4jIKAUICxE+CDEESC4tKoMHJQODAIMCgwGDA0MAQyJDPcMChqMMbxjFGV0YSxlXMN5jEmMKYprAdIFZmDmSeSHzGxZLlg6WW6x6rK2s99gs2aaxfWMPZ9/NocTRxfGFM5HzApcj1xZuTe4FPFI8U3mFeCfxCfNN45fhXyygI7BD0FXwilCq0A/hXhEVkb2i4aJfxCaJG4lfkaiQlJM8JpUvLS19QqZMVl32llyfvIv8H4WtioVKekpvldeqFKiaqP5UO6jepRGqqaT5QeuA9iSdVF0rPUG9V/pHDBYY1hrFGNuayJsym740u2C+02KJ5QSrOutcmzjbQDtXe2sHY0cdJzVnJRcFV3k3BXdlD3VPXS8Tbxsfd99gvwT//ID6wIlBS4N3hVwMfRnOFCEXaRUVEV0RMzN2T9yDBLZE3aSw5IaUNak30zkyLDIzs+ZmX8xlz7PPryjYVPiuWLskq3RV2ZsK/cqSql01jLVedVPrHzbqNdU0n22VaytsP9op3VXUfbpXta+x/+5Em0mzJ/+dGj/t8AyNmf2zvs9JmHt6vvmCpYtEFrcu+bYsc/m9lSGrTq9xWbtvveWGbZtMNm/ZarJt+w6rnft3u+45uy9s/4ODOYd+Hmk/Jn58xUnrU+fOJJ/9dX7SRe1LR68kXv13fc5Nm1t379TfU75/4mHeY7En+59lvhB5efB1/lv5dxc+NH0y/fzq64Lv4T8Ffp360/rP8f9/AA0ADzT6lvFdAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAHqSURBVHjapJUxb9NQFIW/JAip2xNS1/J+goeqUqeajdGVmFgwI1OcmYEgITFG7EgJQ+b2HzgbElJF+QU2iBl7YAFRnQ5+fnFcB0J8Jp/r53vPu+f6vYEA4JBTTjhkN/zkio9kAAihpyr1v/ijN7ovEHqiffFeDHTAdx6wL46HnPX4HM6HHNEHR0NGvRKMhvRE7wT3ACYssBggpyThIRMCAFaEzHhOiQWumfGFBQGQY0kB9EKSCsVCyKpQxUMhdOEMj4Vi91wIGX2uyNJtwTDHAgbjOUBJ/T50ETDAzCn0CiRpLkSd2VW1rqZR6uOpzHoWl40EkmkIlTIhNJc0bUSlSNNtCaZCKGtpyDZimXB92uhBhTEAHzx/BuQ8Isb62Dti16c7PahrNnbovFhXLGQaau4oqDSULDx/BcCl55cEDTUdCqqagWcXbjpqWD8ZWxRUGq5ZOTYhAXLHV0DU/qCtQLJCkZuM0PHQGThvL152JJh5M61SP2CpMpmmgdsTFDJCiaaubq0haQ7Q3xLUZq4NqzS0DNzWxNq8ksgbFmGgwf95oFgijJuB6v9L3Fx2HSg3XeExZxv1xuSEXQt/o8fqg9cDHfB15zuxjRuOETrfu/5b9bhcf+mlRmLgr/cTgp1vqR9c8YlvALcDAPr5jIx+4LKcAAAAAElFTkSuQmCC + + + + + + + + +http://en.wikipedia.org/wiki/Special:Search + diff --git a/mobile/android/locales/en-US/searchplugins/yahoo.xml b/mobile/android/locales/en-US/searchplugins/yahoo.xml new file mode 100644 index 00000000000..ed3a4c3085c --- /dev/null +++ b/mobile/android/locales/en-US/searchplugins/yahoo.xml @@ -0,0 +1,13 @@ + +Yahoo +UTF-8 +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAA7xJREFUeNrs10tslFUUB/DfN9NCaUsir2JAQAQKBgQXiFEeC6JdKAQCoiERXKiJrmRhNMZH3LjQjaILIiqKCWp8BgL4IGpQWkASCY+qWHm0CFjKyz5oO9PO56LfDNNhpmXHwp7ky9w5c+49//ud//nfO0EYhq6nxVxnGwAwAOC6Ayh6IVjfX8wEzMBMlCDdt2fwM+rR1s8a03AIR3AAv+EYGov6mLQKq3FPP4s34AN8gt8LxAxBEaZHT9rq85XgiWh3H15DchiPl6JdfRQly7XLBebuyAXwBdaFwhtTQt1SmSclFOpXNVeiCVNy/Mk8sQfweTaAT7GsZxhkEnfp1qVbiFAQffZpZVEpKrJ8+absQU2aAw9hRUpK+YhSyzbOVzFjpNbGNsnWpGRnShjS3NBq85PVOiV6vY1AICZQrEhMAHFsxZwoJJEHwHdoKcJ9eDG9UKIlac+6WsMm3mDJW/My0V89+pOTv5zVrsOtd08wbu5o7Rc7BAFDRpQoLok7uOmoprpLYj3dfQfmYRdO5QGwTcTMx9LMDASSiS4Htx3XptPx7aetOfogqFw81jcb9goQL467ac4otz0wCbQ2tavffcb+9+tyebIiApBr9ehMC9G07F8CgVKDDVeu7thJG6u2g+lLJ1n+zAKdkqp31jq1r6lnG0/XeLniPeuXbHG+vkVcPHu5+QV4sjUjREjll8iYcqV27zhs5FPD3L/2LlWv3qnx4L9mrp5o1sop1s/d7EDNX8qUKjeop/q9bWgBAN9nA8grRgHiYsqV+fbNPW5eONr0JbdY9XWVjpaE1yo2aWg6a6gy8TT1rr3/f80+C+oK9VMgUCQmqcsPz+3P+Lc8vsuRpgalSsQKJ4fdeXx/RxzIAHgHfxR6CyG6hVKJ7oy//VynpJSUVF/J4bM8vkO9DiNswbBIz3tZKFQSG2TS+DEql4/L+CcvGisRT2qua3PheHME9So7nF1rjI5a88/soPgCi9OyOBuVvfUzZczM4R7+ssrY2aOc3n/OxRPNSkeWmHrveJdOtvin9mKhIsxGc9Z4MKpxIYugYfC8t3PPgmW9uiGIKR5SpP1yQjKS9Jj4Fc272lJYiJ1ZvjpMjsYfoxaz8G5uByzHGryeWS1M6bjcGdUrniFnDzuCfOr2CM5n+QZlJYdGvNLXjeiNaOVnsRfJtNbHxcQj3gdXkp/AhkhNF+UkF11ifkRr9L06l4SFbC32YWmk6eOyRCtAC2qiW9HW6A6Rz5qjs+Z2TM3tuGDgn9EAgP89gP8GAF3DLhLnfG5QAAAAAElFTkSuQmCC + + + + + + +http://search.yahoo.com/ + diff --git a/mobile/android/locales/en-US/updater/updater.ini b/mobile/android/locales/en-US/updater/updater.ini new file mode 100644 index 00000000000..dfa02573065 --- /dev/null +++ b/mobile/android/locales/en-US/updater/updater.ini @@ -0,0 +1,4 @@ +; This file is in the UTF-8 encoding +[Strings] +TitleText=%MOZ_APP_DISPLAYNAME% Update +InfoText=%MOZ_APP_DISPLAYNAME% is installing your updates and will start in a few moments… diff --git a/mobile/android/locales/filter.py b/mobile/android/locales/filter.py new file mode 100644 index 00000000000..a6db1b06230 --- /dev/null +++ b/mobile/android/locales/filter.py @@ -0,0 +1,69 @@ +# ***** 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 +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2009 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Axel Hecht +# +# 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 ***** + + +def test(mod, path, entity = None): + import re + # ignore anything but mobile, which is our local repo checkout name + if mod not in ("netwerk", "dom", "toolkit", "security/manager", + "services/sync", "mobile/android/base", + "mobile"): + return False + + # Ignore Lorentz strings, at least temporarily + if mod == "toolkit" and path == "chrome/mozapps/plugins/plugins.dtd": + if entity.startswith('reloadPlugin.'): return False + if entity.startswith('report.'): return False + + if mod != "mobile": + # we only have exceptions for mobile + return True + if not entity: + return not (re.match(r"searchplugins\/.+\.xml", path) or + re.match(r"mobile-l10n.js", path) or + re.match(r"defines.inc", path)) + if path == "defines.inc": + return entity != "MOZ_LANGPACK_CONTRIBUTORS" + + if path != "chrome/region.properties": + # only region.properties exceptions remain, compare all others + return True + + return not (re.match(r"browser\.search\.order\.[1-9]", entity) or + re.match(r"browser\.contentHandlers\.types\.[0-5]", entity) or + re.match(r"gecko\.handlerService\.schemes\.", entity) or + re.match(r"gecko\.handlerService\.defaultHandlersVersion", entity)) diff --git a/mobile/android/locales/generic/install.rdf b/mobile/android/locales/generic/install.rdf new file mode 100644 index 00000000000..3f7091d8d3b --- /dev/null +++ b/mobile/android/locales/generic/install.rdf @@ -0,0 +1,62 @@ + + + + + +#ifdef MOZ_LANGPACK_CONTRIBUTORS + @MOZ_LANGPACK_CONTRIBUTORS@ +#endif + + + + {a23983c0-fd0e-11dc-95ff-0800200c9a66} + @MOZ_APP_VERSION@ + @MOZ_APP_VERSION@ + + + + diff --git a/mobile/android/locales/generic/profile/bookmarks.json.in b/mobile/android/locales/generic/profile/bookmarks.json.in new file mode 100644 index 00000000000..c188e2285b3 --- /dev/null +++ b/mobile/android/locales/generic/profile/bookmarks.json.in @@ -0,0 +1,20 @@ +#filter substitution +{"type":"text/x-moz-place-container","root":"placesRoot","children": + [{"type":"text/x-moz-place-container","title":"@bookmarks_title@","annos":[{"name":"mobile/bookmarksRoot","expires":4,"type":1,"value":1}], + "children": + [ + {"index":1,"title":"@bookmarks_aboutBrowser@", "type":"text/x-moz-place", "uri":"about:firefox", + "iconUri":"chrome://branding/content/favicon32.png" + }, + {"index":2,"title":"@bookmarks_addons@", "type":"text/x-moz-place", "uri":"https://addons.mozilla.org/@AB_CD@/mobile/", + "icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAcXSURBVFjDxZdrjF1VFcd/a59z7r1z585M5+10oK19mDbSAoGEUprS0ZgISX3URqNpI5iYGJv4Av1gooYvBASF9JuKNiYmamIwGm3SNgj0AW1KhY6dPoAOnU6ZlnnPfd9zzt7LD/fMdIaWh0jDSXbOvTln7/1f//Vf/72OqCof5WX4iC///5nc96B0hOrvFKP3o9Kt4CM6CewD79HDj9VOvtca8kFTsOn70kMQvHLP+h2tK3o+GXS09AKOC2NneXW437109rlKqVbYevjn0b7rwoD1/d985e5vt/et2+ZVoiLVqIR1luXda2nKtppVN6xr/O2eh/8iIi36LlF+YAAibFjWs9o7NrgXYzx8E1CNyhSrU1TCImt676C9qVvWf290NXD6QwegihdGVapxkXKtgIqi6uoj+Y04CTzkulSBwu/633gxbs/14CRGsSgWh6Ul28pkaZSJmdGLBx6vnbo+ZajmV0cH9sdN2TaMCI4YJxYVS2fzjfS//kLFqjz5oZThpu9Ip017jwqyDQgAjECxUki9NTNEOpUmrJVRFAXSqQynLxxXT/TJjT8MnliAW4hE9a9xZH905El9630BcBnv4RW9a7bfe+f2IBM0IElWxRhiW2O0PIgjBgFFma5c5ltf/Gk2jKo4Z7HqsC7COUctrGQOnNjzteGRcwrc9/5EqPLlz67/ajBeukC+No6IYERAoGYrdUVIXRkKvDHVT2BSKODU4ZxFbR1IY9DCXTd/xv/TyODW9w8AUqkgxVT1EqGtzAMgdTYEVBVBcVIv+ZqLUNU6A85SCfOUagViG7Gy/XaA1P9Uhs5FOGJUYhCDE64AADD16FElchHlME8lzFMOC1SiEuoc6pTAa0CNRbVeAP7bxaYN3i5VPg0UBfl1JPEffHys1gE4YkAp1iaJXIgjwmqMaox1MbGLiF3IrPepQmtjN9255bSkO6nGZaSesYUANvxA2iTtvbT5li2965av9xDpHDh/9KEjA8/+pFQqpJxRnESoWN4snCG05TkGZtMwW9hGJGEDmtNdrGq7gxMnX66MXD5im5tz0tHZ0eikPmMOgOf531y+ZE3X3es+701WLmFEuG31ptTKZatTpdo0NZunagtYDYm0gvHqIhSTrCRXOSUofLx9HcdPHC1fGB56WmLvkbHKxJ1j4xPfMKLdCwCocH93V0/m+PBeanEBRMiHY6iJaQiaiPNVVCxWQ8SrR4khYWC2Lq/YZP2voSHI8ebwxcBW7c4ju+I8MAA8dZURqdK7KNfKaHGIYjiBMYLxPTwEG9Uwnkkcz2KM1COfAwBX1HhlwVzQSr48hYobP7JL8+/qhB6mIZ1qoJKfwWlcT6ZaYmtRF+PiCCcxjhDjJZubhRoQqUevCaWZVCPF8jSIXHpPK3aiMxOly21iDIXqBBgHxtXp9qTOiFffdPZeZ+AKE2/Pv6VGc3MGtbpGHhKjP1P3LmeBnrg8dnFzW0ezjJVifOPT3tRLZ9ONZFNNTFYvMlI6884gZMFJCQpVnaEp20JDY9puKMrX+x6SP1aL/kbf0x1glhx8JOyba8k2PhD0pTKZf9x2y23Z1tY2nFompycYeXOkVCjn+VRfX+PJ8WfAuCsgDLQ19NKRXULab0REqNkSU9URJqrDOOvoyqzEVJs4dvjfpZmZYraxOVNYfGNn7rWBYTn8eGQW9IQbH/A/hydPiZgWVBXDiy7i94ju/sKXtnBm8iBqIowneEZYuuhWCH1eGzxrR86Pl2zszMeWtWVWrVzpZ3NpBmeO46yjLbWERanFqBWcKnEYse+fz9lDj0X+Aic89Iv470DXHT+W9kUR1b2PaAngrgeD3U5jEJ2juyu3gmre8uz+Q2XU7lYnf7ZIaej02Nah06M712++taWna5WMFM4yUbvAWHkIcT7qDDc03jSn1WueBUcf1omrm0C3QO3N6Q4OPH+sqKG97/Av7dPz3nx5w3eDv71yZOBf92y7OydGEKeIgCPGSICqRZKjw7xz0ykiIkZEDMmxOms2Yjx8STE9VUhNXLYvAOlkZIDMmT3R2Uq51uCcJfDSdYOas2vBqQXByezi19jcJJ1PGmgQwcZxSEOQw4iPwSPUCm2duVo6MFuATqArGd09N3v3ZltS5dnVA5PCkwAjPmkvSxTHIMSA718r8mTzXBKRp04OnBw4tfmmtWvE8w3igbOOxUs7m946X9gB7vUkPg8g08L27qWLcrW4Snf6E2igWFWIIY4sp/7zqotr+jyQvpYGJNFGFmgC/PMH3RNxZbz94rkDa+fecICgzspi4Pak/F3dh+SGc/2jOtg/qjhkwUElaG1aTp/bb58BWq76NEsYSAMtCYgg0Yo3L9d+AsMkQ4EYiBIQJPOCec/n+1QMTAHD1/w2FBEvaZmCZGOZx4z/DuKNATtvM3/e3KsaLKAKFP8LDkBq6lXFt0cAAAAASUVORK5CYII=" + }, + {"index":3,"title":"@bookmarks_support@", "type":"text/x-moz-place", "uri":"http://support.mozilla.com/@AB_CD@/mobile", + "icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAIYElEQVRYw5VXCVBUVxb9NZUqzWQWlVVl07hk3KKTmLikNMYoIAgiiGyuIBBHDSqOM2piYhCFGI0KLuNCEElRarMKDQ0NguiAiEJAIqKARjQ4fFmCC9Bw5r73f3fTIQTsqst7/fn97rnnrk8AcJdE7I9oNBrx1q1a8dz5HPHLr86IW7YeF4O3HBP/vf2kePCQQszNKxXrnzSK/T2P6RboTwv6+Dx61IAD316Arf1WWI/0hLGZC4aYLuKrsdliGNF+iMkimFsswcTJfghcewAEBhpNZ19Htwgykt/8NDe3YueX32HcxFWkxAXmw91gNcITNm96yeIti7S3HukFC+ulHBgD4+i0DVeulv8eALFXANeLK/GxbTAGGTvToR7dlHl3A+AF6257g+cExnToYg4odE8sOjo0/QegyiyCzShvOsC1h8LhVkthYr4Y5iSWxIi1pRsshrvCjKxm71vYeBi8b0mMDTJyxirfcPzyy/O+AeTmlmAEKR9m6W5A7zBSbEYKZk8PxOYNB3EsWoXvLl7D6YybiEouROTJNKz1C8PUyathQnFhyYCM0oP/q5ET/Pz3obOzq3cAVVUPMXbcSgwl/3W33JisnTHVHzHRSpyuaoT3HQ3Gl2pgXtQOo2ttGHq9E1PKgNVVwPcVTThyUIFxY31gOsyNG6M9iwVqyO6Y3wbAItZ7WSgPoO7I2fdl7juRVvkz3O4BQnYrBFUzhEySLBJ1G+0fQ1DmQEhNw2vqYvjWdiKpoBoO8zbChFjTgmABbEZuy8oq7gmAcpsj7B7hTPl6v71Ie/ISRv99CSGjiRQ26yWbPbsCIdEHQvxHsnwMQeGPsdcroKxpxYK5QZwJGxmEGe3nzN2EtrZ2PYD29g6K+C08zbR0mQ9fAnv6cc7jVlJOlmd2kEIS9XNZ+Qt6dpMU2pPMhZCwQC8MyPmFBKIM6tJHeHvCCp4N2rNNh7lCmV6oB1BQWEFB5s6LjDafLS2XIFFVjEnkWyGN0RtJaywpLSflbZL1qlKyfgkp/FBW7kBiK60M1AUfON97htgYNQ9gLbMsi7x8dpPqLgnAZzujeDXT0s/SKWB5CI49IeWpqdJh8bNIZkuHK89IDDAQWQ8gpOyi/82X/pe4VAbiIL2fdhxn7ndi3qz1lMLu/HwWC6PfWo779+tFgQqEaO/wL065jn6iKCWlEDPKyecKOjB+nv5QZiGzOEMtMaFmQNohJK+n/y0khm4TCE96x1Z6V+EGh8pGhO2Jo/R0MQju8xdyRaGurkF8a/xKKW9Z4aB18sSVUFY24fVLBd3862Do4+QgKSPULXIwXoWQriR2FPI79tKqmAOLghx8ryynguWmcwNj/PMvokSh/FaNyCLUaqSnXOncYTt7PU5Ud0hWMmU6AHb0fY4kCY6StdksKImpbHJXukqOB3s9YMWHGJj1HyRXNHLDLG08dXGwdt1BUSguviNa2CzlgccAsCLkYh+MwzUaAlAs079AojRxBSlJJp/vlGIiI192Q7PkhoshpHC6DKAbW2m7oPypDTPfD5SzwYvqw2JWnkXh5s0q0WqEhy4DhlIJdrLdjKO1z6VCw3zLg5AkZatkKQvA9HRioIL2z2QAz6XvzDU8AOdIbChm47X0fciofYFp7/rr0tHE3BW+a74WhduVD8SRo310bZa9MGtaIM5VN0K41EVWZtOB86UCk+RHyui5ulWymK26wtQk14hWKVXTL5LlUfQ7BwzJPY/kojqMGeWlczWbIzYERYjC06ct4pR3/OWWK6XIKFrzS6thRTVeyKgiAM4S5amH9JT3Ki1yZnRKgBIC8P4PVTgbdxmm5i66ls6qLrVpqQ6sWh3OBw4tCLY/+u05fFpHdCvv0SFO5H9XsqxGXwn7FAZEpLhQIuxRFzasCZfbuxRrvCeoiyUAioTLvM//fWoAr9WsJsyeuRZ5dS0YkEsKE4n6lO1yKe6H8kxZyB2TbgGFP1KXHWPo5klT1qChoVkC0Nr6AumqaygoqMCJkxf5UDHgj3bYHxqD0AZiIYkqX8pe2e+/o1hFcXCpFeNLNAi804bD5Q1QldTgk4B9vCtqCx1j+NONEYbdMCw8jveDU1FKZOfc4LX6HYqNtOR8bHpIilOpKGW19GJxE/6Q+wzuVZ2Iud2A4zGZ8PX5Ch/QDDGaAq/7cMNYYAyUlNw1BKBIyJOGSfLN1/vikJFxDersGzjwTRxuFP2I4LsaDGDKWEtWaUX6PqboJWIq/4eI/XH44D1//XhGin49xDLrl6/a23MeYOPSIBqbWD1gVYqBmfJuAE6cSsXVK2VsZEE5TVO+NYBjZRfsSRwqOxFQC2RX1cNu1joMpgGWxZLh1KzfMyb+NmElqmse9wTw08MnsF2wFUZmLrofssMYqMORCXjwoB5pSXk4EBaL8NCzCKdJd09INLZtjsC8j4J48HafpAwBeNNw6sFZUSjyep8J6+ufwo4642B5MmJV0dF5O5/tWYke+IY9D86Bb9jxVbv/y+CFPHOseyj35qBYg2PN59Dh+L6nYkoNCsAQXihYUL43/R/Izy/DN/vPIYQsp2sYtvzzGL7YFY09e2Oxm5jY/tkpeHqH4M0xy+SeorecxRSj/sjRpP7fC9glgu59PBaYX6fNWIeAT/aD7oF0U4qWgGw7gY2bIhFEsuPz04g5q8L0met0zYatg03ot/SMCs6r34zYJ01ZAKdFOziFA/9kj9dJ/jzIkbPDwGnFWBf1HjzfWZ2f8LYvdhAzDQ1NfV7N+ryc3qH7QuSRRM7C3PnBumLC/M7ugEZmEpCx41bQaL8bZ2JUoFsy+vHhl9O7r3CdZhO0+ENZtUhuEB0WbhMpaMUNGyPE+ITLYu39n1/las6v5/8HR4lI9EcypCoAAAAASUVORK5CYII=" + }, + {"index":4,"title":"@bookmarks_aboutHome@", "type":"text/x-moz-place", "uri":"about:home", + "iconUri":"chrome://branding/content/favicon32.png" + } + ] + }] +} diff --git a/mobile/android/locales/jar.mn b/mobile/android/locales/jar.mn new file mode 100644 index 00000000000..8146f06fc9a --- /dev/null +++ b/mobile/android/locales/jar.mn @@ -0,0 +1,34 @@ +#filter substitution + +@AB_CD@.jar: +% locale browser @AB_CD@ %locale/@AB_CD@/browser/ + locale/@AB_CD@/browser/about.dtd (%chrome/about.dtd) + locale/@AB_CD@/browser/aboutAddons.dtd (%chrome/aboutAddons.dtd) + locale/@AB_CD@/browser/aboutAddons.properties (%chrome/aboutAddons.properties) + locale/@AB_CD@/browser/aboutCertError.dtd (%chrome/aboutCertError.dtd) + locale/@AB_CD@/browser/aboutHome.dtd (%chrome/aboutHome.dtd) + locale/@AB_CD@/browser/browser.dtd (%chrome/browser.dtd) + locale/@AB_CD@/browser/browser.properties (%chrome/browser.properties) + locale/@AB_CD@/browser/config.dtd (%chrome/config.dtd) + locale/@AB_CD@/browser/config.properties (%chrome/config.properties) + locale/@AB_CD@/browser/localepicker.properties (%chrome/localepicker.properties) + locale/@AB_CD@/browser/region.properties (%chrome/region.properties) + locale/@AB_CD@/browser/preferences.dtd (%chrome/preferences.dtd) + locale/@AB_CD@/browser/checkbox.dtd (%chrome/checkbox.dtd) + locale/@AB_CD@/browser/notification.dtd (%chrome/notification.dtd) + locale/@AB_CD@/browser/sync.dtd (%chrome/sync.dtd) + locale/@AB_CD@/browser/sync.properties (%chrome/sync.properties) + locale/@AB_CD@/browser/prompt.dtd (%chrome/prompt.dtd) + locale/@AB_CD@/browser/webapps.dtd (%chrome/webapps.dtd) + locale/@AB_CD@/browser/feedback.dtd (%chrome/feedback.dtd) + locale/@AB_CD@/browser/phishing.dtd (%chrome/phishing.dtd) + locale/@AB_CD@/browser/bookmarks.json (bookmarks.json) + locale/@AB_CD@/browser/searchplugins/list.txt (%searchplugins/list.txt) + +# Fennec-specific overrides of generic strings +* locale/@AB_CD@/browser/netError.dtd (%chrome/overrides/netError.dtd) +% override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd +* locale/@AB_CD@/browser/appstrings.properties (%chrome/overrides/appstrings.properties) +% override chrome://global/locale/appstrings.properties chrome://browser/locale/appstrings.properties +* locale/@AB_CD@/browser/passwordmgr.properties (%chrome/overrides/passwordmgr.properties) +% override chrome://passwordmgr/locale/passwordmgr.properties chrome://browser/locale/passwordmgr.properties diff --git a/mobile/android/locales/l10n-central.ini b/mobile/android/locales/l10n-central.ini new file mode 100644 index 00000000000..c89778472fe --- /dev/null +++ b/mobile/android/locales/l10n-central.ini @@ -0,0 +1,31 @@ ++[general] +depth = ../.. +source-depth = .. +all = locales/all-locales + +[compare] +dirs = mobile/android +tld = mobile/android + +[includes] +toolkit = toolkit/locales/l10n.ini +services_sync = services/sync/locales/l10n.ini +embedding_android = mobile/android/base/locales/l10n.ini + +[include_toolkit] +type = hg +mozilla = mozilla-central +repo = http://hg.mozilla.org/ +l10n.ini = toolkit/locales/l10n.ini + +[include_services_sync] +type = hg +mozilla = mozilla-central +repo = http://hg.mozilla.org/ +l10n.ini = services/sync/locales/l10n.ini + +[include_embedding_android] +type = hg +mozilla = mozilla-central +repo = http://hg.mozilla.org/ +l10n.ini = mobile/android/base/locales/l10n.ini diff --git a/mobile/android/locales/l10n-mozilla-1.9.2.ini b/mobile/android/locales/l10n-mozilla-1.9.2.ini new file mode 100644 index 00000000000..6943a4cac3d --- /dev/null +++ b/mobile/android/locales/l10n-mozilla-1.9.2.ini @@ -0,0 +1,17 @@ +[general] +depth = ../.. +source-depth = .. +all = locales/all-locales + +[compare] +dirs = mobile/android +tld = mobile/android + +[includes] +toolkit = toolkit/locales/l10n.ini + +[include_toolkit] +type = hg +mozilla = releases/mozilla-1.9.2 +repo = http://hg.mozilla.org/ +l10n.ini = toolkit/locales/l10n.ini diff --git a/mobile/android/locales/l10n-mozilla-2.0.ini b/mobile/android/locales/l10n-mozilla-2.0.ini new file mode 100644 index 00000000000..b9cfcdb331a --- /dev/null +++ b/mobile/android/locales/l10n-mozilla-2.0.ini @@ -0,0 +1,31 @@ +[general] +depth = ../.. +source-depth = .. +all = locales/all-locales + +[compare] +dirs = mobile/android +tld = mobile/android + +[includes] +toolkit = toolkit/locales/l10n.ini +services_sync = services/sync/locales/l10n.ini +embedding_android = mobile/android/base/locales/l10n.ini + +[include_toolkit] +type = hg +mozilla = releases/mozilla-2.0 +repo = http://hg.mozilla.org/ +l10n.ini = toolkit/locales/l10n.ini + +[include_services_sync] +type = hg +mozilla = releases/mozilla-2.0 +repo = http://hg.mozilla.org/ +l10n.ini = services/sync/locales/l10n.ini + +[include_embedding_android] +type = hg +mozilla = releases/mozilla-2.0 +repo = http://hg.mozilla.org/ +l10n.ini = mobile/android/base/locales/l10n.ini diff --git a/mobile/android/locales/l10n.ini b/mobile/android/locales/l10n.ini new file mode 100644 index 00000000000..b4fbbbab1b2 --- /dev/null +++ b/mobile/android/locales/l10n.ini @@ -0,0 +1,11 @@ +[general] +depth = ../.. +all = mobile/android/locales/all-locales + +[compare] +dirs = mobile/android + +[includes] +toolkit = toolkit/locales/l10n.ini +services_sync = services/sync/locales/l10n.ini +embedding_android = mobile/android/base/locales/l10n.ini diff --git a/mobile/android/locales/maemo-locales b/mobile/android/locales/maemo-locales new file mode 100644 index 00000000000..5609e3a7f81 --- /dev/null +++ b/mobile/android/locales/maemo-locales @@ -0,0 +1,13 @@ +cs +da +de +es-ES +fi +fr +ja +it +nb-NO +nl +pl +pt-PT +ru diff --git a/mobile/android/makefiles.sh b/mobile/android/makefiles.sh new file mode 100644 index 00000000000..117a33af64b --- /dev/null +++ b/mobile/android/makefiles.sh @@ -0,0 +1,61 @@ +# ***** 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 . +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Finkle +# +# 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 ***** + +add_makefiles " +netwerk/locales/Makefile +dom/locales/Makefile +toolkit/locales/Makefile +security/manager/locales/Makefile +mobile/android/app/Makefile +mobile/android/app/profile/extensions/Makefile +$MOZ_BRANDING_DIRECTORY/Makefile +$MOZ_BRANDING_DIRECTORY/locales/Makefile +mobile/android/chrome/Makefile +mobile/android/chrome/tests/Makefile +mobile/android/components/Makefile +mobile/android/components/build/Makefile +mobile/android/modules/Makefile +mobile/android/installer/Makefile +mobile/android/locales/Makefile +mobile/android/Makefile +mobile/android/themes/core/Makefile" + +if test -n "$MOZ_UPDATE_PACKAGING"; then + add_makefiles " + tools/update-packaging/Makefile + " +fi diff --git a/mobile/android/modules/LocaleRepository.jsm b/mobile/android/modules/LocaleRepository.jsm new file mode 100644 index 00000000000..dae7098b266 --- /dev/null +++ b/mobile/android/modules/LocaleRepository.jsm @@ -0,0 +1,351 @@ +/* ***** 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. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * Wes Johnston + * + * 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 ***** */ + +let EXPORTED_SYMBOLS = ["LocaleRepository"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AddonManager.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); + +// A map between XML keys to LocaleSearchResult keys for string values +// that require no extra parsing from XML +const STRING_KEY_MAP = { + name: "name", + target_locale: "targetLocale", + version: "version", + icon: "iconURL", + homepage: "homepageURL", + support: "supportURL", + strings: "strings" +}; + +var LocaleRepository = { + loggingEnabled: false, + + log: function(aMessage) { + if (this.loggingEnabled) + dump(aMessage + "\n"); + }, + + _getUniqueDescendant: function _getUniqueDescendant(aElement, aTagName) { + let elementsList = aElement.getElementsByTagName(aTagName); + return (elementsList.length == 1) ? elementsList[0] : null; + }, + + _getTextContent: function _getTextContent(aElement) { + let textContent = aElement.textContent.trim(); + return (textContent.length > 0) ? textContent : null; + }, + + _getDescendantTextContent: function _getDescendantTextContent(aElement, aTagName) { + let descendant = this._getUniqueDescendant(aElement, aTagName); + return (descendant != null) ? this._getTextContent(descendant) : null; + }, + + getLocales: function getLocales(aCallback, aFilters) { + let url = Services.prefs.getCharPref("extensions.getLocales.get.url"); + + if (!url) { + aCallback([]); + return; + } + + let buildID = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).QueryInterface(Ci.nsIXULRuntime).appBuildID; + if (aFilters) { + if (aFilters.buildID) + buildID = aFilters.buildID; + } + buildID = buildID.substring(0,4) + "-" + buildID.substring(4).replace(/\d{2}(?=\d)/g, "$&-"); + url = url.replace(/%BUILDID_EXPANDED%/g, buildID); + url = Services.urlFormatter.formatURL(url); + + let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); + request.mozBackgroundRequest = true; + request.open("GET", url, true); + request.overrideMimeType("text/xml"); + + let self = this; + request.addEventListener("readystatechange", function () { + if (request.readyState == 4) { + if (request.status == 200) { + self.log("---- got response") + let documentElement = request.responseXML.documentElement; + let elements = documentElement.getElementsByTagName("addon"); + let totalResults = elements.length; + let parsedTotalResults = parseInt(documentElement.getAttribute("total_results")); + if (parsedTotalResults >= totalResults) + totalResults = parsedTotalResults; + + // TODO: Create a real Skip object from installed locales + self._parseLocales(elements, totalResults, { ids: [], sourceURIs: [] }, aCallback); + } else { + Cu.reportError("Locale Repository: Error getting locale from AMO [" + request.status + "]"); + } + } + }, false); + + request.send(null); + }, + + _parseLocale: function _parseLocale(aElement, aSkip) { + let skipIDs = (aSkip && aSkip.ids) ? aSkip.ids : []; + let skipSourceURIs = (aSkip && aSkip.sourceURIs) ? aSkip.sourceURIs : []; + + let guid = this._getDescendantTextContent(aElement, "guid"); + if (guid == null || skipIDs.indexOf(guid) != -1) + return null; + + let addon = new LocaleSearchResult(guid); + let result = { + addon: addon, + xpiURL: null, + xpiHash: null + }; + + let self = this; + for (let node = aElement.firstChild; node; node = node.nextSibling) { + if (!(node instanceof Ci.nsIDOMElement)) + continue; + + let localName = node.localName; + + // Handle case where the wanted string value is located in text content + // but only if the content is not empty + if (localName in STRING_KEY_MAP) { + addon[STRING_KEY_MAP[localName]] = this._getTextContent(node) || addon[STRING_KEY_MAP[localName]]; + continue; + } + + // Handle cases that aren't as simple as grabbing the text content + switch (localName) { + case "type": + // Map AMO's type id to corresponding string + let id = parseInt(node.getAttribute("id")); + switch (id) { + case 5: + addon.type = "language"; + break; + default: + this.log("Unknown type id when parsing addon: " + id); + } + break; + case "authors": + let authorNodes = node.getElementsByTagName("author"); + Array.forEach(authorNodes, function(aAuthorNode) { + let name = self._getDescendantTextContent(aAuthorNode, "name"); + if (name == null) + name = self._getTextContent(aAuthorNode); + let link = self._getDescendantTextContent(aAuthorNode, "link"); + if (name == null && link == null) + return; + + let author = { name: name, link: link }; + if (addon.creator == null) { + addon.creator = author; + } else { + if (addon.developers == null) + addon.developers = []; + + addon.developers.push(author); + } + }); + break; + case "status": + let repositoryStatus = parseInt(node.getAttribute("id")); + if (!isNaN(repositoryStatus)) + addon.repositoryStatus = repositoryStatus; + break; + case "all_compatible_os": + let nodes = node.getElementsByTagName("os"); + addon.isPlatformCompatible = Array.some(nodes, function(aNode) { + let text = aNode.textContent.toLowerCase().trim(); + return text == "all" || text == Services.appinfo.OS.toLowerCase(); + }); + break; + case "install": + // No os attribute means the xpi is compatible with any os + if (node.hasAttribute("os") && node.getAttribute("os")) { + let os = node.getAttribute("os").trim().toLowerCase(); + // If the os is not ALL and not the current OS then ignore this xpi + if (os != "all" && os != Services.appinfo.OS.toLowerCase()) + break; + } + + let xpiURL = this._getTextContent(node); + if (xpiURL == null) + break; + + if (skipSourceURIs.indexOf(xpiURL) != -1) + return null; + + result.xpiURL = xpiURL; + try { + addon.sourceURI = NetUtil.newURI(xpiURL); + } catch(ex) { + this.log("Addon has invalid uri: " + addon.sourceURI); + addon.sourceURI = null; + } + + let size = parseInt(node.getAttribute("size")); + addon.size = (size >= 0) ? size : null; + + let xpiHash = node.getAttribute("hash"); + if (xpiHash != null) + xpiHash = xpiHash.trim(); + result.xpiHash = xpiHash ? xpiHash : null; + break; + } + } + + return result; + }, + + _parseLocales: function _parseLocales(aElements, aTotalResults, aSkip, aCallback) { + let self = this; + let results = []; + for (let i = 0; i < aElements.length; i++) { + let element = aElements[i]; + + // Ignore add-ons not compatible with this Application + let tags = this._getUniqueDescendant(element, "compatible_applications"); + if (tags == null) + continue; + + let applications = tags.getElementsByTagName("appID"); + let compatible = Array.some(applications, function(aAppNode) { + if (self._getTextContent(aAppNode) != Services.appinfo.ID) + return false; + + let parent = aAppNode.parentNode; + let minVersion = self._getDescendantTextContent(parent, "min_version"); + let maxVersion = self._getDescendantTextContent(parent, "max_version"); + if (minVersion == null || maxVersion == null) + return false; + + let currentVersion = Services.appinfo.version; + return (Services.vc.compare(minVersion, currentVersion) <= 0 && Services.vc.compare(currentVersion, maxVersion) <= 0); + }); + + if (!compatible) + continue; + + // Add-on meets all requirements, so parse out data + let result = this._parseLocale(element, aSkip); + if (result == null) + continue; + + // Ignore add-on missing a required attribute + let requiredAttributes = ["id", "name", "version", "type", "targetLocale", "sourceURI"]; + if (requiredAttributes.some(function(aAttribute) !result.addon[aAttribute])) + continue; + + // Add only if the add-on is compatible with the platform + if (!result.addon.isPlatformCompatible) + continue; + + // Add only if there was an xpi compatible with this OS + if (!result.xpiURL) + continue; + + results.push(result); + + // Ignore this add-on from now on by adding it to the skip array + aSkip.ids.push(result.addon.id); + } + + // Immediately report success if no AddonInstall instances to create + let pendingResults = results.length; + if (pendingResults == 0) { + aCallback([]); + return; + } + + // Create an AddonInstall for each result + let self = this; + results.forEach(function(aResult) { + let addon = aResult.addon; + let callback = function(aInstall) { + aResult.addon.install = aInstall; + pendingResults--; + if (pendingResults == 0) + aCallback(results); + } + + if (aResult.xpiURL) { + AddonManager.getInstallForURL(aResult.xpiURL, callback, + "application/x-xpinstall", aResult.xpiHash, + addon.name, addon.iconURL, addon.version); + } else { + callback(null); + } + }); + } +}; + +function LocaleSearchResult(aId) { + this.id = aId; +} + +LocaleSearchResult.prototype = { + id: null, + type: null, + targetLocale: null, + name: null, + addon: null, + version: null, + iconURL: null, + install: null, + sourceURI: null, + repositoryStatus: null, + size: null, + strings: "", + updateDate: null, + isCompatible: true, + isPlatformCompatible: true, + providesUpdatesSecurely: true, + blocklistState: Ci.nsIBlocklistService.STATE_NOT_BLOCKED, + appDisabled: false, + userDisabled: false, + scope: AddonManager.SCOPE_PROFILE, + isActive: true, + pendingOperations: AddonManager.PENDING_NONE, + permissions: 0 +}; diff --git a/mobile/android/modules/Makefile.in b/mobile/android/modules/Makefile.in new file mode 100644 index 00000000000..98472a4182b --- /dev/null +++ b/mobile/android/modules/Makefile.in @@ -0,0 +1,55 @@ +# ***** 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 +# the Mozilla Foundation . +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Finkle +# +# 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 + +EXTRA_JS_MODULES = \ + LocaleRepository.jsm \ + linuxTypes.jsm \ + video.jsm \ + $(NULL) + +EXTRA_PP_JS_MODULES = \ + contacts.jsm \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/mobile/android/modules/contacts.jsm b/mobile/android/modules/contacts.jsm new file mode 100644 index 00000000000..56846125628 --- /dev/null +++ b/mobile/android/modules/contacts.jsm @@ -0,0 +1,158 @@ +/* ***** 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. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * 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 ***** */ + +let EXPORTED_SYMBOLS = ["Contacts"]; + +const Cu = Components.utils; + +let Contacts = { + _providers: [], + _contacts: [], + + _load: function _load() { + this._contacts = []; + + this._providers.forEach(function(provider) { + this._contacts = this._contacts.concat(provider.getContacts()); + }, this) + }, + + init: function init() { + // Not much to do for now + this._load(); + }, + + refresh: function refresh() { + // Pretty simple for now + this._load(); + }, + + addProvider: function(aProvider) { + this._providers.push(aProvider); + this.refresh(); + }, + + find: function find(aMatch) { + let results = []; + + if (!this._contacts.length) + return results; + + for (let field in aMatch) { + // Simple string-only partial matching + let match = aMatch[field]; + this._contacts.forEach(function(aContact) { + if (field in aContact && aContact[field].indexOf(match) != -1) + results.push(aContact); + }); + } + return results; + } +}; + +#ifndef ANDROID +#ifndef XP_MACOSX +#ifdef XP_UNIX +Cu.import("resource://gre/modules/ctypes.jsm"); +Cu.import("resource:///modules/linuxTypes.jsm"); + +function EBookProvider() { + EBook.init(); +} + +EBookProvider.prototype = { + getContacts: function() { + if (!EBook.lib) { + Cu.reportError("EBook not loaded") + return []; + } + + let gError = new GLib.GError.ptr; + let book = EBook.openSystem(gError.address()); + if (!book) { + Cu.reportError("EBook.openSystem: " + gError.contents.message.readString()) + return []; + } + + if (!EBook.openBook(book, false, gError.address())) { + Cu.reportError("EBook.openBook: " + gError.contents.message.readString()) + return []; + } + + let query = EBook.queryAnyFieldContains(""); + if (query) { + let gList = new GLib.GList.ptr(); + if (!EBook.getContacts(book, query, gList.address(), gError.address())) { + Cu.reportError("EBook.getContacts: " + gError.contents.message.readString()) + return []; + } + + let contacts = []; + while (gList && !gList.isNull()) { + let fullName = EBook.getContactField(gList.contents.data, EBook.E_CONTACT_FULL_NAME); + if (!fullName.isNull()) { + let contact = {}; + contact.fullName = fullName.readString(); + contact.emails = []; + contact.phoneNumbers = []; + + for (let emailIndex=EBook.E_CONTACT_EMAIL_FIRST; emailIndex<=EBook.E_CONTACT_EMAIL_LAST; emailIndex++) { + let email = EBook.getContactField(gList.contents.data, emailIndex); + if (!email.isNull()) + contact.emails.push(email.readString()); + } + + for (let phoneIndex=EBook.E_CONTACT_PHONE_FIRST; phoneIndex<=EBook.E_CONTACT_PHONE_LAST; phoneIndex++) { + let phone = EBook.getContactField(gList.contents.data, phoneIndex); + if (!phone.isNull()) + contact.phoneNumbers.push(phone.readString()); + } + + contacts.push(contact); + } + gList = ctypes.cast(gList.contents.next, GLib.GList.ptr); + } + return contacts; + } + return []; + } +}; + +Contacts.addProvider(new EBookProvider); +# XP_UNIX +#endif +#endif +#endif diff --git a/mobile/android/modules/linuxTypes.jsm b/mobile/android/modules/linuxTypes.jsm new file mode 100644 index 00000000000..288670adeec --- /dev/null +++ b/mobile/android/modules/linuxTypes.jsm @@ -0,0 +1,116 @@ +/* ***** 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. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * 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 ***** */ + +let EXPORTED_SYMBOLS = ["GLib", "EBook"]; + +const Cu = Components.utils; + +Cu.import("resource://gre/modules/ctypes.jsm"); + +let GLib = { + lib: null, + + init: function glib_init() { + if (this.lib) + return; + + this.lib = true; // TODO hook up the real glib + + this.GError = new ctypes.StructType("GError", [ + {"domain": ctypes.int32_t}, + {"code": ctypes.int32_t}, + {"message": ctypes.char.ptr} + ]); + + this.GList = new ctypes.StructType("GList", [ + {"data": ctypes.voidptr_t}, + {"next": ctypes.voidptr_t}, + {"prev": ctypes.voidptr_t} + ]); + } +}; + +let EBook = { + lib: null, + + E_CONTACT_FULL_NAME: 4, + E_CONTACT_EMAIL_1: 8, + E_CONTACT_EMAIL_2: 9, + E_CONTACT_EMAIL_3: 10, + E_CONTACT_EMAIL_4: 11, + E_CONTACT_PHONE_BUSINESS: 17, + E_CONTACT_PHONE_BUSINESS_2: 18, + E_CONTACT_PHONE_HOME: 23, + E_CONTACT_PHONE_HOME_2: 24, + E_CONTACT_PHONE_MOBILE: 27, + + E_CONTACT_EMAIL_FIRST: 8, + E_CONTACT_EMAIL_LAST: 11, + E_CONTACT_PHONE_FIRST: 16, + E_CONTACT_PHONE_LAST: 34, + + init: function ebook_init() { + if (this.lib) + return; + + GLib.init(); + + try { + // Shipping on N900 + this.lib = ctypes.open("libebook-1.2.so.5"); + } catch (e) { + try { + // Shipping on Ubuntu + this.lib = ctypes.open("libebook-1.2.so.9"); + } catch (e) { + Cu.reportError("EBook: couldn't load libebook:\n" + e) + this.lib = null; + return; + } + } + + this.EBook = new ctypes.StructType("EBook"); + this.EQuery = new ctypes.StructType("EQuery"); + + this.openSystem = this.lib.declare("e_book_new_system_addressbook", ctypes.default_abi, EBook.EBook.ptr, GLib.GError.ptr.ptr); + this.openBook = this.lib.declare("e_book_open", ctypes.default_abi, ctypes.bool, EBook.EBook.ptr, ctypes.bool, GLib.GError.ptr.ptr); + + this.queryAnyFieldContains = this.lib.declare("e_book_query_any_field_contains", ctypes.default_abi, EBook.EQuery.ptr, ctypes.char.ptr); + + this.getContacts = this.lib.declare("e_book_get_contacts", ctypes.default_abi, ctypes.bool, EBook.EBook.ptr, EBook.EQuery.ptr, GLib.GList.ptr.ptr, GLib.GError.ptr.ptr); + this.getContactField = this.lib.declare("e_contact_get_const", ctypes.default_abi, ctypes.char.ptr, ctypes.voidptr_t, ctypes.uint32_t); + } +}; diff --git a/mobile/android/modules/video.jsm b/mobile/android/modules/video.jsm new file mode 100644 index 00000000000..df208be487f --- /dev/null +++ b/mobile/android/modules/video.jsm @@ -0,0 +1,5 @@ +var EXPORTED_SYMBOLS = ["Video"]; + +var Video = { + fullScreenSourceElement: null +}; diff --git a/mobile/android/themes/core/Makefile.in b/mobile/android/themes/core/Makefile.in new file mode 100644 index 00000000000..b692a414a54 --- /dev/null +++ b/mobile/android/themes/core/Makefile.in @@ -0,0 +1,46 @@ +# ***** BEGIN LICENSE BLOCK ***** +# ***** 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 +# the Mozilla Foundation . +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Finkle +# +# 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 + +include $(topsrcdir)/config/rules.mk diff --git a/mobile/android/themes/core/about.css b/mobile/android/themes/core/about.css new file mode 100644 index 00000000000..8855a475ec8 --- /dev/null +++ b/mobile/android/themes/core/about.css @@ -0,0 +1,46 @@ +html { + background: #f0f0f0; + padding: 0 1em; + font-family: "Nokia Sans", Tahoma, sans-serif !important; + font-size: 100% !important; +} + +body { + color: black; + position: relative; + min-width: 330px; + max-width: 50em; + margin: 1em auto; + border: 1px solid gray; + -moz-border-radius: 10px; + padding: 3em; + -moz-padding-start: 30px; + background: white; +} + +.aboutPageWideContainer { + max-width: 80%; +} + +#aboutLogoContainer { + border: 1px solid lightgray; + width: 300px; + margin-bottom: 2em; +} + +img { + border: 0; +} + +#version { + font-weight: bold; + color: #909090; + margin: -24px 0 9px 17px; +} + +ul { + margin: 0; + -moz-margin-start: 1.5em; + padding: 0; + list-style: square; +} diff --git a/mobile/android/themes/core/aboutAddons.css b/mobile/android/themes/core/aboutAddons.css new file mode 100644 index 00000000000..e2eef93056c --- /dev/null +++ b/mobile/android/themes/core/aboutAddons.css @@ -0,0 +1,107 @@ +/* ***** 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) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle + * + * 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 ***** */ + +html { + font-size: 24px; +} + +.addons-header { + border-bottom: 3px solid black; +} + +.addon-item { + border-bottom: 1px solid black; + padding: 8px; + position: relative; +} + +.addon-item:last-child { + border-bottom: 0; +} + +.addon-item:not([optionsURL]) .options-btn { + visibility: hidden; +} + +/* Make room for the image */ +.inner { + -moz-margin-start: 48px; +} + +.title { + color: black; +} + +.version { + /* The addon title is not localized, so keep the margin on the left side */ + margin-left: 12px; + font-size: 18px; + color: gray; +} + +.description { + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.buttons { + padding-top: 8px; +} + +body[dir="ltr"] .favicon { + left: 12px; +} + +body[dir="ltr"] .favicon { + right: 12px; +} + +.favicon { + border: none; + top: 8; + width: 32px; + height: 32px; + position: absolute; +} + +button { + color: black; + font-size: 28px !important; + padding: 5px; +} diff --git a/mobile/android/themes/core/aboutHome.css b/mobile/android/themes/core/aboutHome.css new file mode 100644 index 00000000000..8156d1600f5 --- /dev/null +++ b/mobile/android/themes/core/aboutHome.css @@ -0,0 +1,413 @@ +/* ***** 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): + * Mark Finkle + * + * 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 ***** */ + +html { + background: white; + font-family: "Nokia Sans", Tahoma, sans-serif !important; + font-size: 24px; + margin: 0px 20px; +} + +#wrapper { + max-width: 600px; + margin: 0 auto; +} + +#logo { + float: right; + margin-top: -24px; + -moz-margin-end: -34px; + /* Trick to ensure this is shown above the opacity transform happening to content*/ + -moz-transform: translate(0,0); +} + +body[dir="rtl"] #logo { + float: left; +} + +#header { + font-weight: bold; + color: white; + background: transparent -moz-linear-gradient(top, rgba(57,89,117,1) 0%, rgba(30,66,98,1) 50%, rgba(24,54,82,1) 90%); + border-radius: 6px; + padding: 12px; + padding-bottom: 14px; + margin-bottom: 12px; + margin-top: 20px; + box-shadow: inset rgba(0, 0, 0, 0.2) 0 -3px 0px, rgba(0, 0, 0, 0.1) 0px 2px 0px; +} + +#header-suffix { + color: rgb(112,136,156); +} + +.section-box { + background-color: white; + padding: 0; + margin-bottom: 8px; + border-radius: 8px; + border: 1px solid rgba(0,0,0,0.3); + box-shadow: + inset rgba(255, 255, 255, 0.5) 0 1px 0px, + inset rgba(0, 0, 0, 0.1) 0 -3px 0px, + rgba(0, 0, 0, 0.1) 0px 2px 0px; + width: 100%; + overflow: hidden; +} + +.section-box > h1 { + font-size: 18px; + font-weight: normal; + color: black; + background: transparent -moz-linear-gradient(top, rgba(235,235,235,0.2) 0%, rgba(235,235,235,1) 90%); + margin: 0; + padding: 4px 12px 8px 12px; + border-radius: 8px 8px 0 0; +} + +.section-box > div, +.section-box > a { + border-bottom: 1px solid rgba(0,0,0,0.1); + padding: 8px; + padding-bottom: 12px; + position: relative; +} + +.section-box > a { + display: block; + text-decoration: none; +} + +.section-box > div:last-child, +.section-box > a:last-child { + border-bottom: 0; +} + +/* Make room for the image */ +.section-box > div > div, +.section-box > a > div, +.section-row > div > div { + -moz-margin-start: 48px; +} + +.section-box .title { + color: black; +} + +.section-box .openall { + font-size: 18px; + padding: 12px 8px; + color: black; +} + +body[dir="ltr"] .section-box .openall { + text-align: right; +} + +.section-box .version { + /* The addon title is not localized, so keep the margin on the left side */ + margin-left: 12px; + font-size: 18px; + color: gray; +} + +.section-box .inner { + pointer-events: none; +} + +.section-box .favicon { + border: none; + top: 8px; + width: 32px; + height: 32px; + position: absolute; + pointer-events: none; +} + +body[dir="ltr"] .section-box .favicon { + left: 12px; +} + +body[dir="ltr"] .section-box .favicon { + right: 12px; +} + +body[dir="ltr"] #newAddons > div:not(.loading) { + background: url("images/arrowright-16.png") 99% center no-repeat; +} + +body[dir="rtl"] #newAddons > div:not(.loading) { + background: url("images/arrowleft-16.png") 1% center no-repeat; +} + +#remoteTabs[disabled=true] { + pointer-events: none; + color: #aaa; +} + +#remoteTabs[disabled=true] > div > .favicon { + opacity: 0.5; +} + +.section-row { + color: black; + background: transparent -moz-linear-gradient(top, rgba(235,235,235,0.2) 0%, rgba(235,235,235,1) 90%); + padding: 8px; + padding-bottom: 12px; + border-radius: 8px; + border: 1px solid rgba(0,0,0,0.3); + box-shadow: + inset rgba(255, 255, 255, 0.5) 0 1px 0px, + inset rgba(0, 0, 0, 0.1) 0 -3px 0px, + rgba(0, 0, 0, 0.1) 0px 2px 0px; + margin: 24px auto; +} + +.section-row > div { + position: relative; + pointer-events: none; +} + +.section-row .favicon { + border: none; + top: 0; + width: 32px; + height: 32px; + position: absolute; +} + +#newAddons { + margin-bottom: 0; +} + +/* Make sure the button and list match up nicely */ +#newAddons[showlist] { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + box-shadow: none; + margin: 0 -2px 0 0; +} + +#newAddonsList { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +body[dir="ltr"] { + left: 4px; +} + +body[dir="rtl"] { + right: 4px; +} + +.loading > img { + display: block; + margin: 0 auto; +} + +.no-items { + text-align: center; + -moz-margin-start: 0 !important; +} + +#footer-wrapper { + font-size: 18px; + margin-top: 24px; + text-align: center; +} + +#feedback { + display: inline-block; + margin: 0; +} + +#support { + display: inline-block; + margin: 0; +} + +#sync-setup { + font-size: 18px; + margin-top: 24px; + text-align: center; +} + +#syncSetupSync, +#syncPairDevice { + text-decoration: underline; + color: blue; +} + +/* Lightbox for Aurora */ +#lightbox { + position: fixed; + width: 100%; + height: 100%; + top: 0px; + left: 0px; + display: none; +} + +#lightbox-background { + background-color: #000; + width: 100%; + height: 100%; + opacity: 0.4; +} + +#lightbox-wrapper { + background: transparent; + width: 100%; + height: 100%; + top: 0px; + left: 0px; + position: fixed; +} + +#lightbox-container { + max-width: 300px; + margin: 40px auto; + background: #000 url("images/aurora-lightbox-bg.jpg") center top no-repeat; + border-radius: 6px; + padding: 26px 0px 0px; + border: 1px solid #000; + box-shadow: rgba(0, 0, 0, 0.75) 0px 0px 10px 2px; + position: relative; +} + +#lightbox-logo { + width: 65%; + max-width: 195px; + display: block; + margin: 0px auto; +} + +#lightbox-message { + width: 100%; + padding: 34px 0px 18px; + text-align: center; +} + +#lightbox-message > p, +#lightbox-button > p { + font-family: Georgia; + margin: 0px; + padding: 0px; +} + +#lightbox-message > p.title , +#lightbox-button > p.title { + font-size: 24px; + line-height: 24px; + color: #fff; + padding-bottom: 10px; +} + +#lightbox-message > p.message, +#lightbox-button > p.sub-title { + font-size: 16px; + line-height: 20px; +} + +#lightbox-message > p.message { + color: #c0b5b5; +} + +#lightbox-container a, +#lightbox-container a:hover, +#lightbox-container a:visited { + outline: 0px; + border: 0px; + text-decoration: none; + display: block; +} + +#lightbox-button { + background: -moz-linear-gradient(center top , #84C63C 0%, #489615 100%) repeat scroll 0 0 transparent; + margin: 10px; + text-align: center; + border-radius: 4px; + padding: 18px 0px; + box-shadow: rgba(0, 0, 0, 0) 0px 0px, inset rgba(0, 0, 0, 0.1) 0px -3px; +} + +#lightbox-button > p.title, +#lightbox-button > p.sub-title { + text-shadow: rgba(136, 136, 136, 0.39) 0px 0px 0px -1px; +} + +#lightbox-button > p.sub-title { + font-style: italic; + color: #fff; +} + +#lightbox-close { + position: absolute; + top: 15px; + right: 15px; + width: 16px; + height: 16px; +} + +@media (max-width: 399px) { + #support { + margin-top: 8px; + } +} + +@media (min-width: 400px) { + body[dir="ltr"] #feedback { + border-radius: 8px 0 0 8px; + } + + body[dir="rtl"] #feedback { + border-radius: 0 8px 8px 0; + } + + #support { + -moz-border-start: none; + } + + body[dir="ltr"] #support { + border-radius: 0 8px 8px 0; + } + + body[dir="rtl"] #support { + border-radius: 8px 0 0 8px; + } +} diff --git a/mobile/android/themes/core/aboutPage.css b/mobile/android/themes/core/aboutPage.css new file mode 100644 index 00000000000..aacc3c48292 --- /dev/null +++ b/mobile/android/themes/core/aboutPage.css @@ -0,0 +1,105 @@ +/* ***** 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): + * Gavin Sharp + * + * 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 ***** */ + +#aboutLogoContainer { + width: 300px; +} + +#version { + font-weight: bold; + color: #909090; + margin: -24px 20px 0 118px; +} + +#update { + float: right; + padding: 8px; + margin-top: -32px; +} + +body[dir="rtl"] #update { + float: left; +} + +#update-message-checking, +#update-message-none, +#update-message-found { + display: none; + float: right; + padding: 8px; + margin-top: -32px; +} + +body[dir="rtl"] #update-message-checking, +body[dir="rtl"] #update-message-none, +body[dir="rtl"] #update-message-found { + float: left; +} + +#aboutLinks { + background-color: white; + padding: 5px; + border: 2px solid #e6e5e3; + font-size: 24px; +} + +#aboutLinks > li { + clear: both; + border-bottom: 2px solid #e6e5e3; + list-style: none; + -moz-padding-end: 16px; +} + +#aboutLinks > li:last-child { + border-bottom: 0; +} + +#aboutLinks > li > a { + padding: 16px; + display: block; + color: #3a3834; + background: url("images/arrowright-16.png") right center no-repeat; +} + +body[dir="rtl"] #aboutLinks > li > a { + background: url("images/arrowleft-16.png") left center no-repeat; +} + +#aboutDetails { + margin-top: 15px; + font-size: 18px; +} diff --git a/mobile/android/themes/core/browser.css b/mobile/android/themes/core/browser.css new file mode 100644 index 00000000000..c173187c6fd --- /dev/null +++ b/mobile/android/themes/core/browser.css @@ -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 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): + * Mark Finkle + * + * 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 +%include defines.inc + +/* content scrollbars */ +.scroller { + opacity: 0; + background-color: rgba(0, 0, 0, 0.4) !important; + -moz-border-top-colors: none !important; + -moz-border-bottom-colors: none !important; + -moz-border-right-colors: none !important; + -moz-border-left-colors: none !important; + -moz-border-radius: @border_radius_tiny@; + border: @border_width_tiny@ solid rgba(255, 255, 255, 0.4) !important; +} + +.scroller[panning="true"] { + opacity: 1; +} + +.scroller[orient="vertical"] { + min-width: @scroller_thickness@; + width: @scroller_thickness@; + min-height: @scroller_minimum@; +} + +.scroller[orient="horizontal"] { + min-height: @scroller_thickness@; + height: @scroller_thickness@; + min-width: @scroller_minimum@; +} diff --git a/mobile/android/themes/core/config.css b/mobile/android/themes/core/config.css new file mode 100644 index 00000000000..33bd69027ed --- /dev/null +++ b/mobile/android/themes/core/config.css @@ -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 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): + * + * 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 ***** */ + +html { + font-size: 24px; +} + +input, +button { + font-size: 28px; + padding: 5px; +} + +#filter-container, +#new-pref-container { + margin-bottom: 10px; +} + +.pref-item { + padding-top: 10px; + border-top: 1px solid #ccc; +} + +.pref-item[default="false"] { + font-weight: bold; +} + +.pref-item > * { + margin-bottom: 10px; +} + +.modify-pref-button { + margin-right: 10px; +} diff --git a/mobile/android/themes/core/content.css b/mobile/android/themes/core/content.css new file mode 100644 index 00000000000..590822727c8 --- /dev/null +++ b/mobile/android/themes/core/content.css @@ -0,0 +1,370 @@ +/* ***** 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): + * Mark Finkle + * Doug Turner + * + * 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 +%include defines.inc + +@namespace url("http://www.w3.org/1999/xhtml"); +@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +/* make clicking on links stand out a bit (bug 532206) */ +* > *:not(embed):focus, * > *:focus > font { + outline: 2px solid #8db8d8 !important; + /* + XXX How do I preserve mac focusring without blowing focus color on other platforms? + outline-color: -moz-mac-focusring !important; + */ +} + +*:-moz-any-link:focus { + outline-offset: -2px; +} + +/* Style the scrollbars */ +html xul|scrollbar { + display: none; +} + +xul|window xul|scrollbar { + display: block; +} + +xul|scrollbar[orient="vertical"] { + -moz-appearance: none !important; + opacity: 0; + position: relative; + margin-left: -8px; + min-width: 8px; + background-color: transparent !important; + background-image: none !important; + border: 0px solid transparent !important; +} + +xul|scrollbar[orient="vertical"]:-moz-locale-dir(rtl) { + margin-left: 2px; + margin-right: -10px; +} + +xul|scrollbar[orient="vertical"] xul|thumb { + max-width: 6px !important; + min-width: 6px !important; +} + +xul|scrollbar[orient="horizontal"] { + -moz-appearance: none !important; + opacity: 0; + position: relative; + min-height: 8px; + margin-top: -8px; + background-color: transparent !important; + background-image: none !important; + border: 0px solid transparent !important; +} + +xul|scrollbar[orient="horizontal"] xul|thumb { + max-height: 6px !important; + min-height: 6px !important; +} + +xul|*[panning="true"] xul|scrollbar { + opacity: 1; +} + +xul|scrollbox { + overflow-y: scroll; + overflow-x: scroll; +} + +xul|scrollbarbutton { + min-height: 8px !important; + min-width: 8px !important; + -moz-appearance: none !important; + visibility: hidden; +} + +xul|scrollbarbutton[sbattr="scrollbar-up-top"], +xul|scrollbarbutton[sbattr="scrollbar-bottom-top"] { + display: none; +} + +xul|thumb { + background-color: rgba(0, 0, 0, 0.4) !important; + -moz-border-top-colors: none !important; + -moz-border-bottom-colors: none !important; + -moz-border-right-colors: none !important; + -moz-border-left-colors: none !important; + border: 1px solid rgba(255, 255, 255, 0.4) !important; + -moz-border-radius: 3px; +} + +select:not([size]):not([multiple]) > xul|scrollbar, +select[size="1"] > xul|scrollbar, +select:not([size]):not([multiple]) xul|scrollbarbutton, +select[size="1"] xul|scrollbarbutton { + display: block; + margin-left: 0; + min-width: 16px; +} + +/* Override inverse OS themes */ +select, +textarea, +button, +xul|button, +* > input:not([type="image"]) { + -moz-appearance: none !important; /* See bug 598421 for fixing the platform */ + -moz-border-radius: 3px; +} + +select[size], +select[multiple], +select[size][multiple], +textarea, +* > input:not([type="image"]) { + border-style: solid; + border-color: #7d7d7d; + color: #414141; + background: white -moz-linear-gradient(top, rgba(115,115,115,0.5) 0, rgba(215,215,215,0.5) 3px, rgba(255,255,255,0.2) 16px); +} + +/* Selects are handled by the form helper, see bug 685197 */ +select option, select optgroup { + pointer-events: none; +} + +input:-moz-placeholder, +textarea:-moz-placeholder { + color: GrayText; +} + +select:not([size]):not([multiple]), +select[size="0"], +select[size="1"], +* > input[type="button"], +* > input[type="submit"], +* > input[type="reset"], +button { + border-style: solid; + border-color: #7d7d7d; + color: #414141; + background: white -moz-linear-gradient(top, rgba(255,255,255,0.2) 0, rgba(215,215,215,0.5) 18px, rgba(115,115,115,0.5) 100%); +} + +input[type="checkbox"] { + background: white -moz-linear-gradient(top, rgba(115,115,115,0.5) 0, rgba(215,215,215,0.5) 2px, rgba(255,255,255,0.2) 6px); +} + +input[type="radio"] { + background: -moz-radial-gradient(6px 6px, cover, rgba(255,255,255,0.2) 3px, rgba(195,195,195,0.5) 5px, rgba(115,115,115,0.5) 100%); +} + +select { + border-width: 1px; + padding: 1px; +} + +select:not([size]):not([multiple]), +select[size="0"], +select[size="1"] { + padding: 0 1px 0 1px; +} + +* > input:not([type="image"]) { + border-width: 1px; + padding: 1px; +} + +textarea { + resize: none; + border-width: 1px; + padding: 2px 1px 2px 1px; +} + +input[type="button"], +input[type="submit"], +input[type="reset"], +button { + border-width: 1px; + padding: 0 7px 0 7px; +} + +input[type="radio"], +input[type="checkbox"] { + max-width: 14px; + max-height: 14px; + border: 1px solid #a7a7a7 !important; + padding: 2px 1px 2px 1px; +} + +select > input[type="button"] { + border-width: 0px !important; + margin: 0px !important; + padding: 0px !important; + -moz-border-radius: 0; + color: #414141; + + background-size: 100% 90%; + background-color: transparent; + background-image: -moz-radial-gradient(bottom left, #bbbbbb 40%, #f5f5f5) !important; + background-position: -15px center !important; + background-repeat: no-repeat !important; + + /* Use to position an svg arrow on element */ + -moz-binding: url("chrome://browser/content/bindings.xml#select-button"); + position: relative !important; + font-size: inherit; +} + +select[size]:focus, +select[multiple]:focus, +select[size][multiple]:focus, +textarea:focus, +input[type="file"]:focus > input[type="text"], +* > input:not([type="image"]):focus { + outline: 0px !important; + border-style: solid; + border-color: rgb(94,128,153); + background: white -moz-linear-gradient(top, rgba(27,113,177,0.5) 0, rgba(198,225,246,0.2) 3px, rgba(255,255,255,0.2) 16px); +} + +select:not([size]):not([multiple]):focus, +select[size="0"]:focus, +select[size="1"]:focus, +input[type="button"]:focus, +input[type="submit"]:focus, +input[type="reset"]:focus, +button:focus { + outline: 0px !important; + border-style: solid; + border-color: rgb(94,128,153); + background: white -moz-linear-gradient(top, rgba(255,255,255,0.2) 0, rgba(198,225,256,0.2) 18px, rgba(27,113,177,0.5) 100%); +} + +input[type="checkbox"]:focus, +input[type="radio"]:focus { + border-color: #99c6e0 !important; +} + +input[type="checkbox"]:focus { + background: white -moz-linear-gradient(top, rgba(27,113,177,0.5) 0, rgba(198,225,246,0.2) 2px, rgba(255,255,255,0.2) 6px); +} + +input[type="radio"]:focus { + background: -moz-radial-gradient(6px 6px, cover, rgba(255,255,255,0.2) 3px, rgba(198,225,246,0.2) 5px, rgba(27,113,177,0.5) 100%); +} + +/* we need to be specific for selects because the above rules are specific too */ +textarea[disabled], +select[size][disabled], +select[multiple][disabled], +select[size][multiple][disabled], +select:not([size]):not([multiple])[disabled], +select[size="0"][disabled], +select[size="1"][disabled], +button[disabled], +* > input:not([type="image"])[disabled] { + color: rgba(0,0,0,0.3); + border-color: rgba(125,125,125,0.4); + border-style: solid; + border-width: 1px; + background: transparent -moz-linear-gradient(top, rgba(185,185,185,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(255,255,255,0.4) 100%); +} + +select:not([size]):not([multiple])[disabled], +select[size="0"][disabled], +select[size="1"][disabled] { + background: transparent -moz-linear-gradient(top, rgba(255,255,255,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(185,185,185,0.4) 100%); +} + +input[type="button"][disabled], +input[type="submit"][disabled], +input[type="reset"][disabled], +button[disabled="true"] { + padding: 0 7px 0 7px; + background: transparent -moz-linear-gradient(top, rgba(255,255,255,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(185,185,185,0.4) 100%); +} + +input[type="radio"][disabled], +input[type="radio"][disabled]:active, +input[type="radio"][disabled]:hover, +input[type="radio"][disabled]:hover:active, +input[type="checkbox"][disabled], +input[type="checkbox"][disabled]:active, +input[type="checkbox"][disabled]:hover, +input[type="checkbox"][disabled]:hover:active { + border:1px solid rgba(125,125,125,0.4) !important; +} + +select[disabled] > input[type="button"] { + opacity: 0.6; + padding: 1px 7px 1px 7px; +} + +/* -moz-touch-enabled? media elements */ +video > xul|videocontrols, +audio > xul|videocontrols { + -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#touchControls"); +} + +*:-moz-any-link:active, +*[role=button]:active, +button:active, +input:active, +option:active, +select:active, +label:active, +textarea:active { + background-color: @color_background_highlight_overlay@ !important; +} + +/* + * Generate an additional space after the anonymous div to make it easier to + * to position the caret at the end of the text + */ +input > .anonymous-div:after { + content: ""; + margin: 16px; +} + +/* + * Enforce nearest scaling for video in order not to lose too much performance + * after fixing bug 598736 ("Use higher-quality imageinterpolation on mobile") + */ +video { + image-rendering: -moz-crisp-edges; +} diff --git a/mobile/android/themes/core/gingerbread/defines.inc b/mobile/android/themes/core/gingerbread/defines.inc new file mode 100644 index 00000000000..186aa0a2675 --- /dev/null +++ b/mobile/android/themes/core/gingerbread/defines.inc @@ -0,0 +1,128 @@ +%filter substitution + +%define color_background_active #525252 +%define color_background_default #000 +%define color_text_default #fff +%define color_divider_border #333333 +%define color_button_border #5a5a5a +%define color_dialog_border #5a5a5a +%define color_background_dlgbuttons #9a9a9a +%define color_background_panel #d6d6d6 +%define color_text_panel #000 +%define color_background_header #292929 +%define color_text_header #999999 +%define color_background_scroller #9a9a9a +%define color_background_inverse #fff +%define color_text_inverse #000 +%define color_text_button #000 +%define color_text_disabled #808080 +%define color_text_placeholder #808080 +%define color_text_as_link #febc2b + +%define color_background_highlight #febc2b +%define color_background_highlight_overlay rgba(254, 188, 43, 0.8) +%define color_text_highlight #000 + +%define color_subtext_default lightgray +%define color_subtext_inverse #414141 + +%define font_xlarge 5.08mozmm +%define font_xnormal 2.75mozmm +%define font_normal 2.54mozmm +%define font_snormal 2.33mozmm +%define font_small 1.91mozmm +%define font_xsmall 1.69mozmm +%define font_tiny 1.48mozmm +%define font_xtiny 1.27mozmm +%define font_xxtiny 1.08mozmm + +%define touch_row 7.41mozmm +%define touch_button_xlarge 7.62mozmm +%define touch_button_large 6.77mozmm +%define touch_button_small 5.93mozmm +%define touch_button_minwidth 11.86mozmm +%define touch_action_minwidth 21.17mozmm +%define touch_normal 6.77mozmm + +%define margin_context_popup 3.39mozmm +%define margin_large 2.54mozmm +%define margin_xxxnormal 1.69mozmm +%define margin_xnormal 1.06mozmm +%define margin_normal 0.85mozmm +%define margin_snormal 0.64mozmm +%define margin_small 0.42mozmm +%define margin_tiny 0.21mozmm +%define margin_xtiny 0.15mozmm + +%define padding_xlarge 3.39mozmm +%define padding_large 2.54mozmm +%define padding_xxxnormal 1.69mozmm +%define padding_xxnormal 1.27mozmm +%define padding_xnormal 1.06mozmm +%define padding_normal 0.85mozmm +%define padding_snormal 0.64mozmm +%define padding_small 0.42mozmm +%define padding_xsmall 0.21mozmm +%define padding_tiny 0.11mozmm + +%define border_width_xxlarge 0.64mozmm +%define border_width_xlarge 0.42mozmm +%define border_width_large 0.32mozmm +%define border_width_small 0.21mozmm +%define border_width_tiny 0.11mozmm + +%define border_radius_normal 0.85mozmm +%define border_radius_small 0.64mozmm +%define border_radius_xsmall 0.31mozmm +%define border_radius_tiny 0.21mozmm + +%define shadow_width_xlarge 1.06mozmm +%define shadow_width_large 0.64mozmm +%define shadow_width_small 0.21mozmm + +%define textbox_height 5.08mozmm + +%define dropmarker_padding 0.53mozmm + +%define progressmeter_height 3.39mozmm + +%define urlbar_edit_height 6.35mozmm +%define urlbar_edit_indent 0.85mozmm +%define identity_popup_tablet_width 72mozmm + +%define scroller_thickness 0.64mozmm +%define scroller_minimum 1.27mozmm + +%define sidebar_width_minimum 8.47mozmm +%define sidebar_button_height 7.41mozmm +%define documenttab_margin_bottom 0.85mozmm + +%define placelabel_padding 8.47mozmm +%define placeitem_padding 4.23mozmm + +%define autocomplete_item_container_image_padding 0.53mozmm +%define autocomplete_item_container_position 0.21mozmm +%define autocomplete_item_container_size 2.75mozmm +%define autocomplete_item_container_padding 5.08mozmm + +%define autocomplete_item_subtitle_margin 2.75mozmm +%define autocomplete_item_label_margin 3.18mozmm +%define autocomplete_item_tags_margin 3.39mozmm + +%define autocompleteresult_padding 0.53mozmm + +%define dialog_width 76.2mozmm + +%define appmenu_portrait_height 21.17mozmm +%define appmenu_button_height 10.48mozmm + +%define tablet_panel_controls 40mozmm +%define tablet_panel_minwidth 124mozmm + +%ifdef MOZ_PLATFORM_MAEMO +%define orientation -moz-device-orientation +%elifdef ANDROID +%define orientation -moz-device-orientation +%else +%define orientation orientation +%endif diff --git a/mobile/android/themes/core/gingerbread/images/aboutBackground.jpg b/mobile/android/themes/core/gingerbread/images/aboutBackground.jpg new file mode 100644 index 00000000000..5dba1c58eb5 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/aboutBackground.jpg differ diff --git a/mobile/android/themes/core/gingerbread/images/addons-default-hdpi.png b/mobile/android/themes/core/gingerbread/images/addons-default-hdpi.png new file mode 100644 index 00000000000..e08a1a72739 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/addons-default-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/alert-addons-30.png b/mobile/android/themes/core/gingerbread/images/alert-addons-30.png new file mode 100644 index 00000000000..c8c1a8d3a0c Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/alert-addons-30.png differ diff --git a/mobile/android/themes/core/gingerbread/images/alert-downloads-30.png b/mobile/android/themes/core/gingerbread/images/alert-downloads-30.png new file mode 100644 index 00000000000..8279c3c92c1 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/alert-downloads-30.png differ diff --git a/mobile/android/themes/core/gingerbread/images/arrowdown-16.png b/mobile/android/themes/core/gingerbread/images/arrowdown-16.png new file mode 100644 index 00000000000..c982426f2ad Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/arrowdown-16.png differ diff --git a/mobile/android/themes/core/gingerbread/images/arrowleft-16.png b/mobile/android/themes/core/gingerbread/images/arrowleft-16.png new file mode 100644 index 00000000000..464a4a866cd Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/arrowleft-16.png differ diff --git a/mobile/android/themes/core/gingerbread/images/arrowright-16.png b/mobile/android/themes/core/gingerbread/images/arrowright-16.png new file mode 100644 index 00000000000..859e98ba64b Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/arrowright-16.png differ diff --git a/mobile/android/themes/core/gingerbread/images/arrowup-16.png b/mobile/android/themes/core/gingerbread/images/arrowup-16.png new file mode 100644 index 00000000000..2a7e5648535 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/arrowup-16.png differ diff --git a/mobile/android/themes/core/gingerbread/images/back-default-hdpi.png b/mobile/android/themes/core/gingerbread/images/back-default-hdpi.png new file mode 100644 index 00000000000..4bae9afbca0 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/back-default-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/browseaddons-bg.jpg b/mobile/android/themes/core/gingerbread/images/browseaddons-bg.jpg new file mode 100644 index 00000000000..dcd9a92b352 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/browseaddons-bg.jpg differ diff --git a/mobile/android/themes/core/gingerbread/images/button-bg.png b/mobile/android/themes/core/gingerbread/images/button-bg.png new file mode 100644 index 00000000000..f57261d41a4 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/button-bg.png differ diff --git a/mobile/android/themes/core/gingerbread/images/check-30.png b/mobile/android/themes/core/gingerbread/images/check-30.png new file mode 100644 index 00000000000..82cf8f415fa Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/check-30.png differ diff --git a/mobile/android/themes/core/gingerbread/images/check-selected-hdpi.png b/mobile/android/themes/core/gingerbread/images/check-selected-hdpi.png new file mode 100644 index 00000000000..2fa34331d93 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/check-selected-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/check-unselected-hdpi.png b/mobile/android/themes/core/gingerbread/images/check-unselected-hdpi.png new file mode 100644 index 00000000000..add20cb42c9 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/check-unselected-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/dropmarker-hdpi.png b/mobile/android/themes/core/gingerbread/images/dropmarker-hdpi.png new file mode 100644 index 00000000000..a41c303c2a2 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/dropmarker-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/errorpage-larry-black.png b/mobile/android/themes/core/gingerbread/images/errorpage-larry-black.png new file mode 100644 index 00000000000..9f2e4a6e736 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/errorpage-larry-black.png differ diff --git a/mobile/android/themes/core/gingerbread/images/errorpage-larry-white.png b/mobile/android/themes/core/gingerbread/images/errorpage-larry-white.png new file mode 100644 index 00000000000..fc153c7314e Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/errorpage-larry-white.png differ diff --git a/mobile/android/themes/core/gingerbread/images/errorpage-warning.png b/mobile/android/themes/core/gingerbread/images/errorpage-warning.png new file mode 100644 index 00000000000..8bf9d8e7dec Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/errorpage-warning.png differ diff --git a/mobile/android/themes/core/gingerbread/images/favicon-default-32.png b/mobile/android/themes/core/gingerbread/images/favicon-default-32.png new file mode 100644 index 00000000000..8e66e5ae57e Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/favicon-default-32.png differ diff --git a/mobile/android/themes/core/gingerbread/images/forward-default-hdpi.png b/mobile/android/themes/core/gingerbread/images/forward-default-hdpi.png new file mode 100644 index 00000000000..1bfa8012f6d Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/forward-default-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/handle-end.png b/mobile/android/themes/core/gingerbread/images/handle-end.png new file mode 100644 index 00000000000..d2720e70ec2 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/handle-end.png differ diff --git a/mobile/android/themes/core/gingerbread/images/handle-start.png b/mobile/android/themes/core/gingerbread/images/handle-start.png new file mode 100644 index 00000000000..8abd627f0df Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/handle-start.png differ diff --git a/mobile/android/themes/core/gingerbread/images/locked-hdpi.png b/mobile/android/themes/core/gingerbread/images/locked-hdpi.png new file mode 100644 index 00000000000..a21c3a15828 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/locked-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/mute-hdpi.png b/mobile/android/themes/core/gingerbread/images/mute-hdpi.png new file mode 100644 index 00000000000..c716ef35cd5 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/mute-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/navigation-magnifier-30.png b/mobile/android/themes/core/gingerbread/images/navigation-magnifier-30.png new file mode 100644 index 00000000000..2a36e16d21d Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/navigation-magnifier-30.png differ diff --git a/mobile/android/themes/core/gingerbread/images/next-disabled-hdpi.png b/mobile/android/themes/core/gingerbread/images/next-disabled-hdpi.png new file mode 100644 index 00000000000..69cb6d38d6b Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/next-disabled-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/next-hdpi.png b/mobile/android/themes/core/gingerbread/images/next-hdpi.png new file mode 100644 index 00000000000..a370353e828 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/next-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/pause-hdpi.png b/mobile/android/themes/core/gingerbread/images/pause-hdpi.png new file mode 100644 index 00000000000..42b36576978 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/pause-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/play-hdpi.png b/mobile/android/themes/core/gingerbread/images/play-hdpi.png new file mode 100644 index 00000000000..7410c99cd5d Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/play-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/popup-selected-item-hdpi.png b/mobile/android/themes/core/gingerbread/images/popup-selected-item-hdpi.png new file mode 100644 index 00000000000..a11bd508f68 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/popup-selected-item-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/previous-disabled-hdpi.png b/mobile/android/themes/core/gingerbread/images/previous-disabled-hdpi.png new file mode 100644 index 00000000000..fa7b069f597 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/previous-disabled-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/previous-hdpi.png b/mobile/android/themes/core/gingerbread/images/previous-hdpi.png new file mode 100644 index 00000000000..099ff2d574f Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/previous-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/radio-selected-hdpi.png b/mobile/android/themes/core/gingerbread/images/radio-selected-hdpi.png new file mode 100644 index 00000000000..9b3ad38a62a Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/radio-selected-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/radio-unselected-hdpi.png b/mobile/android/themes/core/gingerbread/images/radio-unselected-hdpi.png new file mode 100644 index 00000000000..17e346ae8ef Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/radio-unselected-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/remotetabs-32.png b/mobile/android/themes/core/gingerbread/images/remotetabs-32.png new file mode 100644 index 00000000000..80f59a022c3 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/remotetabs-32.png differ diff --git a/mobile/android/themes/core/gingerbread/images/row-header-bg.png b/mobile/android/themes/core/gingerbread/images/row-header-bg.png new file mode 100644 index 00000000000..d0f3caa673c Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/row-header-bg.png differ diff --git a/mobile/android/themes/core/gingerbread/images/scrubber-hdpi.png b/mobile/android/themes/core/gingerbread/images/scrubber-hdpi.png new file mode 100644 index 00000000000..0a2fdd3c7fe Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/scrubber-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/search-clear-30.png b/mobile/android/themes/core/gingerbread/images/search-clear-30.png new file mode 100644 index 00000000000..8bab39a08d3 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/search-clear-30.png differ diff --git a/mobile/android/themes/core/gingerbread/images/search-glass-30.png b/mobile/android/themes/core/gingerbread/images/search-glass-30.png new file mode 100644 index 00000000000..f8cb0ef2bc3 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/search-glass-30.png differ diff --git a/mobile/android/themes/core/gingerbread/images/textbox-bg.png b/mobile/android/themes/core/gingerbread/images/textbox-bg.png new file mode 100644 index 00000000000..1f02bd73cbd Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/textbox-bg.png differ diff --git a/mobile/android/themes/core/gingerbread/images/throbber.png b/mobile/android/themes/core/gingerbread/images/throbber.png new file mode 100644 index 00000000000..c601ec80ba7 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/throbber.png differ diff --git a/mobile/android/themes/core/gingerbread/images/toggle-off.png b/mobile/android/themes/core/gingerbread/images/toggle-off.png new file mode 100644 index 00000000000..87a660c599e Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/toggle-off.png differ diff --git a/mobile/android/themes/core/gingerbread/images/toggle-on.png b/mobile/android/themes/core/gingerbread/images/toggle-on.png new file mode 100644 index 00000000000..8d333d5d861 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/toggle-on.png differ diff --git a/mobile/android/themes/core/gingerbread/images/unlocked-hdpi.png b/mobile/android/themes/core/gingerbread/images/unlocked-hdpi.png new file mode 100644 index 00000000000..e21b80fa3c6 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/unlocked-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/unmute-hdpi.png b/mobile/android/themes/core/gingerbread/images/unmute-hdpi.png new file mode 100644 index 00000000000..cf2fb7bfb66 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/unmute-hdpi.png differ diff --git a/mobile/android/themes/core/gingerbread/images/urlbar-bg.png b/mobile/android/themes/core/gingerbread/images/urlbar-bg.png new file mode 100644 index 00000000000..9dddc7e7363 Binary files /dev/null and b/mobile/android/themes/core/gingerbread/images/urlbar-bg.png differ diff --git a/mobile/android/themes/core/gingerbread/localePicker.css b/mobile/android/themes/core/gingerbread/localePicker.css new file mode 100644 index 00000000000..2a6564944df --- /dev/null +++ b/mobile/android/themes/core/gingerbread/localePicker.css @@ -0,0 +1,96 @@ +/* ***** 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) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Wes Johnston + * + * 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 +%include defines.inc + +.pane { + -moz-box-pack: center; + -moz-box-align: center; + -moz-box-flex: 1; +} + +#main-page { + background-image: url("chrome://branding/content/logo.png"); + background-repeat: no-repeat; + background-position: center center; +} + +#main-page:not([mode="loading"]) #loading-label, +#main-page[mode] #continue-in-button, +#main-page[mode] #change-language { + visibility: hidden; +} + +#picker-title { + font-weight: bold; + font-size: @font_normal@; +} + +.link { + padding: @padding_xlarge@ 0px; + font-weight: bold; +} + +richlistbox { + padding: 0px; + margin: 0px; + background-color: transparent; +} + +#installer-page { + background-color: black; + color: white; +} + +richlistitem { + height: @touch_row@; + font-size: @font_normal@; + border-bottom: @border_width_tiny@ solid gray; + padding: 0px @padding_normal@; + -moz-box-align: center; +} + +richlistitem .checkbox { + width: 46px; + height: 46px; + list-style-image: url("chrome://browser/skin/images/radio-unselected-hdpi.png"); +} + +richlistitem[selected] .checkbox { + list-style-image: url("chrome://browser/skin/images/radio-selected-hdpi.png"); +} diff --git a/mobile/android/themes/core/gingerbread/platform.css b/mobile/android/themes/core/gingerbread/platform.css new file mode 100644 index 00000000000..92af8911124 --- /dev/null +++ b/mobile/android/themes/core/gingerbread/platform.css @@ -0,0 +1,740 @@ +/* ***** 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): + * Mark Finkle + * + * 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 ***** */ + +/* global skin ------------------------------------------------------------- */ +@import url(chrome://global/skin/); + +%filter substitution +%include defines.inc + +/* general stuff ------------------------------------------------------------ */ +:root { + font-family: "Nokia Sans", Tahoma, sans-serif !important; + font-size: @font_normal@ !important; + background-color: @color_background_default@; /* force */ + color: @color_text_default@; /* force */ +} + +::-moz-selection { + background-color: @color_background_highlight@; + color: @color_text_highlight@; +} + +menu, +menuitem { + padding: 0 !important; + margin: 0 !important; +} + +description, +label { + /* force mac to use the same margins as windows and linux */ + -moz-margin-start: @margin_snormal@; + -moz-margin-end: @margin_snormal@; +} + +/* Override any OS inverse themes */ +textbox { + color: @color_text_inverse@; + background-color: @color_background_inverse@; +} + +/* textboxes --------------------------------------------------------------- */ +textbox:not([type="number"]) { + min-height: @textbox_height@; + border: @border_width_small@ solid @color_button_border@; + -moz-border-top-colors: -moz-initial; + -moz-border-right-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; +} + +textbox[isempty="true"] { + color: @color_text_placeholder@; +} + +textbox.search-bar { + border: @border_width_small@ solid rgba(0,0,0,0.4); + background-color: #f9f9f9; + background: url("chrome://browser/skin/images/textbox-bg.png") top left repeat-x; + background-size: 100% 100%; +} + +textbox[disabled="true"] { + background-color: lightgray; +} + +.link { + color: @color_text_as_link@; + text-decoration: underline; +} + +/* sidebars spacer --------------------------------------------------------- */ +.sidebar-spacer { + background-color: #767973; +} + +/* prompt dialogs ---------------------------------------------------------- */ +.context-block, +.modal-block, +.perm-modal-block { + -moz-box-align: center; + -moz-box-pack: center; + background-color: rgba(0,0,0,.6); +} + +.context-block { + padding: @margin_context_popup@; +} + +.dialog-dark, +.panel-arrowcontent { + background-color: @color_background_inverse@; + box-shadow: black 0 @border_radius_tiny@ @border_radius_tiny@, black 0 -@border_radius_tiny@ @border_radius_tiny@; + padding: 0; +} + +@media (max-width: 499px) { + .context-block { + padding: @padding_xlarge@; + } +} + +dialog > .prompt-header > .prompt-message { + white-space: pre-wrap; +} + +dialog > .prompt-header > .button-checkbox { + margin-left: @margin_large@; +} + +/* buttons ----------------------------------------------------------------- */ +.button-text, +.toolbarbutton-text { + font-weight: normal; + font-size: @font_snormal@ !important; +} + +button { + -moz-appearance: none; + min-width: @touch_button_minwidth@ !important; + min-height: @touch_button_small@ !important; /* button size */ + color: @color_text_button@; + margin: @margin_normal@; + padding: @padding_xnormal@; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border: @border_width_tiny@ solid @color_button_border@; +} + +button[disabled="true"] { + color: @color_text_disabled@ !important; + border: @border_width_tiny@ solid @color_button_border@ !important; +} + +button:focus > .button-box { + border: @border_width_tiny@ solid transparent; +} + +button:not([disabled]):hover:active, +button:not([disabled])[checked="true"] { + background-image: url("chrome://browser/skin/images/toggle-off.png"); +} + +/* Override GTK2 system setting */ +.button-icon { + display: -moz-initial !important; +} + +/* spinbuttons ------------------------------------------------------------- */ +spinbuttons { + border: none !important; +} + +.numberbox-input-box { + border: @border_width_small@ solid @color_button_border@; + border-right: 0 solid transparent; + -moz-border-top-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; +} + +.numberbox-input-box:-moz-locale-dir(rtl) { + border-right: @border_width_small@ solid @color_button_border@; + border-left: 0 solid transparent; +} + +.spinbuttons-box { + border: none !important; + -moz-box-orient: horizontal !important; + -moz-box-direction: reverse !important; +} + +.spinbuttons-up .button-icon, +.spinbuttons-down .button-icon { + display: block; +} + +.spinbuttons-up, +.spinbuttons-down { + -moz-appearance: none !important; + min-width: @touch_button_small@ !important; /* button size */ + min-height: @touch_button_small@ !important; /* button size */ + color: @color_text_button@; + margin: @margin_normal@; + padding: @padding_xnormal@; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border: @border_width_tiny@ solid @color_button_border@; + list-style-image: url("chrome://browser/skin/images/arrowdown-16.png"); +} + +.spinbuttons-up:hover:active:not([disabled=true]), +.spinbuttons-down:hover:active:not([disabled=true]) { + background-image: url("chrome://browser/skin/images/toggle-on.png"); +} + +.spinbuttons-up { + list-style-image: url("chrome://browser/skin/images/arrowup-16.png"); +} + +/* toolbar buttons --------------------------------------------------------- */ +toolbarbutton { + min-width: @touch_button_large@ !important; /* primary button size */ + min-height: @touch_button_large@ !important; /* primary button size */ + -moz-appearance: none !important; + margin: 0; + padding: @padding_xsmall@; +} + +toolbarbutton:not(.show-text) .toolbarbutton-text { + display: none; +} + +.toolbarbutton-icon[label]:not([label=""]), +.toolbarbutton-icon[type="menu"] { + -moz-margin-end: @margin_tiny@; +} + +toolbarbutton:not(.show-text) .toolbarbutton-icon, +toolbarbutton:not([image]) .toolbarbutton-icon, +toolbarbutton[image=''] .toolbarbutton-icon { + -moz-margin-end: 0; +} + +toolbarbutton:hover, +toolbarbutton:hover:active, +toolbarbutton[open="true"] { + border-color: transparent; +} + +/* checkbox buttons ----------------------------------------------------------- */ +.button-checkbox { + padding: 0 !important; + background: none !important; + border: none !important; + -moz-border-image: none !important; + color: @color_text_default@; + -moz-box-align: center; + font-size: @font_small@; + -moz-box-align: center; +} + +.prompt-checkbox-label { + text-align: left; +} + +.button-checkbox > .button-image-icon { + -moz-margin-end: @margin_normal@; + list-style-image: url("chrome://browser/skin/images/check-unselected-hdpi.png"); +} + +.button-checkbox[checked="true"] > .button-image-icon { + list-style-image: url("chrome://browser/skin/images/check-selected-hdpi.png"); +} + +.button-checkbox > .button-box, +.button-checkbox:hover:active > .button-box, +.button-checkbox[checked="true"] > .button-box { + padding-top: @padding_tiny@; + padding-bottom: @padding_xsmall@; + -moz-padding-start: @padding_small@; + -moz-padding-end: @padding_small@; +} + +/* radio buttons ----------------------------------------------------------- */ +radiogroup { + -moz-box-orient: horizontal; +} + +.radio-label { + font-weight: normal; + font-size: @font_snormal@ !important; +} + +radio { + -moz-appearance: none; + min-width: @touch_button_small@ !important; /* button size */ + min-height: @touch_button_small@ !important; /* button size */ + color: @color_text_button@; + padding: @padding_xnormal@; + margin: 0; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border-top: @border_width_tiny@ solid @color_button_border@; + border-bottom: @border_width_tiny@ solid @color_button_border@; +} + +radio .radio-icon, radio .radio-check { + display: none; +} + +radio:not([disabled=true]):hover:active, +radio[selected] { + color: white; + background-image: url("chrome://browser/skin/images/toggle-on.png"); +} + +radio:first-child { + border-left: @border_width_tiny@ solid @color_button_border@; +} + +radio:first-child:-moz-locale-dir(rtl) { + border-left: none; + border-right: @border_width_tiny@ solid @color_button_border@; +} + +radio:last-child { + border-right: @border_width_tiny@ solid @color_button_border@; +} + +radio:last-child:-moz-locale-dir(rtl) { + border-right: none; + border-left: @border_width_tiny@ solid @color_button_border@; +} + +radio[focused="true"] > .radio-label-box { + border: @border_width_tiny@ solid transparent; +} + +/* checkbox --------------------------------------------------------------- */ +checkbox { + margin: @margin_tiny@ @margin_small@ @margin_tiny@ @margin_small@; /* match platform style for buttons */ + -moz-binding: url("chrome://global/content/bindings/checkbox.xml#checkbox-with-spacing") !important; +} + +/* stop the focus from moving/showing the border around the label, which we don't use */ +checkbox:focus > .checkbox-label-center-box > .checkbox-label-box { + border: 1px solid transparent; +} + +.checkbox-check { + border: 2px transparent; + -moz-border-top-colors: -moz-initial; + -moz-border-right-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; + width: 46px; + height: 46px; + background: url("chrome://browser/skin/images/check-unselected-hdpi.png") no-repeat 50% 50%; +} + +checkbox[checked="true"] > .checkbox-spacer-box > .checkbox-check { + background-image: url("chrome://browser/skin/images/check-selected-hdpi.png"); +} + +checkbox[checked="true"][disabled="true"] > .checkbox-spacer-box > .checkbox-check { + background-image: url("chrome://browser/skin/images/check-selected-hdpi.png"); +} + +/* richlistbox ------------------------------------------------------------- */ +richlistbox { + color: @color_text_default@; + background-color: @color_background_default@; + -moz-user-focus: ignore; + margin: 0; +} + +richlistitem { + -moz-user-focus: ignore; + min-height: @touch_row@; /* row size */ + padding: @padding_small@; + border-bottom: @border_width_tiny@ solid @color_divider_border@; +} + +richlistitem label.title, +richlistitem description.title { + font-size: @font_normal@ !important; +} + +richlistitem label.normal, +richlistitem description.normal { + color: @color_subtext_default@; + font-size: @font_small@ !important; + white-space: pre-wrap; + word-wrap: break-word; +} + +richlistitem label.normal-black, +richlistitem description.normal-black { + font-size: @font_small@ !important; + white-space: pre-wrap; + word-wrap: break-word; +} + +richlistitem label.normal-bold, +richlistitem description.normal-bold { + font-weight: bold; + font-size: @font_small@ !important; + white-space: pre-wrap; + word-wrap: break-word; +} + +richlistitem[selected="true"] { + color: @color_text_default@; + background-color: @color_background_default@; +} + +richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]), +richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]) label.normal, +richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]) description.normal { + background-color: @color_background_highlight@; + color: @color_text_highlight@; +} + +richlistitem.section-header, +richlistitem[selected="true"].section-header { + font-weight: bold; + color: @color_text_header@; + background-color: @color_background_header@; +} + +richlistitem .show-on-select { + visibility: collapse; +} + +richlistitem[selected="true"] .show-on-select { + visibility: visible; +} + +richlistitem .hide-on-select { + visibility: visible; +} + +richlistitem[selected="true"] .hide-on-select { + visibility: collapse; +} + +richlistitem[typeName="message"] { + border-bottom: 0; +} + +/* colorpicker ------------------------------------------------------------- */ +colorpicker > panel { + background-color: #767973; +} + +colorpicker > vbox { + background-color: #767973; +} + +/* textbox ----------------------------------------------------------------- */ +.textbox-search-icon { + list-style-image: url("chrome://browser/skin/images/search-glass-30.png"); + -moz-image-region: auto; +} + +.textbox-search-clear { + list-style-image: url("chrome://browser/skin/images/search-clear-30.png"); + -moz-image-region: auto; +} + +/* menulist ---------------------------------------------------------------- */ +.menulist-label { + font-family: "Nokia Sans", Tahoma, sans-serif !important; + font-weight: normal; + font-size: @font_snormal@ !important; + background-color: transparent !important; +} + +menulist { + -moz-appearance: none !important; + -moz-user-focus: ignore; + min-width: @touch_button_minwidth@ !important; + min-height: @touch_button_small@ !important; /* button size */ + color: @color_text_button@ !important; + margin: @margin_normal@; + padding: @padding_small@ @padding_xnormal@; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border: @border_width_tiny@ solid @color_button_border@; +} + +menulist[disabled="true"] { + color: @color_text_disabled@ !important; + border: @border_width_tiny@ solid @color_button_border@ !important; +} + +menulist:not([disabled="true"]):hover:active { + background-image: url("chrome://browser/skin/images/toggle-off.png"); +} + +menulist > dropmarker { + height: 32px; + width: 32px; + margin-left: @margin_snormal@; + background-color: transparent; /* for windows */ + border: none; /* for windows */ + -moz-box-align: center; + -moz-box-pack: center; + list-style-image: url("chrome://browser/skin/images/dropmarker-hdpi.png"); + -moz-image-region: auto; + display: block; +} + +menulist[disabled="true"] > dropmarker { + opacity: 0.5; +} + +/* progressmeter ----------------------------------------------------------- */ +progressmeter { + background-color: #fff; + padding: @padding_small@; + height: @textbox_height@; + border: @border_width_large@ solid #aaa; + -moz-border-top-colors: -moz-initial; + -moz-border-right-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; +} + +.progress-bar { + background-color: @color_background_highlight@; +} + +/* panels / arrowboxes------------------------------------------------------ */ +arrowbox { + -moz-appearance: none; + background: transparent !important; + border: none; +} + +.arrowbox-dark .panel-arrowcontent { + padding: @padding_normal@; /* core spacing */ +} + +dialog, +.arrowbox-dark .panel-arrowcontent, +.panel-dark { + color: @color_text_default@; + background: @color_background_default@; +} + +dialog, +.arrowbox-dark .panel-arrowcontent { + border: @border_width_small@ solid @color_dialog_border@; + box-shadow: black 0 @shadow_width_small@ @shadow_width_small@; +} + +dialog { + margin: @margin_xxxnormal@ !important; + max-width: @dialog_width@; +} + +.prompt-message { + -moz-box-pack: center; + font-size: @font_snormal@; + margin: @padding_normal@; +} + +.prompt-title { + font-size: @font_xnormal@; + padding-top: @padding_xnormal@; + padding-left: @padding_normal@; +} + +/* Authentication dialogs do not have a title */ +.prompt-title:empty, +.prompt-title:empty + .prompt-line { + display: none; +} + +.prompt-line { + border-bottom: @border_width_tiny@ solid @color_divider_border@; + margin: @margin_small@ 0 0 0; + height: @padding_normal@ !important; +} + +.prompt-buttons { + font-size: @font_snormal@; + background-color: @color_background_dlgbuttons@; + display: inline-block; + text-align: center; +} + +.prompt-edit { + margin: @margin_xnormal@; + font-size: @font_normal@; + text-align: start; +} + +/*.panel-row-header ------------------------------------------------------------ */ +.panel-row-header { + border-bottom: @border_width_xxlarge@ solid @color_background_active@; + background-color: @color_background_default@ !important; + padding: 0 !important; +} + +.panel-row-button { + -moz-appearance: none; + background: @color_background_default@; + background-size: 100% 100%; + color: white; + border: 0 solid transparent !important; + -moz-border-start: @border_width_tiny@ solid rgba(255,255,255,0.2) !important; + -moz-border-end: @border_width_tiny@ solid rgba(0,0,0,0.2) !important; + padding-top: @padding_xsmall@ !important; + padding-bottom: @padding_xsmall@ !important; + -moz-padding-start: @padding_xsmall@ !important; + -moz-padding-end: @padding_xsmall@ !important; + -moz-box-flex: 1; + -moz-user-focus: ignore; + -moz-user-select: none; +} + +.panel-row-button:hover:active { + background: @color_background_active@; + background-size: 100% 100%; +} + +.panel-row-button:first-child { + -moz-border-start-width: 0 !important; +} + +.panel-row-button:last-child { + -moz-border-end-width: 0 !important; +} + +@media (@orientation@: portrait) { + .panel-row-button { + -moz-box-orient: vertical; + } + + .panel-row-button .toolbarbutton-text { + font-size: @font_xsmall@ !important; + } +} + +.panel-row-button .toolbarbutton-text { + text-align: left; + text-shadow: rgba(0,0,0,0.3) 0 @shadow_width_small@; +} + +.panel-row-button .toolbarbutton-text:-moz-locale-dir(rtl) { + text-align: right; +} + +.panel-row-button[disabled="true"] { + pointer-events: none; +} + +.panel-row-button[disabled="true"] .toolbarbutton-icon { + opacity: 0.5; +} + +.panel-row-button[disabled="true"] .toolbarbutton-text { + color: @color_text_disabled@; +} + +.panel-row-button[checked="true"] { + color: white !important; + background: @color_background_active@ !important; + background-size: 100% 100% !important; +} + +.panel-row-button[checked="true"], +.panel-row-button[disabled="true"] { + pointer-events: none; +} + +#panel-container-inner { + -moz-box-orient: vertical; +} + +#panel-controls { + -moz-box-orient: horizontal; +} + +@media (min-width: @tablet_panel_minwidth@) { + #panel-container-inner { + -moz-box-orient: horizontal; + -moz-box-pack: center; + } + + #panel-items { + max-width: @tablet_panel_minwidth@; + min-width: 0px !important; + } + + /* This will affect the prefs screen, but not the awesome screen */ + #panel-controls { + -moz-box-orient: vertical !important; + -moz-box-align: start; + } + + #panel-controls > .panel-row-button { + -moz-box-orient: horizontal; + -moz-box-flex: 0; + min-width: @tablet_panel_controls@ !important; + } + + #panel-controls .toolbarbutton-text { + display: -moz-box !important; + -moz-box-flex: 1; + } + + #panel-container { + -moz-box-pack: center; + padding: @padding_xlarge@ 0px; + } +} + +/* because the buttons can wrap, we need to use the margin to create inter-button + spacing and a bottom margin for the notification */ +notification > button { + margin-bottom: @margin_normal@; +} diff --git a/mobile/android/themes/core/header.css b/mobile/android/themes/core/header.css new file mode 100644 index 00000000000..3c221233a80 --- /dev/null +++ b/mobile/android/themes/core/header.css @@ -0,0 +1,47 @@ +/* ***** 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): + * Gavin Sharp + * + * 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 ***** */ + +body { + font-family: helvetica,arial,clean,sans-serif; + color: #69645c; + background: white url("images/aboutBackground.jpg") top center repeat-x; +} + +#wrapper { + max-width: 600px; + margin: 0 auto; +} diff --git a/mobile/android/themes/core/honeycomb/browser.css b/mobile/android/themes/core/honeycomb/browser.css new file mode 100644 index 00000000000..811a152b8b0 --- /dev/null +++ b/mobile/android/themes/core/honeycomb/browser.css @@ -0,0 +1,68 @@ +/* ***** 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): + * Mark Finkle + * + * 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 +%include defines.inc +%define honeycomb 1 + +/* content scrollbars */ +.scroller { + opacity: 0; + background-color: rgba(0, 0, 0, 0.4) !important; + -moz-border-top-colors: none !important; + -moz-border-bottom-colors: none !important; + -moz-border-right-colors: none !important; + -moz-border-left-colors: none !important; + -moz-border-radius: @border_radius_tiny@; + border: @border_width_tiny@ solid rgba(255, 255, 255, 0.4) !important; +} + +.scroller[panning="true"] { + opacity: 1; +} + +.scroller[orient="vertical"] { + min-width: @scroller_thickness@; + width: @scroller_thickness@; + min-height: @scroller_minimum@; +} + +.scroller[orient="horizontal"] { + min-height: @scroller_thickness@; + height: @scroller_thickness@; + min-width: @scroller_minimum@; +} diff --git a/mobile/android/themes/core/honeycomb/defines.inc b/mobile/android/themes/core/honeycomb/defines.inc new file mode 100644 index 00000000000..309a6c82480 --- /dev/null +++ b/mobile/android/themes/core/honeycomb/defines.inc @@ -0,0 +1,165 @@ +%filter substitution + +%define color_background_active #fff +%define color_text_active #222222 +%define color_background_default_window #fff +%define color_background_default rgba(255,255,255,0.95) +%define color_text_default #222222 +%define color_toolbar_background #eaeaea +%define color_toolbar_border #d9d9d9 +%define color_divider_border #6699ff +%define color_url_border #737373 +%define color_background_button #d9d9d9 +%define color_background_button_disabled #e3e3e3 +%define color_background_button_overlay rgba(217, 217, 217, 0.8) +%define color_button_border rgb(207,207,207) +%define color_background_dialog #fff +%define color_text_dialog #000 +%define color_dialog_border #5a5a5a +%define color_background_dlgbuttons #9a9a9a +%define color_background_panel #d6d6d6 +%define color_text_panel #000 +%define color_background_header #6699ff +%define color_text_header #fff +%define color_background_scroller #9a9a9a +%define color_background_textbox #fff +%define color_text_textbox #000 +%define color_text_disabled #808080 +%define color_text_button #222 +%define color_text_button_disabled #999 +%define color_text_placeholder #808080 +%define color_text_as_link #69f +%define color_background_panelrow #c8c8c8 +%define color_text_panelrow #222222 +%define color_text_toolbutton_inverse #666666 +%define color_background_settings #efefef +%define color_text_panel_header #999 +%define color_text_panel_subheader #333 +%define color_background_toaster #000 + +%define color_background_highlight #a7c5f4 +%define color_background_highlight_overlay rgba(167, 197, 244, 0.8) +%define color_text_highlight #000 +%define color_selection #c0e49a +%define color_shadow #6699ff +%define color_shadow_light rgba(102,153,255, 0.2) +%define color_shadow_green rgba(137,251,21, 0.2) +%define color_shadow_grey rgba(200,200,200, 0.5) + +%define color_subtext_default #aaaaaa +%define color_subtext_settings #666666 + +%define font_xlarge 6.08mozmm +%define font_xnormal 3.75mozmm +%define font_normal 3.54mozmm +%define font_snormal 3mozmm +%define font_small 2.91mozmm +%define font_xsmall 2.69mozmm +%define font_tiny 2.48mozmm +%define font_xtiny 2.27mozmm +%define font_xxtiny 1.93mozmm + +%define touch_row 10.478mozmm +%define touch_button_xlarge 10.62mozmm +%define touch_button_large 9.77mozmm +%define touch_button_small 8.93mozmm +%define touch_button_minwidth 11.86mozmm +%define touch_action_minwidth 21.17mozmm +%define touch_button_tiny 3.75mozmm +%define touch_button_minwidth 16.30mozmm +%define touch_button_minwidth 11.86mozmm +%define touch_normal 6.77mozmm + +%define margin_toaster 15.24mozmm +%define margin_context_popup 3.39mozmm +%define margin_xlarge 3.39mozmm +%define margin_large 2.54mozmm +%define margin_xxxnormal 1.69mozmm +%define margin_xxnormal 1.27mozmm +%define margin_xnormal 1.06mozmm +%define margin_normal 0.85mozmm +%define margin_snormal 0.64mozmm +%define margin_small 0.42mozmm +%define margin_tiny 0.21mozmm +%define margin_xtiny 0.15mozmm + +%define padding_xxxlarge 13.35mozmm +%define padding_xxlarge 7.938mozmm +%define padding_xlarge 3.39mozmm +%define padding_large 2.54mozmm +%define padding_xxxnormal 1.69mozmm +%define padding_xxnormal 1.27mozmm +%define padding_xnormal 1.06mozmm +%define padding_normal 0.85mozmm +%define padding_snormal 0.64mozmm +%define padding_small 0.42mozmm +%define padding_xsmall 0.21mozmm +%define padding_tiny 0.11mozmm + +%define border_width_xxlarge 0.64mozmm +%define border_width_xlarge 0.42mozmm +%define border_width_large 0.32mozmm +%define border_width_small 0.21mozmm +%define border_width_tiny 0.11mozmm + +%define border_radius_normal 0.85mozmm +%define border_radius_small 0.64mozmm +%define border_radius_xsmall 0.31mozmm +%define border_radius_tiny 0.21mozmm + +%define shadow_width_xlarge 3.06mozmm +%define shadow_width_large 2.64mozmm +%define shadow_width_medium 0.75mozmm +%define shadow_width_small 0.21mozmm +%define shadow_width_tiny 0.1mozmm + +%define textbox_height 5.08mozmm + +%define dropmarker_padding 0.53mozmm + +%define progressmeter_height 3.39mozmm + +%define urlbar_edit_height 5.25mozmm +%define urlbar_edit_indent 0.85mozmm +%define identity_popup_tablet_width 72mozmm + +%define scroller_thickness 0.64mozmm +%define scroller_minimum 1.27mozmm + +%define sidebar_width_minimum 8.47mozmm +%define sidebar_button_height 7.41mozmm +%define documenttab_margin_bottom 0.85mozmm + +%define placelabel_padding 8.47mozmm +%define placeitem_padding 4.23mozmm + +%define awesome_header_maxwidth 25mozmm +%define autocomplete_item_container_image_padding 0.53mozmm +%define autocomplete_item_container_position 0.21mozmm +%define autocomplete_item_container_size 4mozmm +%define autocomplete_item_container_padding 5.08mozmm + +%define autocomplete_item_subtitle_margin 2.75mozmm +%define autocomplete_item_label_margin 3.18mozmm +%define autocomplete_item_tags_margin 3.39mozmm + +%define autocompleteresult_padding 0.53mozmm + +%define dialog_width 76.2mozmm + +%define appmenu_portrait_height 21.17mozmm +%define appmenu_button_height 10.48mozmm + +%define tablet_panel_controls 40mozmm +%define tablet_panel_controls_wide 55mozmm +%define tablet_panel_minwidth 124mozmm +%define tablet_panel_item_width 69mozmm +%define tablet_panel_item_width_wide 90mozmm + +%ifdef MOZ_PLATFORM_MAEMO +%define orientation -moz-device-orientation +%elifdef ANDROID +%define orientation -moz-device-orientation +%else +%define orientation orientation +%endif diff --git a/mobile/android/themes/core/honeycomb/images/aboutBackground.jpg b/mobile/android/themes/core/honeycomb/images/aboutBackground.jpg new file mode 100644 index 00000000000..5dba1c58eb5 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/aboutBackground.jpg differ diff --git a/mobile/android/themes/core/honeycomb/images/addons-default-hdpi.png b/mobile/android/themes/core/honeycomb/images/addons-default-hdpi.png new file mode 100644 index 00000000000..90ea938027a Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/addons-default-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/alert-addons-30.png b/mobile/android/themes/core/honeycomb/images/alert-addons-30.png new file mode 100644 index 00000000000..18744ad8522 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/alert-addons-30.png differ diff --git a/mobile/android/themes/core/honeycomb/images/alert-downloads-30.png b/mobile/android/themes/core/honeycomb/images/alert-downloads-30.png new file mode 100644 index 00000000000..2546352d28f Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/alert-downloads-30.png differ diff --git a/mobile/android/themes/core/honeycomb/images/arrowdown-16.png b/mobile/android/themes/core/honeycomb/images/arrowdown-16.png new file mode 100644 index 00000000000..c982426f2ad Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/arrowdown-16.png differ diff --git a/mobile/android/themes/core/honeycomb/images/arrowleft-16.png b/mobile/android/themes/core/honeycomb/images/arrowleft-16.png new file mode 100644 index 00000000000..464a4a866cd Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/arrowleft-16.png differ diff --git a/mobile/android/themes/core/honeycomb/images/arrowright-16.png b/mobile/android/themes/core/honeycomb/images/arrowright-16.png new file mode 100644 index 00000000000..859e98ba64b Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/arrowright-16.png differ diff --git a/mobile/android/themes/core/honeycomb/images/arrowup-16.png b/mobile/android/themes/core/honeycomb/images/arrowup-16.png new file mode 100644 index 00000000000..2a7e5648535 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/arrowup-16.png differ diff --git a/mobile/android/themes/core/honeycomb/images/back-default-hdpi.png b/mobile/android/themes/core/honeycomb/images/back-default-hdpi.png new file mode 100644 index 00000000000..0f868e75feb Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/back-default-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/browseaddons-bg.jpg b/mobile/android/themes/core/honeycomb/images/browseaddons-bg.jpg new file mode 100644 index 00000000000..dcd9a92b352 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/browseaddons-bg.jpg differ diff --git a/mobile/android/themes/core/honeycomb/images/button-bg.png b/mobile/android/themes/core/honeycomb/images/button-bg.png new file mode 100644 index 00000000000..0dbc5329eae Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/button-bg.png differ diff --git a/mobile/android/themes/core/honeycomb/images/check-selected-hdpi.png b/mobile/android/themes/core/honeycomb/images/check-selected-hdpi.png new file mode 100644 index 00000000000..10b067f39d5 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/check-selected-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/check-selected-tap-hdpi.png b/mobile/android/themes/core/honeycomb/images/check-selected-tap-hdpi.png new file mode 100644 index 00000000000..85c7ff80ff6 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/check-selected-tap-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/check-unselected-hdpi.png b/mobile/android/themes/core/honeycomb/images/check-unselected-hdpi.png new file mode 100644 index 00000000000..ca1e30df8b7 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/check-unselected-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/check-unselected-tap-hdpi.png b/mobile/android/themes/core/honeycomb/images/check-unselected-tap-hdpi.png new file mode 100644 index 00000000000..c478328b9ff Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/check-unselected-tap-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/dropmarker-hdpi.png b/mobile/android/themes/core/honeycomb/images/dropmarker-hdpi.png new file mode 100644 index 00000000000..7bef658caa1 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/dropmarker-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/errorpage-larry-black.png b/mobile/android/themes/core/honeycomb/images/errorpage-larry-black.png new file mode 100644 index 00000000000..9f2e4a6e736 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/errorpage-larry-black.png differ diff --git a/mobile/android/themes/core/honeycomb/images/errorpage-larry-white.png b/mobile/android/themes/core/honeycomb/images/errorpage-larry-white.png new file mode 100644 index 00000000000..fc153c7314e Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/errorpage-larry-white.png differ diff --git a/mobile/android/themes/core/honeycomb/images/errorpage-warning.png b/mobile/android/themes/core/honeycomb/images/errorpage-warning.png new file mode 100644 index 00000000000..8bf9d8e7dec Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/errorpage-warning.png differ diff --git a/mobile/android/themes/core/honeycomb/images/favicon-default-32.png b/mobile/android/themes/core/honeycomb/images/favicon-default-32.png new file mode 100644 index 00000000000..8e66e5ae57e Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/favicon-default-32.png differ diff --git a/mobile/android/themes/core/honeycomb/images/forward-default-hdpi.png b/mobile/android/themes/core/honeycomb/images/forward-default-hdpi.png new file mode 100644 index 00000000000..57611d4dc20 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/forward-default-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/locked-hdpi.png b/mobile/android/themes/core/honeycomb/images/locked-hdpi.png new file mode 100644 index 00000000000..766a56746fe Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/locked-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/menu-hdpi.png b/mobile/android/themes/core/honeycomb/images/menu-hdpi.png new file mode 100644 index 00000000000..96ba76a2a4a Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/menu-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/menu-top-insideglow-green.png b/mobile/android/themes/core/honeycomb/images/menu-top-insideglow-green.png new file mode 100644 index 00000000000..61219f16108 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/menu-top-insideglow-green.png differ diff --git a/mobile/android/themes/core/honeycomb/images/menu-top-insideglow-grey.png b/mobile/android/themes/core/honeycomb/images/menu-top-insideglow-grey.png new file mode 100644 index 00000000000..70d2d2ea76f Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/menu-top-insideglow-grey.png differ diff --git a/mobile/android/themes/core/honeycomb/images/menu-top-insideglow.png b/mobile/android/themes/core/honeycomb/images/menu-top-insideglow.png new file mode 100644 index 00000000000..7bf59d5706f Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/menu-top-insideglow.png differ diff --git a/mobile/android/themes/core/honeycomb/images/mute-hdpi.png b/mobile/android/themes/core/honeycomb/images/mute-hdpi.png new file mode 100644 index 00000000000..0bd1e60e6a3 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/mute-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/navigation-magnifier-30.png b/mobile/android/themes/core/honeycomb/images/navigation-magnifier-30.png new file mode 100644 index 00000000000..5ca622b354c Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/navigation-magnifier-30.png differ diff --git a/mobile/android/themes/core/honeycomb/images/next-disabled-hdpi.png b/mobile/android/themes/core/honeycomb/images/next-disabled-hdpi.png new file mode 100644 index 00000000000..81e68769e09 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/next-disabled-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/next-hdpi.png b/mobile/android/themes/core/honeycomb/images/next-hdpi.png new file mode 100644 index 00000000000..c0115d49148 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/next-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/panelrow-active-hdpi.png b/mobile/android/themes/core/honeycomb/images/panelrow-active-hdpi.png new file mode 100644 index 00000000000..23676c11c47 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/panelrow-active-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/panelrow-default-hdpi.png b/mobile/android/themes/core/honeycomb/images/panelrow-default-hdpi.png new file mode 100644 index 00000000000..d8143e245c9 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/panelrow-default-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/panelrow-selected-hdpi.png b/mobile/android/themes/core/honeycomb/images/panelrow-selected-hdpi.png new file mode 100644 index 00000000000..5e8dc6eb3a9 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/panelrow-selected-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/pause-hdpi.png b/mobile/android/themes/core/honeycomb/images/pause-hdpi.png new file mode 100644 index 00000000000..e377d321ce0 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/pause-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/play-hdpi.png b/mobile/android/themes/core/honeycomb/images/play-hdpi.png new file mode 100644 index 00000000000..a8482eb4dd7 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/play-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/popup-bg-hdpi.png b/mobile/android/themes/core/honeycomb/images/popup-bg-hdpi.png new file mode 100644 index 00000000000..df8e20c929f Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/popup-bg-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/popup-selected-item-hdpi.png b/mobile/android/themes/core/honeycomb/images/popup-selected-item-hdpi.png new file mode 100644 index 00000000000..dd511023c1f Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/popup-selected-item-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/previous-disabled-hdpi.png b/mobile/android/themes/core/honeycomb/images/previous-disabled-hdpi.png new file mode 100644 index 00000000000..459f5ab7de4 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/previous-disabled-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/previous-hdpi.png b/mobile/android/themes/core/honeycomb/images/previous-hdpi.png new file mode 100644 index 00000000000..530206d58a5 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/previous-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/remotetabs-32.png b/mobile/android/themes/core/honeycomb/images/remotetabs-32.png new file mode 100644 index 00000000000..80f59a022c3 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/remotetabs-32.png differ diff --git a/mobile/android/themes/core/honeycomb/images/row-header-bg.png b/mobile/android/themes/core/honeycomb/images/row-header-bg.png new file mode 100644 index 00000000000..aaefd0f3d98 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/row-header-bg.png differ diff --git a/mobile/android/themes/core/honeycomb/images/scrubber-hdpi.png b/mobile/android/themes/core/honeycomb/images/scrubber-hdpi.png new file mode 100644 index 00000000000..49c60505f46 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/scrubber-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/search-clear-30.png b/mobile/android/themes/core/honeycomb/images/search-clear-30.png new file mode 100644 index 00000000000..8bab39a08d3 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/search-clear-30.png differ diff --git a/mobile/android/themes/core/honeycomb/images/search-glass-30.png b/mobile/android/themes/core/honeycomb/images/search-glass-30.png new file mode 100644 index 00000000000..71bf1f255ee Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/search-glass-30.png differ diff --git a/mobile/android/themes/core/honeycomb/images/sidebarbutton-active-hdpi.png b/mobile/android/themes/core/honeycomb/images/sidebarbutton-active-hdpi.png new file mode 100644 index 00000000000..30f1d2017bc Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/sidebarbutton-active-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/tabs-default-bg-rtl.png b/mobile/android/themes/core/honeycomb/images/tabs-default-bg-rtl.png new file mode 100644 index 00000000000..0700a979123 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/tabs-default-bg-rtl.png differ diff --git a/mobile/android/themes/core/honeycomb/images/tabs-default-bg.png b/mobile/android/themes/core/honeycomb/images/tabs-default-bg.png new file mode 100644 index 00000000000..0762ade997d Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/tabs-default-bg.png differ diff --git a/mobile/android/themes/core/honeycomb/images/tabs-hdpi.png b/mobile/android/themes/core/honeycomb/images/tabs-hdpi.png new file mode 100644 index 00000000000..95b43ce975a Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/tabs-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/tabs-selected-bg-rtl.png b/mobile/android/themes/core/honeycomb/images/tabs-selected-bg-rtl.png new file mode 100644 index 00000000000..06d4647fd60 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/tabs-selected-bg-rtl.png differ diff --git a/mobile/android/themes/core/honeycomb/images/tabs-selected-bg.png b/mobile/android/themes/core/honeycomb/images/tabs-selected-bg.png new file mode 100644 index 00000000000..3bf979e4cfc Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/tabs-selected-bg.png differ diff --git a/mobile/android/themes/core/honeycomb/images/textbox-bg.png b/mobile/android/themes/core/honeycomb/images/textbox-bg.png new file mode 100644 index 00000000000..40edca065d6 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/textbox-bg.png differ diff --git a/mobile/android/themes/core/honeycomb/images/throbber.png b/mobile/android/themes/core/honeycomb/images/throbber.png new file mode 100644 index 00000000000..c601ec80ba7 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/throbber.png differ diff --git a/mobile/android/themes/core/honeycomb/images/toggle-off.png b/mobile/android/themes/core/honeycomb/images/toggle-off.png new file mode 100644 index 00000000000..a27900e1fe4 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/toggle-off.png differ diff --git a/mobile/android/themes/core/honeycomb/images/toggle-on.png b/mobile/android/themes/core/honeycomb/images/toggle-on.png new file mode 100644 index 00000000000..a7dc009d5ea Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/toggle-on.png differ diff --git a/mobile/android/themes/core/honeycomb/images/unlocked-hdpi.png b/mobile/android/themes/core/honeycomb/images/unlocked-hdpi.png new file mode 100644 index 00000000000..2b993352a4d Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/unlocked-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/unmute-hdpi.png b/mobile/android/themes/core/honeycomb/images/unmute-hdpi.png new file mode 100644 index 00000000000..4dbb94f98f0 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/unmute-hdpi.png differ diff --git a/mobile/android/themes/core/honeycomb/images/urlbar-border-bottom-active.png b/mobile/android/themes/core/honeycomb/images/urlbar-border-bottom-active.png new file mode 100644 index 00000000000..0c2e114032e Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/urlbar-border-bottom-active.png differ diff --git a/mobile/android/themes/core/honeycomb/images/urlbar-border-bottom.png b/mobile/android/themes/core/honeycomb/images/urlbar-border-bottom.png new file mode 100644 index 00000000000..d527d50bbf5 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/urlbar-border-bottom.png differ diff --git a/mobile/android/themes/core/honeycomb/images/urlbar-border-side-active.png b/mobile/android/themes/core/honeycomb/images/urlbar-border-side-active.png new file mode 100644 index 00000000000..d422717f790 Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/urlbar-border-side-active.png differ diff --git a/mobile/android/themes/core/honeycomb/images/urlbar-border-side.png b/mobile/android/themes/core/honeycomb/images/urlbar-border-side.png new file mode 100644 index 00000000000..fe299ea362e Binary files /dev/null and b/mobile/android/themes/core/honeycomb/images/urlbar-border-side.png differ diff --git a/mobile/android/themes/core/honeycomb/platform.css b/mobile/android/themes/core/honeycomb/platform.css new file mode 100644 index 00000000000..b359b2c126b --- /dev/null +++ b/mobile/android/themes/core/honeycomb/platform.css @@ -0,0 +1,877 @@ +/* ***** 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): + * Mark Finkle + * + * 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 ***** */ + +/* global skin ------------------------------------------------------------- */ +@import url(chrome://global/skin/); + +%filter substitution +%include defines.inc + +/* general stuff ------------------------------------------------------------ */ +:root { + font-family: "Nokia Sans", Tahoma, sans-serif !important; + font-size: @font_normal@ !important; + background-color: @color_background_default_window@; /* force */ + color: @color_text_default@; /* force */ +} + +::-moz-selection { + background-color: @color_selection@; + color: @color_text_highlight@; +} + +menu, +menuitem { + padding: 0 !important; + margin: 0 !important; +} + +description, +label { + /* force mac to use the same margins as windows and linux */ + -moz-margin-start: @margin_snormal@; + -moz-margin-end: @margin_snormal@; +} + +/* Override any OS inverse themes */ +textbox { + color: @color_text_textbox@; + background-color: @color_background_textbox@; +} + +/* textboxes --------------------------------------------------------------- */ +textbox:not([type="number"]) { + min-height: @textbox_height@; + border: @border_width_small@ solid @color_button_border@; + -moz-border-top-colors: -moz-initial; + -moz-border-right-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; +} + +textbox[isempty="true"] { + color: @color_text_placeholder@; +} + +textbox.search-bar { + border: @border_width_small@ solid rgba(0,0,0,0.4); + background-color: #f9f9f9; + background: url("chrome://browser/skin/images/textbox-bg.png") top left repeat-x; + background-size: 100% 100%; +} + +textbox[disabled="true"] { + background-color: lightgray; +} + +.link { + color: @color_text_as_link@; + text-decoration: underline; +} + +/* sidebars spacer --------------------------------------------------------- */ +.sidebar-spacer { + background-color: #767973; +} + +/* prompt dialogs ---------------------------------------------------------- */ +.context-block, +.modal-block, +.perm-modal-block { + -moz-box-align: center; + -moz-box-pack: center; + background-color: rgba(0,0,0,.6); +} + +.dialog-dark, +.panel-arrowcontent { + background-color: @color_background_default@; + padding: 0; + box-shadow: 0 0 @shadow_width_tiny@ @shadow_width_medium@ @color_shadow_light@; +} + +.panel-arrowcontent { + background-image: url(chrome://browser/skin/images/menu-top-insideglow.png); + background-repeat: repeat-x; + background-position: top left; +} + +dialog > .prompt-header > .prompt-message { + white-space: pre-wrap; +} + +dialog > .prompt-header > .button-checkbox { + margin-left: @margin_large@; +} + +/* buttons ----------------------------------------------------------------- */ +.button-text, +.toolbarbutton-text { + font-weight: normal; + font-size: @font_xtiny@ !important; +} + +button { + -moz-appearance: none; + min-width: @touch_button_minwidth@ !important; + min-height: @touch_button_tiny@ !important; /* button size */ + color: @color_text_button@; + background-image: none; + background-color: @color_background_button@; + margin: @margin_normal@; + padding: @padding_xnormal@; + border-width: 0px; + border-radius: 0px; +} + +button[disabled="true"] { + color: @color_text_button_disabled@ !important; + background-color: @color_background_button_disabled@; +} + +button:not([disabled]):hover:active, +button:not([disabled])[checked="true"] { + background-color: @color_background_highlight@; +} + +/* Override GTK2 system setting */ +.button-icon { + display: -moz-initial !important; +} + +/* spinbuttons ------------------------------------------------------------- */ +spinbuttons { + border: none !important; +} + +.numberbox-input-box { + border: @border_width_small@ solid @color_button_border@; + border-right: 0 solid transparent; + -moz-border-top-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; +} + +.numberbox-input-box:-moz-locale-dir(rtl) { + border-right: @border_width_small@ solid @color_button_border@; + border-left: 0 solid transparent; +} + +.spinbuttons-box { + border: none !important; + -moz-box-orient: horizontal !important; + -moz-box-direction: reverse !important; +} + +.spinbuttons-up .button-icon, +.spinbuttons-down .button-icon { + display: block; +} + +.spinbuttons-up, +.spinbuttons-down { + -moz-appearance: none !important; + min-width: @touch_button_small@ !important; /* button size */ + min-height: @touch_button_small@ !important; /* button size */ + color: @color_text_button@; + margin: @margin_normal@; + padding: @padding_xnormal@; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border: @border_width_tiny@ solid @color_button_border@; + list-style-image: url("chrome://browser/skin/images/arrowdown-16.png"); +} + +.spinbuttons-up:hover:active:not([disabled=true]), +.spinbuttons-down:hover:active:not([disabled=true]) { + background-image: url("chrome://browser/skin/images/toggle-on.png"); +} + +.spinbuttons-up { + list-style-image: url("chrome://browser/skin/images/arrowup-16.png"); +} + +/* toolbar buttons --------------------------------------------------------- */ +toolbar { + -moz-appearance: none; + background-color: @color_background_default@; + max-height: @touch_button_small@; +} + +toolbarbutton { + min-width: @touch_button_small@ !important; /* primary button size */ + min-height: @touch_button_small@ !important; /* primary button size */ + -moz-appearance: none !important; + padding: @padding_xsmall@; +} + +toolbarbutton:not(.show-text) .toolbarbutton-text { + display: none; +} + +.toolbarbutton-icon[label]:not([label=""]), +.toolbarbutton-icon[type="menu"] { + -moz-margin-end: @margin_tiny@; +} + +toolbarbutton:not(.show-text) .toolbarbutton-icon, +toolbarbutton:not([image]) .toolbarbutton-icon, +toolbarbutton[image=''] .toolbarbutton-icon { + -moz-margin-end: 0; +} + +toolbarbutton:hover, +toolbarbutton:hover:active, +toolbarbutton[open="true"] { + border-color: transparent; +} + +toolbarbutton:not([disabled="true"]):active, +toolbarbutton:not([disabled="true"])[open="true"] { + background-color: @color_background_highlight@; +} + +/* checkbox buttons ----------------------------------------------------------- */ +.button-checkbox { + padding: 0 !important; + background: none !important; + border: none !important; + -moz-border-image: none !important; + color: @color_text_default@; + -moz-box-align: center; + font-size: @font_small@; + -moz-box-align: center; +} + +.prompt-checkbox-label { + text-align: left; +} + +.button-checkbox > .button-image-icon { + -moz-margin-end: @margin_normal@; + list-style-image: url("chrome://browser/skin/images/check-unselected-hdpi.png"); +} + +.button-checkbox[checked="true"] > .button-image-icon { + list-style-image: url("chrome://browser/skin/images/check-selected-hdpi.png"); +} + +.button-checkbox > .button-box, +.button-checkbox:hover:active > .button-box, +.button-checkbox[checked="true"] > .button-box { + padding-top: @padding_tiny@; + padding-bottom: @padding_xsmall@; + -moz-padding-start: @padding_small@; + -moz-padding-end: @padding_small@; +} + +/* radio buttons ----------------------------------------------------------- */ +radiogroup { + -moz-box-orient: horizontal; +} + +.radio-label { + font-weight: normal; + font-size: @font_snormal@ !important; +} + +radio { + -moz-appearance: none; + min-width: @touch_button_small@ !important; /* button size */ + min-height: @touch_button_small@ !important; /* button size */ + color: @color_text_button@; + padding: @padding_xnormal@; + margin: 0; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border-top: @border_width_tiny@ solid @color_button_border@; + border-bottom: @border_width_tiny@ solid @color_button_border@; +} + +radio .radio-icon, radio .radio-check { + display: none; +} + +radio:not([disabled=true]):hover:active, +radio[selected] { + color: white; + background-image: url("chrome://browser/skin/images/toggle-on.png"); +} + +radio:first-child { + border-left: @border_width_tiny@ solid @color_button_border@; +} + +radio:first-child:-moz-locale-dir(rtl) { + border-left: none; + border-right: @border_width_tiny@ solid @color_button_border@; +} + +radio:last-child { + border-right: @border_width_tiny@ solid @color_button_border@; +} + +radio:last-child:-moz-locale-dir(rtl) { + border-right: none; + border-left: @border_width_tiny@ solid @color_button_border@; +} + +radio[focused="true"] > .radio-label-box { + border: @border_width_tiny@ solid transparent; +} + +/* checkbox --------------------------------------------------------------- */ +checkbox { + margin: @margin_tiny@ @margin_small@ @margin_tiny@ @margin_small@; /* match platform style for buttons */ + -moz-binding: url("chrome://global/content/bindings/checkbox.xml#checkbox-with-spacing") !important; +} + +/* stop the focus from moving/showing the border around the label, which we don't use */ +checkbox:focus > .checkbox-label-center-box > .checkbox-label-box { + border: 1px solid transparent; +} + +.checkbox-check { + border: 2px transparent; + -moz-border-top-colors: -moz-initial; + -moz-border-right-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; + width: 46px; + height: 46px; + background: url("chrome://browser/skin/images/check-unselected-hdpi.png") no-repeat 50% 50%; +} + +checkbox[checked="true"] > .checkbox-spacer-box > .checkbox-check { + background-image: url("chrome://browser/skin/images/check-selected-hdpi.png"); +} + +checkbox[checked="true"][disabled="true"] > .checkbox-spacer-box > .checkbox-check { + background-image: url("chrome://browser/skin/images/check-selected-hdpi.png"); +} + +/* richlistbox ------------------------------------------------------------- */ +richlistbox { + color: @color_text_default@; + background-color: transparent; + -moz-user-focus: ignore; + margin: 0; +} + +richlistitem { + -moz-user-focus: ignore; + min-height: @touch_row@; /* row size */ + padding: @padding_small@; + border-bottom: @border_width_tiny@ solid @color_button_border@; +} + +richlistitem:last-child, +richlistitem[selector="last-child"] { + border-bottom: none; +} + +richlistitem label.title, +richlistitem description.title { + font-size: @font_snormal@ !important; +} + +richlistitem label.normal, +richlistitem description.normal { + color: @color_subtext_default@; + font-size: @font_xtiny@ !important; + white-space: pre-wrap; + word-wrap: break-word; +} + +richlistitem label.normal-black, +richlistitem description.normal-black { + font-size: @font_xtiny@ !important; + white-space: pre-wrap; + word-wrap: break-word; +} + +richlistitem label.normal-bold, +richlistitem description.normal-bold { + font-weight: bold; + font-size: @font_xtiny@ !important; + white-space: pre-wrap; + word-wrap: break-word; +} + +richlistitem[selected="true"] { + color: @color_text_default@; + background-color: @color_background_default@; +} + +richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]), +richlistitem:hover:active:not([selected="true"]):not([class="section-header"]), +richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]) label.normal, +richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]) description.normal { + background-color: @color_background_highlight@; + color: @color_text_highlight@; +} + +richlistitem.section-header, +richlistitem[selected="true"].section-header { + font-size: @font_xtiny@; + font-weight: bold; + color: @color_text_panel_subheader@; + background-color: @color_background_button@; + margin: 0; + padding: @padding_xxnormal@ @padding_large@; + border-top: @border_width_tiny@ solid @color_background_settings@; + border-bottom: @border_width_large@ solid; + -moz-border-bottom-colors: @color_background_button@ @color_background_settings@; +} + +richlistitem .show-on-select { + visibility: collapse; +} + +richlistitem[selected="true"] .show-on-select { + visibility: visible; +} + +richlistitem .hide-on-select { + visibility: visible; +} + +richlistitem[selected="true"] .hide-on-select { + visibility: collapse; +} + +richlistitem[typeName="message"] { + border-bottom: 0; +} + +richlistitem setting { + -moz-padding-start: 0; + -moz-padding-end: 0; +} + +richlistitem setting:first-child { + border-top: @border_width_tiny@ solid @color_background_button@; +} + +richlistitem[isDisabled="true"] .title, +richlistitem[isDisabled="true"] .normal { + color: @color_text_disabled@; +} + +richlistitem[isDisabled="true"] image { + opacity: 0.25; +} + +/* colorpicker ------------------------------------------------------------- */ +colorpicker > panel { + background-color: #767973; +} + +colorpicker > vbox { + background-color: #767973; +} + +/* textbox ----------------------------------------------------------------- */ +.textbox-search-icon { + list-style-image: url("chrome://browser/skin/images/search-glass-30.png"); + -moz-image-region: auto; +} + +.textbox-search-clear { + list-style-image: url("chrome://browser/skin/images/search-clear-30.png"); + -moz-image-region: auto; +} + +/* menulist ---------------------------------------------------------------- */ +.menulist-label { + font-family: "Nokia Sans", Tahoma, sans-serif !important; + font-weight: normal; + font-size: @font_xtiny@; + background-color: transparent !important; +} + +menulist { + -moz-appearance: none !important; + -moz-user-focus: ignore; + min-width: @touch_button_minwidth@ !important; + min-height: @touch_button_tiny@ !important; /* button size */ + color: @color_text_button@ !important; + background-color: @color_background_button@; + margin: @margin_normal@; + padding: @padding_xsmall@ @padding_xnormal@; + border-width: 0; + border-radius: 0; +} + +menulist[disabled="true"] { + color: @color_text_button_disabled@ !important; + background-color: @color_background_button_disabled@; +} + +menulist:not([disabled="true"]):hover:active { + background-color: @color_background_highlight@; +} + +menulist > dropmarker { + height: 32px; + width: 32px; + margin-left: @margin_snormal@; + background-color: transparent; /* for windows */ + border: none; /* for windows */ + -moz-box-align: center; + -moz-box-pack: center; + list-style-image: url("chrome://browser/skin/images/dropmarker-hdpi.png"); + -moz-image-region: auto; + display: block; +} + +menulist[disabled="true"] > dropmarker { + opacity: 0.5; +} + +/* progressmeter ----------------------------------------------------------- */ +progressmeter { + background-color: #fff; + padding: @padding_small@; + height: @textbox_height@; + border: @border_width_large@ solid #aaa; + -moz-border-top-colors: -moz-initial; + -moz-border-right-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; +} + +.progress-bar { + background-color: @color_background_highlight@; +} + +/* panels / arrowboxes------------------------------------------------------ */ +arrowbox { + -moz-appearance: none; + background: transparent !important; + border: none; +} + +.panel-arrow { + min-height: 18px; +} + +.arrowbox-dark .panel-arrowcontent { + padding: @padding_normal@; /* core spacing */ +} + +dialog, +.arrowbox-dark .panel-arrowcontent, +.panel-dark, +.dialog-dark { + color: @color_text_default@; + background: @color_background_default@; +} + +dialog { + border: @border_width_small@ solid @color_dialog_border@; + box-shadow: 0 0 @shadow_width_tiny@ @shadow_width_medium@ @color_shadow_light@; +} + +dialog, +.dialog-dark { + margin: @margin_xxxnormal@ !important; +} + +#context-popup, +#menulist-popup, +dialog { + margin: @margin_xxxnormal@ !important; + max-width: @dialog_width@; + -moz-box-flex: 1; +} + +.prompt-message { + -moz-box-pack: center; + font-size: @font_snormal@; + padding: @padding_normal@ @padding_large@; + min-height: @touch_row@; +} + +.prompt-header { + border-bottom: @border_width_tiny@ solid @color_button_border@; + margin: 0px @margin_large@ !important; +} + +.prompt-title { + font-size: @font_snormal@; + min-height: @touch_row@; + padding: @padding_xlarge@ @padding_large@; + margin: 0px; +} + +/* Authentication dialogs do not have a title */ +.prompt-title:empty, +.prompt-title:empty + .prompt-line { + display: none; +} + +.prompt-line { + background-color: transparent; + border-bottom: @border_width_xxlarge@ solid @color_divider_border@; + height: @border_width_xxlarge@ !important; +} + +.prompt-buttons { + font-size: @font_snormal@; + background-color: transparent; + text-align: center; +} + +.prompt-edit { + margin: @margin_xnormal@; + font-size: @font_normal@; + text-align: start; +} + +/*.panel-row-header ------------------------------------------------------------ */ +.panel-row-header { + background-color: @color_background_panelrow@ !important; + color: @color_text_panelrow@; + padding: 0 !important; +} + +.prompt-button, +.panel-row-button { + color: @color_text_panelrow@; + -moz-appearance: none; + border: @border_width_tiny@ solid transparent; + -moz-user-focus: ignore; + -moz-user-select: none; + margin: @margin_xtiny@; + -moz-margin-end: -moz-calc(2 * @margin_xtiny@); + padding: @padding_normal@ 0px !important; + -moz-box-flex: 1; + background-image: none; + background-color: transparent; + border-radius: 0px !important; +} + +.prompt-button[disabled="true"] { + border: none !important; +} + +.prompt-button > .button-box { + -moz-border-end: @border_width_tiny@ solid @color_button_border@; + -moz-border-right-colors: transparent @color_button_border@; + -moz-margin-end: -moz-calc(-3 * @border_width_tiny@); + padding: @padding_xxxnormal@ 0; +} + +.prompt-button:last-of-type { + -moz-margin-end: @margin_xtiny@; +} + +.prompt-button:last-of-type > .button-box { + -moz-border-end: none; +} + +.prompt-button:not([disabled]):hover:active, +.panel-row-button:hover:active { + background-image: none; + background-color: @color_background_highlight@; + color: @color_text_highlight@; +} + +.prompt-button { + min-width: 33%; + min-height: @touch_button_small@; +} + +.prompt-button .button-text { + font-size: @font_snormal@ !important; +} + +.panel-row-button:first-child { + -moz-border-start-width: 0 !important; +} + +.panel-row-button:last-child { + -moz-border-end-width: 0 !important; +} + +@media (@orientation@: portrait) { + .panel-row-button { + -moz-box-orient: vertical; + } +} + +@media (@orientation@: portrait) and (min-width: @tablet_panel_minwidth@) { + #panel-controls > .panel-row-button { + min-width: @tablet_panel_controls@ !important; + } + + #panel-items { + max-width: @tablet_panel_item_width@ !important; + } +} + +@media (@orientation@: landscape) and (min-width: @tablet_panel_minwidth@) { + #panel-controls > .panel-row-button { + min-width: @tablet_panel_controls_wide@ !important; + } + + #panel-items { + max-width: @tablet_panel_item_width_wide@ !important; + } +} + +.panel-row-button .toolbarbutton-text { + text-align: left; + font-size: @font_xtiny@ !important; +} + +.panel-row-button .toolbarbutton-text:-moz-locale-dir(rtl) { + text-align: right; +} + +.panel-row-button[disabled="true"] { + pointer-events: none; +} + +.panel-row-button[disabled="true"] .toolbarbutton-icon { + opacity: 0.5; +} + +.panel-row-button[disabled="true"] .toolbarbutton-text { + color: @color_text_disabled@; +} + +.panel-row-button[checked="true"] { + background: @color_background_default_window@; + color: @color_text_default@; +} + +.panel-row-button[checked="true"], +.panel-row-button[disabled="true"] { + pointer-events: none; +} + +#panel-container { + background-color: @color_background_settings@ !important; +} + +#panel-container-inner { + -moz-box-orient: vertical; + background-color: transparent !important; +} + +#panel-container-inner > vbox { + border: @border_width_large@ solid @color_background_active@; + box-shadow: 0 0 @shadow_width_tiny@ @shadow_width_medium@ @color_background_button_overlay@; +} + +#panel-controls { + -moz-box-orient: horizontal; + background-color: transparent !important; + padding: @padding_xxxnormal@ 0 !important; +} + +#panel-controls .toolbarbutton-text { + font-size: @font_snormal@ !important; +} + +#panel-controls .toolbarbutton-icon[label]:not([label=""]), +#panel-controls .toolbarbutton-icon[type="menu"] { + -moz-margin-start: @margin_xxxnormal@; + -moz-margin-end: @margin_xnormal@; +} + +#panel-controls > .panel-row-button { + border-top: @border_width_tiny@ solid @color_background_settings@ !important; + border-bottom: @border_width_large@ solid !important; + -moz-border-bottom-colors: @color_background_button@ @color_background_settings@ !important; + -moz-border-start: 0 solid; + -moz-border-end: 0 solid; +} + +#panel-controls > .panel-row-button[checked="true"] { + background-color: @color_background_highlight@; + color: @color_text_default@; +} + +.panel-list { + background: transparent; +} + +@media (min-width: @tablet_panel_minwidth@) { + #panel-container-inner { + -moz-box-orient: horizontal; + -moz-box-pack: center; + } + + #panel-items { + min-width: 0px !important; + } + + /* This will affect the prefs screen, but not the awesome screen */ + #panel-controls { + -moz-box-orient: vertical !important; + -moz-box-align: start; + } + + #panel-controls > .panel-row-button { + margin: 0; + -moz-box-orient: horizontal; + -moz-box-flex: 0; + } + + #panel-controls .toolbarbutton-text { + display: -moz-box !important; + -moz-box-flex: 1; + } + + #panel-container { + -moz-box-pack: center; + padding: @padding_xxxlarge@ 0 @padding_xlarge@ 0; + } + + #panel-container-inner > vbox { + padding: @padding_xlarge@ @padding_xxlarge@; + } +} + +/* because the buttons can wrap, we need to use the margin to create inter-button + spacing and a bottom margin for the notification */ +notification > button { + margin-bottom: @margin_normal@; +} diff --git a/mobile/android/themes/core/images/aboutBackground.jpg b/mobile/android/themes/core/images/aboutBackground.jpg new file mode 100644 index 00000000000..5dba1c58eb5 Binary files /dev/null and b/mobile/android/themes/core/images/aboutBackground.jpg differ diff --git a/mobile/android/themes/core/images/addons-32.png b/mobile/android/themes/core/images/addons-32.png new file mode 100644 index 00000000000..9679afd823c Binary files /dev/null and b/mobile/android/themes/core/images/addons-32.png differ diff --git a/mobile/android/themes/core/images/addons-default-hdpi.png b/mobile/android/themes/core/images/addons-default-hdpi.png new file mode 100644 index 00000000000..25f09906e01 Binary files /dev/null and b/mobile/android/themes/core/images/addons-default-hdpi.png differ diff --git a/mobile/android/themes/core/images/alert-addons-30.png b/mobile/android/themes/core/images/alert-addons-30.png new file mode 100644 index 00000000000..18744ad8522 Binary files /dev/null and b/mobile/android/themes/core/images/alert-addons-30.png differ diff --git a/mobile/android/themes/core/images/alert-downloads-30.png b/mobile/android/themes/core/images/alert-downloads-30.png new file mode 100644 index 00000000000..2546352d28f Binary files /dev/null and b/mobile/android/themes/core/images/alert-downloads-30.png differ diff --git a/mobile/android/themes/core/images/arrowdown-16.png b/mobile/android/themes/core/images/arrowdown-16.png new file mode 100644 index 00000000000..c982426f2ad Binary files /dev/null and b/mobile/android/themes/core/images/arrowdown-16.png differ diff --git a/mobile/android/themes/core/images/arrowleft-16.png b/mobile/android/themes/core/images/arrowleft-16.png new file mode 100644 index 00000000000..464a4a866cd Binary files /dev/null and b/mobile/android/themes/core/images/arrowleft-16.png differ diff --git a/mobile/android/themes/core/images/arrowright-16.png b/mobile/android/themes/core/images/arrowright-16.png new file mode 100644 index 00000000000..859e98ba64b Binary files /dev/null and b/mobile/android/themes/core/images/arrowright-16.png differ diff --git a/mobile/android/themes/core/images/arrowup-16.png b/mobile/android/themes/core/images/arrowup-16.png new file mode 100644 index 00000000000..2a7e5648535 Binary files /dev/null and b/mobile/android/themes/core/images/arrowup-16.png differ diff --git a/mobile/android/themes/core/images/aurora-lightbox-bg.jpg b/mobile/android/themes/core/images/aurora-lightbox-bg.jpg new file mode 100644 index 00000000000..e25ca85aa8a Binary files /dev/null and b/mobile/android/themes/core/images/aurora-lightbox-bg.jpg differ diff --git a/mobile/android/themes/core/images/aurora-lightbox-close.png b/mobile/android/themes/core/images/aurora-lightbox-close.png new file mode 100644 index 00000000000..394e7c4d354 Binary files /dev/null and b/mobile/android/themes/core/images/aurora-lightbox-close.png differ diff --git a/mobile/android/themes/core/images/aurora-lightbox-logo.png b/mobile/android/themes/core/images/aurora-lightbox-logo.png new file mode 100644 index 00000000000..12cb9d7e22b Binary files /dev/null and b/mobile/android/themes/core/images/aurora-lightbox-logo.png differ diff --git a/mobile/android/themes/core/images/back-default-hdpi.png b/mobile/android/themes/core/images/back-default-hdpi.png new file mode 100644 index 00000000000..8c2387cfcbe Binary files /dev/null and b/mobile/android/themes/core/images/back-default-hdpi.png differ diff --git a/mobile/android/themes/core/images/browseaddons-bg.jpg b/mobile/android/themes/core/images/browseaddons-bg.jpg new file mode 100644 index 00000000000..dcd9a92b352 Binary files /dev/null and b/mobile/android/themes/core/images/browseaddons-bg.jpg differ diff --git a/mobile/android/themes/core/images/button-bg.png b/mobile/android/themes/core/images/button-bg.png new file mode 100644 index 00000000000..0dbc5329eae Binary files /dev/null and b/mobile/android/themes/core/images/button-bg.png differ diff --git a/mobile/android/themes/core/images/check-30.png b/mobile/android/themes/core/images/check-30.png new file mode 100644 index 00000000000..82cf8f415fa Binary files /dev/null and b/mobile/android/themes/core/images/check-30.png differ diff --git a/mobile/android/themes/core/images/check-selected-30.png b/mobile/android/themes/core/images/check-selected-30.png new file mode 100644 index 00000000000..a29f65655ef Binary files /dev/null and b/mobile/android/themes/core/images/check-selected-30.png differ diff --git a/mobile/android/themes/core/images/check-unselected-30.png b/mobile/android/themes/core/images/check-unselected-30.png new file mode 100644 index 00000000000..054c7373b40 Binary files /dev/null and b/mobile/android/themes/core/images/check-unselected-30.png differ diff --git a/mobile/android/themes/core/images/checkmark-hdpi.png b/mobile/android/themes/core/images/checkmark-hdpi.png new file mode 100644 index 00000000000..affc84c6960 Binary files /dev/null and b/mobile/android/themes/core/images/checkmark-hdpi.png differ diff --git a/mobile/android/themes/core/images/dropmarker-hdpi.png b/mobile/android/themes/core/images/dropmarker-hdpi.png new file mode 100644 index 00000000000..960fbd6ab24 Binary files /dev/null and b/mobile/android/themes/core/images/dropmarker-hdpi.png differ diff --git a/mobile/android/themes/core/images/errorpage-larry-black.png b/mobile/android/themes/core/images/errorpage-larry-black.png new file mode 100644 index 00000000000..9f2e4a6e736 Binary files /dev/null and b/mobile/android/themes/core/images/errorpage-larry-black.png differ diff --git a/mobile/android/themes/core/images/errorpage-larry-white.png b/mobile/android/themes/core/images/errorpage-larry-white.png new file mode 100644 index 00000000000..fc153c7314e Binary files /dev/null and b/mobile/android/themes/core/images/errorpage-larry-white.png differ diff --git a/mobile/android/themes/core/images/errorpage-warning.png b/mobile/android/themes/core/images/errorpage-warning.png new file mode 100644 index 00000000000..8bf9d8e7dec Binary files /dev/null and b/mobile/android/themes/core/images/errorpage-warning.png differ diff --git a/mobile/android/themes/core/images/favicon-default-32.png b/mobile/android/themes/core/images/favicon-default-32.png new file mode 100644 index 00000000000..8e66e5ae57e Binary files /dev/null and b/mobile/android/themes/core/images/favicon-default-32.png differ diff --git a/mobile/android/themes/core/images/forward-default-hdpi.png b/mobile/android/themes/core/images/forward-default-hdpi.png new file mode 100644 index 00000000000..4bcf5010976 Binary files /dev/null and b/mobile/android/themes/core/images/forward-default-hdpi.png differ diff --git a/mobile/android/themes/core/images/handle-end.png b/mobile/android/themes/core/images/handle-end.png new file mode 100644 index 00000000000..d2720e70ec2 Binary files /dev/null and b/mobile/android/themes/core/images/handle-end.png differ diff --git a/mobile/android/themes/core/images/handle-start.png b/mobile/android/themes/core/images/handle-start.png new file mode 100644 index 00000000000..8abd627f0df Binary files /dev/null and b/mobile/android/themes/core/images/handle-start.png differ diff --git a/mobile/android/themes/core/images/homescreen-blank-hdpi.png b/mobile/android/themes/core/images/homescreen-blank-hdpi.png new file mode 100644 index 00000000000..066864cf79e Binary files /dev/null and b/mobile/android/themes/core/images/homescreen-blank-hdpi.png differ diff --git a/mobile/android/themes/core/images/homescreen-default-hdpi.png b/mobile/android/themes/core/images/homescreen-default-hdpi.png new file mode 100644 index 00000000000..963b5770fd9 Binary files /dev/null and b/mobile/android/themes/core/images/homescreen-default-hdpi.png differ diff --git a/mobile/android/themes/core/images/locked-hdpi.png b/mobile/android/themes/core/images/locked-hdpi.png new file mode 100644 index 00000000000..e50bc4f1dd2 Binary files /dev/null and b/mobile/android/themes/core/images/locked-hdpi.png differ diff --git a/mobile/android/themes/core/images/menu-hdpi.png b/mobile/android/themes/core/images/menu-hdpi.png new file mode 100644 index 00000000000..8662b9319c4 Binary files /dev/null and b/mobile/android/themes/core/images/menu-hdpi.png differ diff --git a/mobile/android/themes/core/images/mozilla-32.png b/mobile/android/themes/core/images/mozilla-32.png new file mode 100644 index 00000000000..98d8789e274 Binary files /dev/null and b/mobile/android/themes/core/images/mozilla-32.png differ diff --git a/mobile/android/themes/core/images/mute-hdpi.png b/mobile/android/themes/core/images/mute-hdpi.png new file mode 100644 index 00000000000..0bd1e60e6a3 Binary files /dev/null and b/mobile/android/themes/core/images/mute-hdpi.png differ diff --git a/mobile/android/themes/core/images/navigation-magnifier-30.png b/mobile/android/themes/core/images/navigation-magnifier-30.png new file mode 100644 index 00000000000..48001657c46 Binary files /dev/null and b/mobile/android/themes/core/images/navigation-magnifier-30.png differ diff --git a/mobile/android/themes/core/images/next-disabled-hdpi.png b/mobile/android/themes/core/images/next-disabled-hdpi.png new file mode 100644 index 00000000000..81e68769e09 Binary files /dev/null and b/mobile/android/themes/core/images/next-disabled-hdpi.png differ diff --git a/mobile/android/themes/core/images/next-hdpi.png b/mobile/android/themes/core/images/next-hdpi.png new file mode 100644 index 00000000000..c0115d49148 Binary files /dev/null and b/mobile/android/themes/core/images/next-hdpi.png differ diff --git a/mobile/android/themes/core/images/panelrow-active-hdpi.png b/mobile/android/themes/core/images/panelrow-active-hdpi.png new file mode 100644 index 00000000000..23676c11c47 Binary files /dev/null and b/mobile/android/themes/core/images/panelrow-active-hdpi.png differ diff --git a/mobile/android/themes/core/images/panelrow-default-hdpi.png b/mobile/android/themes/core/images/panelrow-default-hdpi.png new file mode 100644 index 00000000000..d8143e245c9 Binary files /dev/null and b/mobile/android/themes/core/images/panelrow-default-hdpi.png differ diff --git a/mobile/android/themes/core/images/panelrow-selected-hdpi.png b/mobile/android/themes/core/images/panelrow-selected-hdpi.png new file mode 100644 index 00000000000..5e8dc6eb3a9 Binary files /dev/null and b/mobile/android/themes/core/images/panelrow-selected-hdpi.png differ diff --git a/mobile/android/themes/core/images/pause-hdpi.png b/mobile/android/themes/core/images/pause-hdpi.png new file mode 100644 index 00000000000..e377d321ce0 Binary files /dev/null and b/mobile/android/themes/core/images/pause-hdpi.png differ diff --git a/mobile/android/themes/core/images/play-hdpi.png b/mobile/android/themes/core/images/play-hdpi.png new file mode 100644 index 00000000000..a8482eb4dd7 Binary files /dev/null and b/mobile/android/themes/core/images/play-hdpi.png differ diff --git a/mobile/android/themes/core/images/popup-bg-hdpi.png b/mobile/android/themes/core/images/popup-bg-hdpi.png new file mode 100644 index 00000000000..df8e20c929f Binary files /dev/null and b/mobile/android/themes/core/images/popup-bg-hdpi.png differ diff --git a/mobile/android/themes/core/images/popup-selected-item-hdpi.png b/mobile/android/themes/core/images/popup-selected-item-hdpi.png new file mode 100644 index 00000000000..dd511023c1f Binary files /dev/null and b/mobile/android/themes/core/images/popup-selected-item-hdpi.png differ diff --git a/mobile/android/themes/core/images/previous-disabled-hdpi.png b/mobile/android/themes/core/images/previous-disabled-hdpi.png new file mode 100644 index 00000000000..459f5ab7de4 Binary files /dev/null and b/mobile/android/themes/core/images/previous-disabled-hdpi.png differ diff --git a/mobile/android/themes/core/images/previous-hdpi.png b/mobile/android/themes/core/images/previous-hdpi.png new file mode 100644 index 00000000000..530206d58a5 Binary files /dev/null and b/mobile/android/themes/core/images/previous-hdpi.png differ diff --git a/mobile/android/themes/core/images/ratings-18.png b/mobile/android/themes/core/images/ratings-18.png new file mode 100644 index 00000000000..b264e6d0168 Binary files /dev/null and b/mobile/android/themes/core/images/ratings-18.png differ diff --git a/mobile/android/themes/core/images/remotetabs-32.png b/mobile/android/themes/core/images/remotetabs-32.png new file mode 100644 index 00000000000..80f59a022c3 Binary files /dev/null and b/mobile/android/themes/core/images/remotetabs-32.png differ diff --git a/mobile/android/themes/core/images/row-header-bg.png b/mobile/android/themes/core/images/row-header-bg.png new file mode 100644 index 00000000000..aaefd0f3d98 Binary files /dev/null and b/mobile/android/themes/core/images/row-header-bg.png differ diff --git a/mobile/android/themes/core/images/scrubber-hdpi.png b/mobile/android/themes/core/images/scrubber-hdpi.png new file mode 100644 index 00000000000..49c60505f46 Binary files /dev/null and b/mobile/android/themes/core/images/scrubber-hdpi.png differ diff --git a/mobile/android/themes/core/images/search-clear-30.png b/mobile/android/themes/core/images/search-clear-30.png new file mode 100644 index 00000000000..8bab39a08d3 Binary files /dev/null and b/mobile/android/themes/core/images/search-clear-30.png differ diff --git a/mobile/android/themes/core/images/search-glass-30.png b/mobile/android/themes/core/images/search-glass-30.png new file mode 100644 index 00000000000..71bf1f255ee Binary files /dev/null and b/mobile/android/themes/core/images/search-glass-30.png differ diff --git a/mobile/android/themes/core/images/section-collapsed-16.png b/mobile/android/themes/core/images/section-collapsed-16.png new file mode 100644 index 00000000000..c9805f654c7 Binary files /dev/null and b/mobile/android/themes/core/images/section-collapsed-16.png differ diff --git a/mobile/android/themes/core/images/section-expanded-16.png b/mobile/android/themes/core/images/section-expanded-16.png new file mode 100644 index 00000000000..128cef90af6 Binary files /dev/null and b/mobile/android/themes/core/images/section-expanded-16.png differ diff --git a/mobile/android/themes/core/images/sidebarbutton-active-hdpi.png b/mobile/android/themes/core/images/sidebarbutton-active-hdpi.png new file mode 100644 index 00000000000..30f1d2017bc Binary files /dev/null and b/mobile/android/themes/core/images/sidebarbutton-active-hdpi.png differ diff --git a/mobile/android/themes/core/images/tabs-hdpi.png b/mobile/android/themes/core/images/tabs-hdpi.png new file mode 100644 index 00000000000..ba656e12dc2 Binary files /dev/null and b/mobile/android/themes/core/images/tabs-hdpi.png differ diff --git a/mobile/android/themes/core/images/textbox-bg.png b/mobile/android/themes/core/images/textbox-bg.png new file mode 100644 index 00000000000..40edca065d6 Binary files /dev/null and b/mobile/android/themes/core/images/textbox-bg.png differ diff --git a/mobile/android/themes/core/images/throbber.png b/mobile/android/themes/core/images/throbber.png new file mode 100644 index 00000000000..c601ec80ba7 Binary files /dev/null and b/mobile/android/themes/core/images/throbber.png differ diff --git a/mobile/android/themes/core/images/toggle-off.png b/mobile/android/themes/core/images/toggle-off.png new file mode 100644 index 00000000000..a27900e1fe4 Binary files /dev/null and b/mobile/android/themes/core/images/toggle-off.png differ diff --git a/mobile/android/themes/core/images/toggle-on.png b/mobile/android/themes/core/images/toggle-on.png new file mode 100644 index 00000000000..a7dc009d5ea Binary files /dev/null and b/mobile/android/themes/core/images/toggle-on.png differ diff --git a/mobile/android/themes/core/images/unlocked-hdpi.png b/mobile/android/themes/core/images/unlocked-hdpi.png new file mode 100644 index 00000000000..359923dc6cc Binary files /dev/null and b/mobile/android/themes/core/images/unlocked-hdpi.png differ diff --git a/mobile/android/themes/core/images/unmute-hdpi.png b/mobile/android/themes/core/images/unmute-hdpi.png new file mode 100644 index 00000000000..4dbb94f98f0 Binary files /dev/null and b/mobile/android/themes/core/images/unmute-hdpi.png differ diff --git a/mobile/android/themes/core/jar.mn b/mobile/android/themes/core/jar.mn new file mode 100644 index 00000000000..7e3bf5537ce --- /dev/null +++ b/mobile/android/themes/core/jar.mn @@ -0,0 +1,259 @@ +#filter substitution + +chrome.jar: +% skin browser classic/1.0 %skin/ os!=Android +% skin browser classic/1.0 %skin/ os=Android osversion<2.3 +% skin browser froyo/1.0 %skin/ +# NOTE: If you add a new file here, you'll need to add it to the gingerbread +# and honeycomb sections at the bottom of this file + skin/aboutPage.css (aboutPage.css) + skin/about.css (about.css) + skin/aboutAddons.css (aboutAddons.css) + skin/aboutHome.css (aboutHome.css) +* skin/browser.css (browser.css) +* skin/content.css (content.css) + skin/config.css (config.css) + skin/header.css (header.css) +* skin/platform.css (platform.css) + skin/touchcontrols.css (touchcontrols.css) + skin/netError.css (netError.css) +% override chrome://global/skin/about.css chrome://browser/skin/about.css +% override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css +% override chrome://global/skin/netError.css chrome://browser/skin/netError.css + + skin/images/aboutBackground.jpg (images/aboutBackground.jpg) + skin/images/button-bg.png (images/button-bg.png) + skin/images/textbox-bg.png (images/textbox-bg.png) + skin/images/browseaddons-bg.jpg (images/browseaddons-bg.jpg) + skin/images/addons-32.png (images/addons-32.png) + skin/images/arrowleft-16.png (images/arrowleft-16.png) + skin/images/arrowright-16.png (images/arrowright-16.png) + skin/images/arrowup-16.png (images/arrowup-16.png) + skin/images/arrowdown-16.png (images/arrowdown-16.png) + skin/images/popup-bg-hdpi.png (images/popup-bg-hdpi.png) + skin/images/popup-selected-item-hdpi.png (images/popup-selected-item-hdpi.png) + skin/images/checkmark-hdpi.png (images/checkmark-hdpi.png) + skin/images/check-selected-30.png (images/check-selected-30.png) + skin/images/check-unselected-30.png (images/check-unselected-30.png) + skin/images/dropmarker-hdpi.png (images/dropmarker-hdpi.png) + skin/images/ratings-18.png (images/ratings-18.png) + skin/images/favicon-default-32.png (images/favicon-default-32.png) + skin/images/errorpage-warning.png (images/errorpage-warning.png) + skin/images/errorpage-warning.png (images/errorpage-warning.png) + skin/images/errorpage-larry-white.png (images/errorpage-larry-white.png) + skin/images/errorpage-larry-black.png (images/errorpage-larry-black.png) + skin/images/throbber.png (images/throbber.png) + skin/images/navigation-magnifier-30.png (images/navigation-magnifier-30.png) + skin/images/alert-addons-30.png (images/alert-addons-30.png) + skin/images/alert-downloads-30.png (images/alert-downloads-30.png) + skin/images/addons-default-hdpi.png (images/addons-default-hdpi.png) + skin/images/back-default-hdpi.png (images/back-default-hdpi.png) + skin/images/tabs-hdpi.png (images/tabs-hdpi.png) + skin/images/menu-hdpi.png (images/menu-hdpi.png) + skin/images/panelrow-active-hdpi.png (images/panelrow-active-hdpi.png) + skin/images/panelrow-default-hdpi.png (images/panelrow-default-hdpi.png) + skin/images/panelrow-selected-hdpi.png (images/panelrow-selected-hdpi.png) + skin/images/forward-default-hdpi.png (images/forward-default-hdpi.png) + skin/images/row-header-bg.png (images/row-header-bg.png) + skin/images/remotetabs-32.png (images/remotetabs-32.png) + skin/images/mozilla-32.png (images/mozilla-32.png) + skin/images/toggle-on.png (images/toggle-on.png) + skin/images/toggle-off.png (images/toggle-off.png) + skin/images/sidebarbutton-active-hdpi.png (images/sidebarbutton-active-hdpi.png) + skin/images/previous-hdpi.png (images/previous-hdpi.png) + skin/images/previous-disabled-hdpi.png (images/previous-disabled-hdpi.png) + skin/images/next-hdpi.png (images/next-hdpi.png) + skin/images/next-disabled-hdpi.png (images/next-disabled-hdpi.png) + skin/images/unlocked-hdpi.png (images/unlocked-hdpi.png) + skin/images/locked-hdpi.png (images/locked-hdpi.png) + skin/images/check-30.png (images/check-30.png) + skin/images/search-glass-30.png (images/search-glass-30.png) + skin/images/search-clear-30.png (images/search-clear-30.png) + skin/images/section-expanded-16.png (images/section-expanded-16.png) + skin/images/section-collapsed-16.png (images/section-collapsed-16.png) + skin/images/play-hdpi.png (images/play-hdpi.png) + skin/images/pause-hdpi.png (images/pause-hdpi.png) + skin/images/mute-hdpi.png (images/mute-hdpi.png) + skin/images/unmute-hdpi.png (images/unmute-hdpi.png) + skin/images/scrubber-hdpi.png (images/scrubber-hdpi.png) + skin/images/handle-start.png (images/handle-start.png) + skin/images/handle-end.png (images/handle-end.png) + skin/images/homescreen-blank-hdpi.png (images/homescreen-blank-hdpi.png) + skin/images/homescreen-default-hdpi.png (images/homescreen-default-hdpi.png) + skin/images/aurora-lightbox-bg.jpg (images/aurora-lightbox-bg.jpg) + skin/images/aurora-lightbox-logo.png (images/aurora-lightbox-logo.png) + skin/images/aurora-lightbox-close.png (images/aurora-lightbox-close.png) + +chrome.jar: +% skin browser classic/1.0 %skin/gingerbread/ os=Android osversion=2.3 osversion=2.3.3 osversion=2.3.4 osversion=2.3.5 osversion=2.3.6 osversion=2.3.7 +% skin browser gingerbread/1.0 %skin/gingerbread/ + skin/gingerbread/aboutPage.css (aboutPage.css) + skin/gingerbread/about.css (about.css) + skin/gingerbread/aboutAddons.css (aboutAddons.css) + skin/gingerbread/aboutHome.css (aboutHome.css) +* skin/gingerbread/browser.css (gingerbread/browser.css) +* skin/gingerbread/content.css (gingerbread/content.css) + skin/gingerbread/config.css (config.css) + skin/gingerbread/header.css (header.css) +* skin/gingerbread/platform.css (gingerbread/platform.css) + skin/gingerbread/touchcontrols.css (touchcontrols.css) + skin/gingerbread/netError.css (netError.css) +% override chrome://global/skin/about.css chrome://browser/skin/about.css +% override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css +% override chrome://global/skin/netError.css chrome://browser/skin/netError.css + + skin/gingerbread/images/aboutBackground.jpg (gingerbread/images/aboutBackground.jpg) + skin/gingerbread/images/button-bg.png (gingerbread/images/button-bg.png) + skin/gingerbread/images/textbox-bg.png (gingerbread/images/textbox-bg.png) + skin/gingerbread/images/urlbar-bg.png (gingerbread/images/urlbar-bg.png) + skin/gingerbread/images/browseaddons-bg.jpg (gingerbread/images/browseaddons-bg.jpg) + skin/gingerbread/images/addons-32.png (images/addons-32.png) + skin/gingerbread/images/arrowleft-16.png (gingerbread/images/arrowleft-16.png) + skin/gingerbread/images/arrowright-16.png (gingerbread/images/arrowright-16.png) + skin/gingerbread/images/arrowup-16.png (gingerbread/images/arrowup-16.png) + skin/gingerbread/images/arrowdown-16.png (gingerbread/images/arrowdown-16.png) + skin/gingerbread/images/popup-selected-item-hdpi.png (gingerbread/images/popup-selected-item-hdpi.png) + skin/gingerbread/images/checkmark-hdpi.png (images/checkmark-hdpi.png) + skin/gingerbread/images/check-selected-hdpi.png (gingerbread/images/check-selected-hdpi.png) + skin/gingerbread/images/check-unselected-hdpi.png (gingerbread/images/check-unselected-hdpi.png) + skin/gingerbread/images/radio-selected-hdpi.png (gingerbread/images/radio-selected-hdpi.png) + skin/gingerbread/images/radio-unselected-hdpi.png (gingerbread/images/radio-unselected-hdpi.png) + skin/gingerbread/images/dropmarker-hdpi.png (gingerbread/images/dropmarker-hdpi.png) + skin/gingerbread/images/ratings-18.png (images/ratings-18.png) + skin/gingerbread/images/favicon-default-32.png (gingerbread/images/favicon-default-32.png) + skin/gingerbread/images/throbber.png (gingerbread/images/throbber.png) + skin/gingerbread/images/navigation-magnifier-30.png (gingerbread/images/navigation-magnifier-30.png) + skin/gingerbread/images/alert-addons-30.png (gingerbread/images/alert-addons-30.png) + skin/gingerbread/images/alert-downloads-30.png (gingerbread/images/alert-downloads-30.png) + skin/gingerbread/images/addons-default-hdpi.png (gingerbread/images/addons-default-hdpi.png) + skin/gingerbread/images/back-default-hdpi.png (gingerbread/images/back-default-hdpi.png) + skin/gingerbread/images/forward-default-hdpi.png (gingerbread/images/forward-default-hdpi.png) + skin/gingerbread/images/row-header-bg.png (gingerbread/images/row-header-bg.png) + skin/gingerbread/images/remotetabs-32.png (gingerbread/images/remotetabs-32.png) + skin/gingerbread/images/mozilla-32.png (images/mozilla-32.png) + skin/gingerbread/images/toggle-on.png (gingerbread/images/toggle-on.png) + skin/gingerbread/images/toggle-off.png (gingerbread/images/toggle-off.png) + skin/gingerbread/images/previous-hdpi.png (gingerbread/images/previous-hdpi.png) + skin/gingerbread/images/previous-disabled-hdpi.png (gingerbread/images/previous-disabled-hdpi.png) + skin/gingerbread/images/next-hdpi.png (gingerbread/images/next-hdpi.png) + skin/gingerbread/images/next-disabled-hdpi.png (gingerbread/images/next-disabled-hdpi.png) + skin/gingerbread/images/unlocked-hdpi.png (gingerbread/images/unlocked-hdpi.png) + skin/gingerbread/images/locked-hdpi.png (gingerbread/images/locked-hdpi.png) + skin/gingerbread/images/check-30.png (gingerbread/images/check-30.png) + skin/gingerbread/images/search-glass-30.png (gingerbread/images/search-glass-30.png) + skin/gingerbread/images/search-clear-30.png (gingerbread/images/search-clear-30.png) + skin/gingerbread/images/section-expanded-16.png (images/section-expanded-16.png) + skin/gingerbread/images/section-collapsed-16.png (images/section-collapsed-16.png) + skin/gingerbread/images/play-hdpi.png (gingerbread/images/play-hdpi.png) + skin/gingerbread/images/pause-hdpi.png (gingerbread/images/pause-hdpi.png) + skin/gingerbread/images/mute-hdpi.png (gingerbread/images/mute-hdpi.png) + skin/gingerbread/images/unmute-hdpi.png (gingerbread/images/unmute-hdpi.png) + skin/gingerbread/images/scrubber-hdpi.png (gingerbread/images/scrubber-hdpi.png) + skin/gingerbread/images/handle-start.png (gingerbread/images/handle-start.png) + skin/gingerbread/images/handle-end.png (gingerbread/images/handle-end.png) + skin/gingerbread/images/tabs-hdpi.png (images/tabs-hdpi.png) + skin/gingerbread/images/menu-hdpi.png (images/menu-hdpi.png) + skin/gingerbread/images/errorpage-warning.png (images/errorpage-warning.png) + skin/gingerbread/images/errorpage-larry-white.png (images/errorpage-larry-white.png) + skin/gingerbread/images/errorpage-larry-black.png (images/errorpage-larry-black.png) + skin/gingerbread/images/homescreen-blank-hdpi.png (images/homescreen-blank-hdpi.png) + skin/gingerbread/images/homescreen-default-hdpi.png (images/homescreen-default-hdpi.png) + skin/gingerbread/images/aurora-lightbox-bg.jpg (images/aurora-lightbox-bg.jpg) + skin/gingerbread/images/aurora-lightbox-logo.png (images/aurora-lightbox-logo.png) + skin/gingerbread/images/aurora-lightbox-close.png (images/aurora-lightbox-close.png) + +chrome.jar: +% skin browser classic/1.0 %skin/honeycomb/ os=Android osversion>=3.0 +% skin browser honeycomb/1.0 %skin/honeycomb/ + skin/honeycomb/aboutPage.css (aboutPage.css) + skin/honeycomb/about.css (about.css) + skin/honeycomb/aboutAddons.css (aboutAddons.css) + skin/honeycomb/aboutHome.css (aboutHome.css) +* skin/honeycomb/browser.css (honeycomb/browser.css) +* skin/honeycomb/content.css (content.css) + skin/honeycomb/config.css (config.css) + skin/honeycomb/header.css (header.css) +* skin/honeycomb/platform.css (honeycomb/platform.css) + skin/honeycomb/touchcontrols.css (touchcontrols.css) + skin/honeycomb/netError.css (netError.css) +% override chrome://global/skin/about.css chrome://browser/skin/about.css +% override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css +% override chrome://global/skin/netError.css chrome://browser/skin/netError.css + + skin/honeycomb/images/aboutBackground.jpg (honeycomb/images/aboutBackground.jpg) + skin/honeycomb/images/button-bg.png (honeycomb/images/button-bg.png) + skin/honeycomb/images/textbox-bg.png (honeycomb/images/textbox-bg.png) + skin/honeycomb/images/browseaddons-bg.jpg (honeycomb/images/browseaddons-bg.jpg) + skin/honeycomb/images/addons-32.png (images/addons-32.png) + skin/honeycomb/images/arrowleft-16.png (honeycomb/images/arrowleft-16.png) + skin/honeycomb/images/arrowright-16.png (honeycomb/images/arrowright-16.png) + skin/honeycomb/images/arrowup-16.png (honeycomb/images/arrowup-16.png) + skin/honeycomb/images/arrowdown-16.png (honeycomb/images/arrowdown-16.png) + skin/honeycomb/images/popup-bg-hdpi.png (honeycomb/images/popup-bg-hdpi.png) + skin/honeycomb/images/popup-selected-item-hdpi.png (honeycomb/images/popup-selected-item-hdpi.png) + skin/honeycomb/images/dropmarker-hdpi.png (honeycomb/images/dropmarker-hdpi.png) + skin/honeycomb/images/ratings-18.png (images/ratings-18.png) + skin/honeycomb/images/favicon-default-32.png (honeycomb/images/favicon-default-32.png) + skin/honeycomb/images/throbber.png (honeycomb/images/throbber.png) + skin/honeycomb/images/navigation-magnifier-30.png (honeycomb/images/navigation-magnifier-30.png) + skin/honeycomb/images/alert-addons-30.png (honeycomb/images/alert-addons-30.png) + skin/honeycomb/images/alert-downloads-30.png (honeycomb/images/alert-downloads-30.png) + skin/honeycomb/images/addons-default-hdpi.png (honeycomb/images/addons-default-hdpi.png) + skin/honeycomb/images/back-default-hdpi.png (honeycomb/images/back-default-hdpi.png) + skin/honeycomb/images/panelrow-active-hdpi.png (honeycomb/images/panelrow-active-hdpi.png) + skin/honeycomb/images/panelrow-default-hdpi.png (honeycomb/images/panelrow-default-hdpi.png) + skin/honeycomb/images/panelrow-selected-hdpi.png (honeycomb/images/panelrow-selected-hdpi.png) + skin/honeycomb/images/radio-selected-hdpi.png (gingerbread/images/radio-selected-hdpi.png) + skin/honeycomb/images/radio-unselected-hdpi.png (gingerbread/images/radio-unselected-hdpi.png) + skin/honeycomb/images/forward-default-hdpi.png (honeycomb/images/forward-default-hdpi.png) + skin/honeycomb/images/row-header-bg.png (honeycomb/images/row-header-bg.png) + skin/honeycomb/images/remotetabs-32.png (honeycomb/images/remotetabs-32.png) + skin/honeycomb/images/mozilla-32.png (images/mozilla-32.png) + skin/honeycomb/images/toggle-on.png (honeycomb/images/toggle-on.png) + skin/honeycomb/images/toggle-off.png (honeycomb/images/toggle-off.png) + skin/honeycomb/images/sidebarbutton-active-hdpi.png (honeycomb/images/sidebarbutton-active-hdpi.png) + skin/honeycomb/images/previous-hdpi.png (honeycomb/images/previous-hdpi.png) + skin/honeycomb/images/previous-disabled-hdpi.png (honeycomb/images/previous-disabled-hdpi.png) + skin/honeycomb/images/next-hdpi.png (honeycomb/images/next-hdpi.png) + skin/honeycomb/images/next-disabled-hdpi.png (honeycomb/images/next-disabled-hdpi.png) + skin/honeycomb/images/unlocked-hdpi.png (honeycomb/images/unlocked-hdpi.png) + skin/honeycomb/images/locked-hdpi.png (honeycomb/images/locked-hdpi.png) + skin/honeycomb/images/checkmark-hdpi.png (images/checkmark-hdpi.png) + skin/honeycomb/images/check-30.png (images/check-30.png) + skin/honeycomb/images/check-selected-hdpi.png (honeycomb/images/check-selected-hdpi.png) + skin/honeycomb/images/check-unselected-hdpi.png (honeycomb/images/check-unselected-hdpi.png) + skin/honeycomb/images/check-selected-tap-hdpi.png (honeycomb/images/check-selected-tap-hdpi.png) + skin/honeycomb/images/check-unselected-tap-hdpi.png (honeycomb/images/check-unselected-tap-hdpi.png) + skin/honeycomb/images/search-glass-30.png (honeycomb/images/search-glass-30.png) + skin/honeycomb/images/search-clear-30.png (honeycomb/images/search-clear-30.png) + skin/honeycomb/images/section-expanded-16.png (images/section-expanded-16.png) + skin/honeycomb/images/section-collapsed-16.png (images/section-collapsed-16.png) + skin/honeycomb/images/play-hdpi.png (honeycomb/images/play-hdpi.png) + skin/honeycomb/images/pause-hdpi.png (honeycomb/images/pause-hdpi.png) + skin/honeycomb/images/mute-hdpi.png (honeycomb/images/mute-hdpi.png) + skin/honeycomb/images/unmute-hdpi.png (honeycomb/images/unmute-hdpi.png) + skin/honeycomb/images/scrubber-hdpi.png (honeycomb/images/scrubber-hdpi.png) + skin/honeycomb/images/handle-start.png (images/handle-start.png) + skin/honeycomb/images/handle-end.png (images/handle-end.png) + skin/honeycomb/images/tabs-hdpi.png (honeycomb/images/tabs-hdpi.png) + skin/honeycomb/images/tabs-default-bg.png (honeycomb/images/tabs-default-bg.png) + skin/honeycomb/images/tabs-selected-bg.png (honeycomb/images/tabs-selected-bg.png) + skin/honeycomb/images/tabs-default-bg-rtl.png (honeycomb/images/tabs-default-bg-rtl.png) + skin/honeycomb/images/tabs-selected-bg-rtl.png (honeycomb/images/tabs-selected-bg-rtl.png) + skin/honeycomb/images/menu-hdpi.png (honeycomb/images/menu-hdpi.png) + skin/honeycomb/images/errorpage-warning.png (images/errorpage-warning.png) + skin/honeycomb/images/errorpage-larry-white.png (images/errorpage-larry-white.png) + skin/honeycomb/images/errorpage-larry-black.png (images/errorpage-larry-black.png) + skin/honeycomb/images/homescreen-blank-hdpi.png (images/homescreen-blank-hdpi.png) + skin/honeycomb/images/homescreen-default-hdpi.png (images/homescreen-default-hdpi.png) + skin/honeycomb/images/urlbar-border-side.png (honeycomb/images/urlbar-border-side.png) + skin/honeycomb/images/urlbar-border-bottom.png (honeycomb/images/urlbar-border-bottom.png) + skin/honeycomb/images/urlbar-border-side-active.png (honeycomb/images/urlbar-border-side-active.png) + skin/honeycomb/images/urlbar-border-bottom-active.png (honeycomb/images/urlbar-border-bottom-active.png) + skin/honeycomb/images/aurora-lightbox-bg.jpg (images/aurora-lightbox-bg.jpg) + skin/honeycomb/images/aurora-lightbox-logo.png (images/aurora-lightbox-logo.png) + skin/honeycomb/images/aurora-lightbox-close.png (images/aurora-lightbox-close.png) + + skin/honeycomb/images/menu-top-insideglow.png (honeycomb/images/menu-top-insideglow.png) + skin/honeycomb/images/menu-top-insideglow-green.png (honeycomb/images/menu-top-insideglow-green.png) + skin/honeycomb/images/menu-top-insideglow-grey.png (honeycomb/images/menu-top-insideglow-grey.png) diff --git a/mobile/android/themes/core/netError.css b/mobile/android/themes/core/netError.css new file mode 100644 index 00000000000..b69468f2494 --- /dev/null +++ b/mobile/android/themes/core/netError.css @@ -0,0 +1,127 @@ +/* + * This defines the look-and-feel styling of the error pages. + * (see: netError.xhtml) + * + * Original styling by William Price + * Updated for mobile by: Wes Johnston + */ + +body { + margin: 0; + padding: 0 8px 8px; + font-family: "Nokia Sans", Tahoma, sans-serif !important; +} + +h1 { + font-size: 22px; +} + +h2 { + font-size: 16px; +} + +ul { + margin: 0px; + padding: 0px 0px 0px 1em; +} + +li { + margin: 0px; + padding: 8px 0px; +} + +#errorPage { + background-color: #CEE6F4; +} + +#errorPage.certerror { + background-color: #EFD400; +} + +#errorPage.blockedsite { + background-color: #BF0000; +} + +#errorTitle { + background: url("chrome://browser/skin/images/errorpage-warning.png") left center no-repeat; + /* Scaled by .666 of their actual size */ + background-size: 40px 40px; + background-origin: content-box; + min-height: 60px; + margin-left: auto; + margin-right: auto; + max-width: 500px; + margin-left: auto; + margin-right: auto; +} + +#errorPage.certerror #errorTitle { + background-image: url("chrome://browser/skin/images/errorpage-larry-black.png"); +} + +#errorPage.blockedsite #errorTitle { + background-image: url("chrome://browser/skin/images/errorpage-larry-white.png"); + color: white; +} + +.errorTitleText { + padding: 0px 0px 0px 50px; + display: inline-block; + vertical-align: middle +} + +#errorPageContainer { + background-color: white; + border: 1px solid #999999; + border-radius: 6px; + padding: 6px 20px 20px; + font-size: 14px; + max-width: 500px; + margin-left: auto; + margin-right: auto; +} + +#errorShortDesc > p:empty { + display: none; +} + +#errorShortDesc > p { + overflow: auto; + border-bottom: 1px solid #999999; + padding-bottom: 1em; +} + +#errorPage.blockedsite #errorShortDesc > p { + font-weight: bold; + border-bottom: none; + padding-bottom: 0px; +} + +#securityOverrideDiv { + padding-top: 10px; +} + +div[collapsed] { + padding-left: 15px; + background-image: url("chrome://browser/skin/images/arrowright-16.png"); + background-size: 11px 11px; + background-repeat: no-repeat; + background-position: left 0.3em; +} + +div[collapsed="true"] { + background-image: url("chrome://browser/skin/images/arrowright-16.png"); +} + +div[collapsed="false"] { + background-image: url("chrome://browser/skin/images/arrowdown-16.png"); +} + +div[collapsed="true"] > p, +div[collapsed="true"] > div { + display: none; +} + +button { + padding: 0.3em !important; +} diff --git a/mobile/android/themes/core/platform.css b/mobile/android/themes/core/platform.css new file mode 100644 index 00000000000..61986be7166 --- /dev/null +++ b/mobile/android/themes/core/platform.css @@ -0,0 +1,753 @@ +/* ***** 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): + * Mark Finkle + * + * 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 ***** */ + +/* global skin ------------------------------------------------------------- */ +@import url(chrome://global/skin/); + +%filter substitution +%include defines.inc + +/* general stuff ------------------------------------------------------------ */ +:root { + font-family: "Nokia Sans", Tahoma, sans-serif !important; + font-size: @font_normal@ !important; + background-color: white; /* force */ + color: black; /* force */ +} + +::-moz-selection { + background-color: #8db8d8; + color: black; +} + +menu, +menuitem { + padding: 0 !important; + margin: 0 !important; +} + +description, +label { + /* force mac to use the same margins as windows and linux */ + -moz-margin-start: @margin_snormal@; + -moz-margin-end: @margin_snormal@; +} + +/* Override any OS inverse themes */ +richlistbox, +textbox { + color: black; + background-color: white; +} + +/* textboxes --------------------------------------------------------------- */ +textbox:not([type="number"]) { + min-height: @textbox_height@; + border: @border_width_small@ solid #cacdd5; + -moz-border-radius: @border_radius_normal@; + -moz-border-top-colors: -moz-initial; + -moz-border-right-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; +} + +textbox[isempty="true"] { + color: gray; +} + +textbox.search-bar { + border: @border_width_small@ solid rgba(0,0,0,0.4); + background-color: #f9f9f9; + background: url("chrome://browser/skin/images/textbox-bg.png") top left repeat-x; + background-size: 100% 100%; +} + +textbox[disabled="true"] { + background-color: lightgray; +} + +.link { + color: blue; + text-decoration: underline; +} + +/* sidebars spacer --------------------------------------------------------- */ +.sidebar-spacer { + background-color: #767973; +} + +/* prompt dialogs ---------------------------------------------------------- */ +.context-block, +.modal-block, +.perm-modal-block { + -moz-box-align: center; + -moz-box-pack: center; + background-color: rgba(0,0,0,.6); +} + +.context-block { + padding: @margin_context_popup@; +} + +.dialog-dark, +.panel-arrowcontent { + background: url("chrome://browser/skin/images/popup-bg-hdpi.png") left bottom repeat-x; + background-color: white; + border-radius: @border_radius_normal@; + box-shadow: black 0 @border_radius_tiny@ @border_radius_tiny@, black 0 -@border_radius_tiny@ @border_radius_tiny@; + padding: @padding_normal@ 0; /* core spacing on top/bottom */ +} + +@media (max-width: 499px) { + .context-block { + padding: @padding_xlarge@; + } +} + +dialog > .prompt-header > .prompt-message { + white-space: pre-wrap; +} + +dialog > .prompt-header > .button-checkbox { + margin-left: @margin_large@; +} + +/* buttons ----------------------------------------------------------------- */ +.button-text, +.toolbarbutton-text { + font-weight: normal; + font-size: @font_normal@ !important; +} + +button { + -moz-appearance: none; + min-width: @touch_button_small@ !important; /* button size */ + min-height: @touch_button_small@ !important; /* button size */ + color: #000; + border-radius: @border_radius_normal@; + margin: @margin_normal@; + padding: @padding_xnormal@; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border: @border_width_tiny@ solid #cacdd5; +} + +button[disabled="true"] { + color: #aaa !important; + border: @border_width_tiny@ solid #cacdd5 !important; +} + +button:focus > .button-box { + border: @border_width_tiny@ solid transparent; +} + +button:not([disabled]):hover:active, +button:not([disabled])[checked="true"] { + background-image: url("chrome://browser/skin/images/toggle-off.png"); +} + +/* Override GTK2 system setting */ +.button-icon { + display: -moz-initial !important; +} + +/* spinbuttons ------------------------------------------------------------- */ +spinbuttons { + border: none !important; +} + +.numberbox-input-box { + border: @border_width_small@ solid #cacdd5; + border-right: 0 solid transparent; + border-radius: @border_radius_normal@ 0 0 @border_radius_normal@; + -moz-border-top-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; +} + +.numberbox-input-box:-moz-locale-dir(rtl) { + border-radius: 0 @border_radius_normal@ @border_radius_normal@ 0; + border-right: @border_width_small@ solid #cacdd5; + border-left: 0 solid transparent; +} + +.spinbuttons-box { + border: none !important; + -moz-box-orient: horizontal !important; + -moz-box-direction: reverse !important; +} + +.spinbuttons-up .button-icon, +.spinbuttons-down .button-icon { + display: block; +} + +.spinbuttons-up, +.spinbuttons-down { + -moz-appearance: none !important; + min-width: @touch_button_small@ !important; /* button size */ + min-height: @touch_button_small@ !important; /* button size */ + color: #000; + margin: @margin_normal@; + padding: @padding_xnormal@; + border-radius: 0; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border: @border_width_tiny@ solid #cacdd5; + list-style-image: url("chrome://browser/skin/images/arrowdown-16.png"); +} + +.spinbuttons-up:hover:active:not([disabled=true]), +.spinbuttons-down:hover:active:not([disabled=true]) { + background-image: url("chrome://browser/skin/images/toggle-on.png"); +} + +.spinbuttons-up { + border-radius: 0 @border_radius_normal@ @border_radius_normal@ 0; + list-style-image: url("chrome://browser/skin/images/arrowup-16.png"); +} + +.spinbuttons-up:-moz-locale-dir(rtl) { + border-radius: @border_radius_normal@ 0 0 @border_radius_normal@; +} + +/* toolbar buttons --------------------------------------------------------- */ +toolbarbutton { + min-width: @touch_button_large@ !important; /* primary button size */ + min-height: @touch_button_large@ !important; /* primary button size */ + -moz-appearance: none !important; + margin: 0; + padding: @padding_xsmall@; +} + +toolbarbutton:not(.show-text) .toolbarbutton-text { + display: none; +} + +.toolbarbutton-icon[label]:not([label=""]), +.toolbarbutton-icon[type="menu"] { + -moz-margin-end: @margin_tiny@; +} + +toolbarbutton:not(.show-text) .toolbarbutton-icon, +toolbarbutton:not([image]) .toolbarbutton-icon, +toolbarbutton[image=''] .toolbarbutton-icon { + -moz-margin-end: 0; +} + +toolbarbutton:hover, +toolbarbutton:hover:active, +toolbarbutton[open="true"] { + border-color: transparent; +} + +/* checkbox buttons ----------------------------------------------------------- */ +.button-checkbox { + padding: 0 !important; + background: none !important; + border: none !important; + -moz-border-image: none !important; + color: white; + -moz-box-align: center; + font-size: @font_small@; + -moz-box-align: center; +} + +.prompt-checkbox-label { + text-align: left; +} + +.button-checkbox > .button-image-icon { + -moz-margin-end: @margin_normal@; + list-style-image: url("chrome://browser/skin/images/check-unselected-30.png"); +} + +.button-checkbox[checked="true"] > .button-image-icon { + list-style-image: url("chrome://browser/skin/images/check-selected-30.png"); +} + +.button-checkbox:hover:active > .button-box, +.button-checkbox[checked="true"] > .button-box { + padding-top: @padding_tiny@; + padding-bottom: @padding_xsmall@; + -moz-padding-start: @margin_small@; + -moz-padding-end: @margin_small@; +} + +/* radio buttons ----------------------------------------------------------- */ +radiogroup { + -moz-box-orient: horizontal; +} + +.radio-label { + font-weight: normal; + font-size: @font_normal@ !important; +} + +radio { + -moz-appearance: none; + min-width: @touch_button_small@ !important; /* button size */ + min-height: @touch_button_small@ !important; /* button size */ + color: #000; + padding: @padding_xnormal@; + margin: 0; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border-top: @border_width_tiny@ solid #cacdd5; + border-bottom: @border_width_tiny@ solid #cacdd5; +} + +radio .radio-icon, radio .radio-check { + display: none; +} + +radio:not([disabled=true]):hover:active, +radio[selected] { + color: white; + background-image: url("chrome://browser/skin/images/toggle-on.png"); +} + +radio:first-child { + border-left: @border_width_tiny@ solid #cacdd5; + border-radius: @border_radius_normal@ 0 0 @border_radius_normal@; +} + +radio:first-child:-moz-locale-dir(rtl) { + border-left: none; + border-right: @border_width_tiny@ solid #cacdd5; + border-radius: 0 @border_radius_normal@ @border_radius_normal@ 0; +} + +radio:last-child { + border-right: @border_width_tiny@ solid #cacdd5; + border-radius: 0 @border_radius_normal@ @border_radius_normal@ 0; +} + +radio:last-child:-moz-locale-dir(rtl) { + border-right: none; + border-left: @border_width_tiny@ solid #cacdd5; + border-radius: @border_radius_normal@ 0 0 @border_radius_normal@; +} + +radio[focused="true"] > .radio-label-box { + border: @border_width_tiny@ solid transparent; +} + +/* checkbox radios --------------------------------------------------------- */ +checkbox { + margin: @margin_tiny@ @margin_small@ @margin_tiny@ @margin_small@; /* match platform style for buttons */ +} + +radio.checkbox-radio-on:not([selected]) { + border-right: @border_width_tiny@ solid #cacdd5; +} + +radio.checkbox-radio-on:not([selected]):-moz-locale-dir(rtl) { + border-left: none; + border-left: @border_width_tiny@ solid #cacdd5; +} + +radio.checkbox-radio-off[selected], +radio.checkbox-radio-off:hover:active { + background-image: url("chrome://browser/skin/images/toggle-off.png"); + color: black; + background-repeat: repeat-x; +} + +radio.checkbox-radio-on:not([selected]) .radio-label-box, +radio.checkbox-radio-off:not([selected]) .radio-label-box { + visibility: hidden; +} + +/* richlistbox ------------------------------------------------------------- */ +richlistbox { + -moz-user-focus: ignore; + margin: 0; +} + +richlistitem { + -moz-user-focus: ignore; + min-height: @touch_row@; /* row size */ + padding: @padding_small@; + border-bottom: @border_width_tiny@ solid rgb(207,207,207); +} + +richlistitem label.title, +richlistitem description.title { + font-size: @font_normal@ !important; +} + +richlistitem label.normal, +richlistitem description.normal { + color: gray; + font-size: @font_small@ !important; + white-space: pre-wrap; + word-wrap: break-word; +} + +richlistitem label.normal-black, +richlistitem description.normal-black { + font-size: @font_small@ !important; + white-space: pre-wrap; + word-wrap: break-word; +} + +richlistitem label.normal-bold, +richlistitem description.normal-bold { + font-weight: bold; + font-size: @font_small@ !important; + white-space: pre-wrap; + word-wrap: break-word; +} + +richlistitem[selected="true"] { + color: black; + background-color: white; +} + +richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]) { + background-color: #8db8d8; +} + +richlistitem.section-header, +richlistitem[selected="true"].section-header { + font-weight: bold; + color: #000; + background-color: lightgray; +} + +richlistitem .show-on-select { + visibility: collapse; +} + +richlistitem[selected="true"] .show-on-select { + visibility: visible; +} + +richlistitem .hide-on-select { + visibility: visible; +} + +richlistitem[selected="true"] .hide-on-select { + visibility: collapse; +} + +richlistitem[typeName="message"] { + border-bottom: 0; +} + +/* colorpicker ------------------------------------------------------------- */ +colorpicker > panel { + background-color: #767973; +} + +colorpicker > vbox { + background-color: #767973; +} + +/* textbox ----------------------------------------------------------------- */ +.textbox-search-icon { + list-style-image: url("chrome://browser/skin/images/search-glass-30.png"); + -moz-image-region: auto; +} + +.textbox-search-clear { + list-style-image: url("chrome://browser/skin/images/search-clear-30.png"); + -moz-image-region: auto; +} + +/* menulist ---------------------------------------------------------------- */ +.menulist-label { + font-family: "Nokia Sans", Tahoma, sans-serif !important; + font-weight: normal; + font-size: @font_normal@ !important; + background-color: transparent !important; +} + +menulist { + -moz-appearance: none !important; + -moz-user-focus: ignore; + min-width: @touch_button_small@ !important; /* button size */ + min-height: @touch_button_small@ !important; /* button size */ + color: #000 !important; + border-radius: @border_radius_normal@; + margin: @margin_normal@; + padding: @padding_small@ @padding_xnormal@; + background-image: url("chrome://browser/skin/images/button-bg.png"); + background-size: auto 100%; + border: @border_width_tiny@ solid #cacdd5; +} + +menulist[disabled="true"] { + color: #aaa !important; + border: @border_width_tiny@ solid #cacdd5 !important; +} + +menulist:not([disabled="true"]):hover:active { + background-image: url("chrome://browser/skin/images/toggle-off.png"); +} + +menulist > dropmarker { + height: 32px; + width: 32px; + margin-left: @margin_snormal@; + background-color: transparent; /* for windows */ + border: none; /* for windows */ + -moz-box-align: center; + -moz-box-pack: center; + list-style-image: url("chrome://browser/skin/images/dropmarker-hdpi.png"); + -moz-image-region: auto; + display: block; +} + +menulist[disabled="true"] > dropmarker { + opacity: 0.5; +} + +/* progressmeter ----------------------------------------------------------- */ +progressmeter { + background-color: #fff; + padding: @padding_small@; + height: @textbox_height@; + border: @border_width_large@ solid #aaa; + -moz-border-top-colors: -moz-initial; + -moz-border-right-colors: -moz-initial; + -moz-border-bottom-colors: -moz-initial; + -moz-border-left-colors: -moz-initial; + -moz-border-radius: @border_radius_normal@; +} + +.progress-bar { + background-color: #8db8d8; +} + +/* panels / arrowboxes------------------------------------------------------ */ +arrowbox { + -moz-appearance: none; + background: transparent !important; + border: none; +} + +dialog, +.arrowbox-dark .panel-arrowcontent, +.panel-dark { + color: white; + background: rgb(94,97,102); +} + +dialog, +.arrowbox-dark .panel-arrowcontent { + border: @border_width_large@ solid white; + border-radius: @border_radius_normal@; + box-shadow: black 0 @shadow_width_small@ @shadow_width_small@; +} + +dialog { + margin: @margin_xxxnormal@ !important; + max-width: @dialog_width@; +} + +.prompt-message { + text-align: center; + -moz-box-pack: center; + font-size: @font_snormal@; + margin: @padding_normal@; +} + +.prompt-message .link { + color: white; +} + +.prompt-title { + text-align: center; + font-size: @font_xnormal@; + -moz-box-align: center; + -moz-box-pack: center; + padding-top: @padding_xnormal@; +} + +/* Authentication dialogs do not have a title */ +.prompt-title:empty, +.prompt-title:empty + .prompt-line { + display: none; +} + +.prompt-line { + border-bottom: @border_width_small@ solid white; + margin: @margin_small@ 3em 0 3em; + height: @padding_normal@ !important; +} + +.prompt-buttons { + font-size: @font_snormal@; + background-color: lightgray; + display: inline-block; + text-align: center; +} + +.prompt-edit { + margin: @margin_xnormal@; + font-size: @font_normal@; + text-align: start; +} + +/*.panel-row-header ------------------------------------------------------------ */ +.panel-row-header { + border-bottom: @border_width_xlarge@ solid rgb(101,121,227); + background-color: rgb(94,97,102); + padding: 0 !important; +} + +.panel-row-button { + -moz-appearance: none; + background: rgb(94,97,102) url(images/panelrow-default-hdpi.png) no-repeat; + background-size: 100% 100%; + color: white; + border: 0 solid transparent !important; + -moz-border-start: @border_width_tiny@ solid rgba(255,255,255,0.2) !important; + -moz-border-end: @border_width_tiny@ solid rgba(0,0,0,0.2) !important; + padding-top: @padding_xsmall@ !important; + padding-bottom: @padding_xsmall@ !important; + -moz-padding-start: @padding_xsmall@ !important; + -moz-padding-end: @padding_xsmall@ !important; + -moz-box-flex: 1; + -moz-user-focus: ignore; + -moz-user-select: none; +} + +.panel-row-button:hover:active { + background: rgb(94,97,102) url(images/panelrow-active-hdpi.png) no-repeat; + background-size: 100% 100%; +} + +.panel-row-button:first-child { + -moz-border-start-width: 0 !important; +} + +.panel-row-button:last-child { + -moz-border-end-width: 0 !important; +} + +@media (@orientation@: portrait) { + .panel-row-button { + -moz-box-orient: vertical; + } + + .panel-row-button .toolbarbutton-text { + font-size: @font_xsmall@ !important; + } +} + +.panel-row-button .toolbarbutton-text { + text-align: left; + text-shadow: rgba(0,0,0,0.3) 0 @shadow_width_small@; +} + +.panel-row-button .toolbarbutton-text:-moz-locale-dir(rtl) { + text-align: right; +} + +.panel-row-button[disabled="true"] { + pointer-events: none; +} + +.panel-row-button[disabled="true"] .toolbarbutton-icon { + opacity: 0.5; +} + +.panel-row-button[disabled="true"] .toolbarbutton-text { + color: #aaa; +} + +.panel-row-button[checked="true"] { + color: white !important; + background: rgb(94, 97, 102) url(images/panelrow-selected-hdpi.png) no-repeat !important; + background-size: 100% 100% !important; +} + +.panel-row-button[checked="true"], +.panel-row-button[disabled="true"] { + pointer-events: none; +} + +#panel-container-inner { + -moz-box-orient: vertical; +} + +#panel-controls { + -moz-box-orient: horizontal; +} + +@media (min-width: @tablet_panel_minwidth@) { + #panel-container-inner { + -moz-box-orient: horizontal; + -moz-box-pack: center; + } + + #panel-items { + max-width: @tablet_panel_minwidth@; + min-width: 0px !important; + } + + /* This will affect the prefs screen, but not the awesome screen */ + #panel-controls { + -moz-box-orient: vertical !important; + -moz-box-align: start; + } + + #panel-controls > .panel-row-button { + -moz-box-orient: horizontal; + -moz-box-flex: 0; + min-width: @tablet_panel_controls@ !important; + } + + #panel-controls .toolbarbutton-text { + display: -moz-box !important; + -moz-box-flex: 1; + } + + #panel-container { + -moz-box-pack: center; + padding: @padding_xlarge@ 0px; + } +} + +/* because the buttons can wrap, we need to use the margin to create inter-button + spacing and a bottom margin for the notification */ +notification > button { + margin-bottom: @margin_normal@; +} diff --git a/mobile/android/themes/core/touchcontrols.css b/mobile/android/themes/core/touchcontrols.css new file mode 100644 index 00000000000..022476b4cc8 --- /dev/null +++ b/mobile/android/themes/core/touchcontrols.css @@ -0,0 +1,169 @@ +@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul); + +/* video controls */ +.controlsOverlay { + -moz-box-pack: center; + -moz-box-align: end; + padding: 20px; + -moz-box-flex: 1; + -moz-box-orient: horizontal; +} + +.controlBar { + -moz-box-flex: 1; + font-size: 16pt; + padding: 10px; + background-color: #34353a; + border-radius: 8px; + width: 100%; +} + +.controlsSpacer { + display: none; + -moz-box-flex: 0; +} + +.playButton, +.muteButton { + -moz-appearance: none; + min-height: 42px; + min-width: 42px; + border: none !important; +} + +.playButton { + -moz-transform: translateX(21px); + background: url("chrome://browser/skin/images/pause-hdpi.png") no-repeat center; +} + +.playButton[paused="true"] { + background: url("chrome://browser/skin/images/play-hdpi.png") no-repeat center; +} + +.muteButton { + background: url("chrome://browser/skin/images/mute-hdpi.png") no-repeat center; +} + +.muteButton[muted="true"] { + background: url("chrome://browser/skin/images/unmute-hdpi.png") no-repeat center; +} + +/* bars */ +.scrubberStack { + width: 100%; + min-height: 32px; + max-height: 32px; + padding: 0px 8px; + margin: 0px; +} + +.bufferBar, +.bufferBar .progress-bar, +.progressBar, +.progressBar .progress-bar, +.scrubber, +.scrubber .scale-slider, +.scrubber .scale-thumb { + -moz-appearance: none; + border: none; + padding: 0px; + margin: 0px; + background-color: transparent; +} + +.bufferBar { + border: 1px solid #5e6166; +} + +.bufferBar, +.progressBar { + margin: 9px 0px 11px 0px; + height: 8px +} + +.bufferBar .progress-bar { + background-color: #5e6166; +} + +.progressBar .progress-bar { + background-color: white; +} + +.scrubber { + margin-left: -16px; + margin-right: -16px; +} + +.scrubber .scale-thumb { + display: -moz-box; + background: url("chrome://browser/skin/images/scrubber-hdpi.png") no-repeat; + height: 32px; + width: 32px; +} + +.durationBox { + -moz-box-orient: horizontal; + -moz-box-pack: start; + -moz-box-align: center; + color: white; + font-weight: bold; + padding: 0px 8px; + margin-top: -6px; +} + +.positionLabel { + -moz-box-flex: 1; +} + +.statusOverlay { + -moz-box-align: center; + -moz-box-pack: center; + background-color: rgb(50,50,50); +} + +.statusIcon { + margin-bottom: 28px; + width: 36px; + height: 36px; +} + +.statusIcon[type="throbber"] { + background: url(chrome://global/skin/media/throbber.png) no-repeat center; +} + +.statusIcon[type="error"] { + background: url(chrome://global/skin/media/error.png) no-repeat center; +} + +/* CSS Transitions */ +.controlBar:not([immediate]) { + -moz-transition-property: opacity; + -moz-transition-duration: 200ms; +} + +.controlBar[fadeout] { + opacity: 0; +} + +.statusOverlay:not([immediate]) { + -moz-transition-property: opacity; + -moz-transition-duration: 300ms; + -moz-transition-delay: 750ms; +} + +.statusOverlay[fadeout] { + opacity: 0; +} + +.volumeStack, +.controlBar[firstshow="true"] .muteButton, +.controlBar[firstshow="true"] .scrubberStack, +.controlBar[firstshow="true"] .durationBox, +.timeLabel { + display: none; +} + +.controlBar[firstshow="true"] .playButton { + -moz-transform: none; +} + diff --git a/mobile/xul/installer/package-manifest.in b/mobile/xul/installer/package-manifest.in index 36f73ddf081..32240c418c0 100644 --- a/mobile/xul/installer/package-manifest.in +++ b/mobile/xul/installer/package-manifest.in @@ -82,6 +82,7 @@ #ifdef ANDROID @BINPATH@/AndroidManifest.xml @BINPATH@/resources.arsc +@BINPATH@/package-name.txt @BINPATH@/classes.dex @BINPATH@/@DLL_PREFIX@mozutils@DLL_SUFFIX@ @BINPATH@/res/drawable diff --git a/other-licenses/android/APKOpen.cpp b/other-licenses/android/APKOpen.cpp index 1f217c845b4..2e884a7bf79 100644 --- a/other-licenses/android/APKOpen.cpp +++ b/other-licenses/android/APKOpen.cpp @@ -623,6 +623,10 @@ report_mapping(char *name, void *base, uint32_t len, uint32_t offset) extern "C" void simple_linker_init(void); +extern "C" struct timeval timings[2]; +#define TIMING_RELOC 0 +#define TIMING_CONSTRUCTORS 1 + static void loadLibs(const char *apkName) { @@ -714,6 +718,9 @@ loadLibs(const char *apkName) (usage2.ru_utime.tv_sec - usage1.ru_utime.tv_sec)*1000 + (usage2.ru_utime.tv_usec - usage1.ru_utime.tv_usec)/1000, (usage2.ru_stime.tv_sec - usage1.ru_stime.tv_sec)*1000 + (usage2.ru_stime.tv_usec - usage1.ru_stime.tv_usec)/1000, usage2.ru_majflt-usage1.ru_majflt); + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Spent %dms on relocations, %dms on constructors", + timings[TIMING_RELOC].tv_sec * 1000 + timings[TIMING_RELOC].tv_usec / 1000, + timings[TIMING_CONSTRUCTORS].tv_sec * 1000 + timings[TIMING_CONSTRUCTORS].tv_usec / 1000); StartupTimeline_Record(LINKER_INITIALIZED, &t0); StartupTimeline_Record(LIBRARIES_LOADED, &t1); diff --git a/other-licenses/android/dlfcn.c b/other-licenses/android/dlfcn.c index bbde8bf41df..4295669d5f5 100644 --- a/other-licenses/android/dlfcn.c +++ b/other-licenses/android/dlfcn.c @@ -43,7 +43,6 @@ static const char *dl_errors[] = { #define unlikely(expr) __builtin_expect (expr, 0) static pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER; -extern int extractLibs; static void set_dlerror(int err) { @@ -54,9 +53,6 @@ static void set_dlerror(int err) void *__wrap_dlopen(const char *filename, int flag) { - if (extractLibs) - return dlopen(filename, flag); - soinfo *ret; pthread_mutex_lock(&dl_lock); @@ -88,9 +84,6 @@ void *moz_mapped_dlopen(const char *filename, int flag, const char *__wrap_dlerror(void) { - if (extractLibs) - return dlerror(); - const char *tmp = dl_err_str; dl_err_str = NULL; return (const char *)tmp; @@ -98,9 +91,6 @@ const char *__wrap_dlerror(void) void *__wrap_dlsym(void *handle, const char *symbol) { - if (extractLibs) - return dlsym(handle, symbol); - soinfo *found; Elf32_Sym *sym; unsigned bind; @@ -183,9 +173,6 @@ int __wrap_dladdr(void *addr, Dl_info *info) int __wrap_dlclose(void *handle) { - if (extractLibs) - return dlclose(handle); - pthread_mutex_lock(&dl_lock); (void)unload_library((soinfo*)handle); pthread_mutex_unlock(&dl_lock); diff --git a/other-licenses/android/linker.c b/other-licenses/android/linker.c index 7dd2a3d188e..4021f95a30e 100644 --- a/other-licenses/android/linker.c +++ b/other-licenses/android/linker.c @@ -96,6 +96,10 @@ static soinfo *sonext = &libdl_info; static soinfo *somain; /* main process, always the one after libdl_info */ #endif +/* Keep track of cumulative time spent in relocations and static constructors */ +#define TIMING_RELOC 0 +#define TIMING_CONSTRUCTORS 1 +struct timeval timings[2] = { { 0, 0 }, { 0, 0 } }; /* Set up for the buddy allocator managing the non-prelinked libraries. */ static struct ba_bits ba_nonprelink_bitmap[(LIBLAST - LIBBASE) / LIBINC]; @@ -1317,9 +1321,11 @@ soinfo *find_library(const char *name) } } - si = dlopen(name, RTLD_LAZY); - if (si) - return si; + if (strncmp(name, getenv("CACHE_PATH"), strlen(getenv("CACHE_PATH")))) { + si = dlopen(name, RTLD_LAZY); + if (si) + return si; + } TRACE("[ %5d '%s' has not been loaded yet. Locating...]\n", pid, name); si = load_library(name); @@ -1980,6 +1986,7 @@ static int link_image(soinfo *si, unsigned wr_offset) unsigned *d; Elf32_Phdr *phdr = si->phdr; int phnum = si->phnum; + struct timeval t0, t1; INFO("[ %5d linking %s ]\n", pid, si->name); DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid, @@ -2181,8 +2188,6 @@ static int link_image(soinfo *si, unsigned wr_offset) memset(preloads, 0, sizeof(preloads)); for(i = 0; ldpreload_names[i] != NULL; i++) { soinfo *lsi = find_library(ldpreload_names[i]); - if(lsi == 0) - lsi = dlopen(ldpreload_names[i], RTLD_LAZY); if(lsi == 0) { strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf)); DL_ERR("%5d could not load needed library '%s' for '%s' (%s)", @@ -2197,9 +2202,7 @@ static int link_image(soinfo *si, unsigned wr_offset) for(d = si->dynamic; *d; d += 2) { if(d[0] == DT_NEEDED){ DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]); - soinfo *lsi = dlopen(si->strtab + d[1], RTLD_LAZY); - if(lsi == 0) - lsi = find_library(si->strtab + d[1]); + soinfo *lsi = find_library(si->strtab + d[1]); if(lsi == 0) { strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf)); DL_ERR("%5d could not load needed library '%s' for '%s' (%s)", @@ -2218,6 +2221,7 @@ static int link_image(soinfo *si, unsigned wr_offset) } } + gettimeofday(&t0, 0); #ifndef ANDROID_NO_RUNTIME_RELOC /* Initialize GOT[1] and GOT[2], which are used by the PLT trampoline */ Elf32_Addr *got = (Elf32_Addr *)si->plt_got; @@ -2264,6 +2268,10 @@ static int link_image(soinfo *si, unsigned wr_offset) si->flags |= FLAG_LINKED; DEBUG("[ %5d finished linking %s ]\n", pid, si->name); + gettimeofday(&t1, 0); + timings[TIMING_RELOC].tv_usec += t1.tv_usec - t0.tv_usec; + timings[TIMING_RELOC].tv_sec += t1.tv_sec - t0.tv_sec; + #if 0 /* This is the way that the old dynamic linker did protection of * non-writable areas. It would scan section headers and find where @@ -2298,7 +2306,12 @@ static int link_image(soinfo *si, unsigned wr_offset) */ if (getuid() != geteuid() || getgid() != getegid()) nullify_closed_stdio (); + gettimeofday(&t0, 0); call_constructors(si); + gettimeofday(&t1, 0); + timings[TIMING_CONSTRUCTORS].tv_usec += t1.tv_usec - t0.tv_usec; + timings[TIMING_CONSTRUCTORS].tv_sec += t1.tv_sec - t0.tv_sec; + notify_gdb_of_load(si); return 0; diff --git a/other-licenses/skia-npapi/ANPCanvas.cpp b/other-licenses/skia-npapi/ANPCanvas.cpp new file mode 100644 index 00000000000..ce7eb56a47a --- /dev/null +++ b/other-licenses/skia-npapi/ANPCanvas.cpp @@ -0,0 +1,194 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "SkANP.h" + +static ANPCanvas* anp_newCanvas(const ANPBitmap* bitmap) { + SkBitmap bm; + return new ANPCanvas(*SkANP::SetBitmap(&bm, *bitmap)); +} + +static void anp_deleteCanvas(ANPCanvas* canvas) { + delete canvas; +} + +static void anp_save(ANPCanvas* canvas) { + canvas->skcanvas->save(); +} + +static void anp_restore(ANPCanvas* canvas) { + canvas->skcanvas->restore(); +} + +static void anp_translate(ANPCanvas* canvas, float tx, float ty) { + canvas->skcanvas->translate(SkFloatToScalar(tx), SkFloatToScalar(ty)); +} + +static void anp_scale(ANPCanvas* canvas, float sx, float sy) { + canvas->skcanvas->scale(SkFloatToScalar(sx), SkFloatToScalar(sy)); +} + +static void anp_rotate(ANPCanvas* canvas, float degrees) { + canvas->skcanvas->rotate(SkFloatToScalar(degrees)); +} + +static void anp_skew(ANPCanvas* canvas, float kx, float ky) { + canvas->skcanvas->skew(SkFloatToScalar(kx), SkFloatToScalar(ky)); +} + +static void anp_clipRect(ANPCanvas* canvas, const ANPRectF* rect) { + SkRect r; + canvas->skcanvas->clipRect(*SkANP::SetRect(&r, *rect)); +} + +static void anp_clipPath(ANPCanvas* canvas, const ANPPath* path) { + canvas->skcanvas->clipPath(*path); +} +static void anp_concat(ANPCanvas* canvas, const ANPMatrix* matrix) { + canvas->skcanvas->concat(*matrix); +} + +static void anp_getTotalMatrix(ANPCanvas* canvas, ANPMatrix* matrix) { + const SkMatrix& src = canvas->skcanvas->getTotalMatrix(); + *matrix = *reinterpret_cast(&src); +} + +static bool anp_getLocalClipBounds(ANPCanvas* canvas, ANPRectF* r, + bool antialias) { + SkRect bounds; + if (canvas->skcanvas->getClipBounds(&bounds, + antialias ? SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType)) { + SkANP::SetRect(r, bounds); + return true; + } + return false; +} + +static bool anp_getDeviceClipBounds(ANPCanvas* canvas, ANPRectI* r) { + const SkRegion& clip = canvas->skcanvas->getTotalClip(); + if (!clip.isEmpty()) { + SkANP::SetRect(r, clip.getBounds()); + return true; + } + return false; +} + +static void anp_drawColor(ANPCanvas* canvas, ANPColor color) { + canvas->skcanvas->drawColor(color); +} + +static void anp_drawPaint(ANPCanvas* canvas, const ANPPaint* paint) { + canvas->skcanvas->drawPaint(*paint); +} + +static void anp_drawLine(ANPCanvas* canvas, float x0, float y0, + float x1, float y1, const ANPPaint* paint) { + canvas->skcanvas->drawLine(SkFloatToScalar(x0), SkFloatToScalar(y0), + SkFloatToScalar(x1), SkFloatToScalar(y1), *paint); +} + +static void anp_drawRect(ANPCanvas* canvas, const ANPRectF* rect, + const ANPPaint* paint) { + SkRect r; + canvas->skcanvas->drawRect(*SkANP::SetRect(&r, *rect), *paint); +} + +static void anp_drawOval(ANPCanvas* canvas, const ANPRectF* rect, + const ANPPaint* paint) { + SkRect r; + canvas->skcanvas->drawOval(*SkANP::SetRect(&r, *rect), *paint); +} + +static void anp_drawPath(ANPCanvas* canvas, const ANPPath* path, + const ANPPaint* paint) { + canvas->skcanvas->drawPath(*path, *paint); +} + +static void anp_drawText(ANPCanvas* canvas, const void* text, uint32_t length, + float x, float y, const ANPPaint* paint) { + canvas->skcanvas->drawText(text, length, + SkFloatToScalar(x), SkFloatToScalar(y), + *paint); +} + +static void anp_drawPosText(ANPCanvas* canvas, const void* text, + uint32_t byteLength, const float xy[], const ANPPaint* paint) { + canvas->skcanvas->drawPosText(text, byteLength, + reinterpret_cast(xy), *paint); +} + +static void anp_drawBitmap(ANPCanvas* canvas, const ANPBitmap* bitmap, + float x, float y, const ANPPaint* paint) { + SkBitmap bm; + canvas->skcanvas->drawBitmap(*SkANP::SetBitmap(&bm, *bitmap), + SkFloatToScalar(x), SkFloatToScalar(y), + paint); +} + +static void anp_drawBitmapRect(ANPCanvas* canvas, const ANPBitmap* bitmap, + const ANPRectI* src, const ANPRectF* dst, + const ANPPaint* paint) { + SkBitmap bm; + SkRect dstR; + SkIRect srcR, *srcPtr = NULL; + + if (src) { + srcPtr = SkANP::SetRect(&srcR, *src); + } + canvas->skcanvas->drawBitmapRect(*SkANP::SetBitmap(&bm, *bitmap), srcPtr, + *SkANP::SetRect(&dstR, *dst), paint); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void InitCanvasInterface(ANPCanvasInterfaceV0* i) { + ASSIGN(i, newCanvas); + ASSIGN(i, deleteCanvas); + ASSIGN(i, save); + ASSIGN(i, restore); + ASSIGN(i, translate); + ASSIGN(i, scale); + ASSIGN(i, rotate); + ASSIGN(i, skew); + ASSIGN(i, clipRect); + ASSIGN(i, clipPath); + ASSIGN(i, concat); + ASSIGN(i, getTotalMatrix); + ASSIGN(i, getLocalClipBounds); + ASSIGN(i, getDeviceClipBounds); + ASSIGN(i, drawColor); + ASSIGN(i, drawPaint); + ASSIGN(i, drawLine); + ASSIGN(i, drawRect); + ASSIGN(i, drawOval); + ASSIGN(i, drawPath); + ASSIGN(i, drawText); + ASSIGN(i, drawPosText); + ASSIGN(i, drawBitmap); + ASSIGN(i, drawBitmapRect); +} diff --git a/other-licenses/skia-npapi/ANPPaint.cpp b/other-licenses/skia-npapi/ANPPaint.cpp new file mode 100644 index 00000000000..aa9d2fbd680 --- /dev/null +++ b/other-licenses/skia-npapi/ANPPaint.cpp @@ -0,0 +1,209 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "SkANP.h" +#include "SkTypeface.h" + +static ANPPaint* anp_newPaint() { + return new ANPPaint; +} + +static void anp_deletePaint(ANPPaint* paint) { + delete paint; +} + +static ANPPaintFlags anp_getFlags(const ANPPaint* paint) { + return paint->getFlags(); +} + +static void anp_setFlags(ANPPaint* paint, ANPPaintFlags flags) { + paint->setFlags(flags); +} + +static ANPColor anp_getColor(const ANPPaint* paint) { + return paint->getColor(); +} + +static void anp_setColor(ANPPaint* paint, ANPColor color) { + paint->setColor(color); +} + +static ANPPaintStyle anp_getStyle(const ANPPaint* paint) { + return paint->getStyle(); +} + +static void anp_setStyle(ANPPaint* paint, ANPPaintStyle style) { + paint->setStyle(static_cast(style)); +} + +static float anp_getStrokeWidth(const ANPPaint* paint) { + return SkScalarToFloat(paint->getStrokeWidth()); +} + +static float anp_getStrokeMiter(const ANPPaint* paint) { + return SkScalarToFloat(paint->getStrokeMiter()); +} + +static ANPPaintCap anp_getStrokeCap(const ANPPaint* paint) { + return paint->getStrokeCap(); +} + +static ANPPaintJoin anp_getStrokeJoin(const ANPPaint* paint) { + return paint->getStrokeJoin(); +} + +static void anp_setStrokeWidth(ANPPaint* paint, float width) { + paint->setStrokeWidth(SkFloatToScalar(width)); +} + +static void anp_setStrokeMiter(ANPPaint* paint, float miter) { + paint->setStrokeMiter(SkFloatToScalar(miter)); +} + +static void anp_setStrokeCap(ANPPaint* paint, ANPPaintCap cap) { + paint->setStrokeCap(static_cast(cap)); +} + +static void anp_setStrokeJoin(ANPPaint* paint, ANPPaintJoin join) { + paint->setStrokeJoin(static_cast(join)); +} + +static ANPTextEncoding anp_getTextEncoding(const ANPPaint* paint) { + return paint->getTextEncoding(); +} + +static ANPPaintAlign anp_getTextAlign(const ANPPaint* paint) { + return paint->getTextAlign(); +} + +static float anp_getTextSize(const ANPPaint* paint) { + return SkScalarToFloat(paint->getTextSize()); +} + +static float anp_getTextScaleX(const ANPPaint* paint) { + return SkScalarToFloat(paint->getTextScaleX()); +} + +static float anp_getTextSkewX(const ANPPaint* paint) { + return SkScalarToFloat(paint->getTextSkewX()); +} + +static ANPTypeface* anp_getTypeface(const ANPPaint* paint) { + return reinterpret_cast(paint->getTypeface()); +} + +static void anp_setTextEncoding(ANPPaint* paint, ANPTextEncoding encoding) { + paint->setTextEncoding(static_cast(encoding)); +} + +static void anp_setTextAlign(ANPPaint* paint, ANPPaintAlign align) { + paint->setTextAlign(static_cast(align)); +} + +static void anp_setTextSize(ANPPaint* paint, float textSize) { + paint->setTextSize(SkFloatToScalar(textSize)); +} + +static void anp_setTextScaleX(ANPPaint* paint, float scaleX) { + paint->setTextScaleX(SkFloatToScalar(scaleX)); +} + +static void anp_setTextSkewX(ANPPaint* paint, float skewX) { + paint->setTextSkewX(SkFloatToScalar(skewX)); +} + +static void anp_setTypeface(ANPPaint* paint, ANPTypeface* tf) { + paint->setTypeface(tf); +} + +static float anp_measureText(ANPPaint* paint, const void* text, + uint32_t byteLength, ANPRectF* bounds) { + SkScalar w = paint->measureText(text, byteLength, + reinterpret_cast(bounds)); + return SkScalarToFloat(w); +} + +/** Return the number of unichars specifed by the text. + If widths is not null, returns the array of advance widths for each + unichar. + If bounds is not null, returns the array of bounds for each unichar. + */ +static int anp_getTextWidths(ANPPaint* paint, const void* text, + uint32_t byteLength, float widths[], ANPRectF bounds[]) { + return paint->getTextWidths(text, byteLength, widths, + reinterpret_cast(bounds)); +} + +static float anp_getFontMetrics(ANPPaint* paint, ANPFontMetrics* metrics) { + SkPaint::FontMetrics fm; + SkScalar spacing = paint->getFontMetrics(&fm); + if (metrics) { + metrics->fTop = SkScalarToFloat(fm.fTop); + metrics->fAscent = SkScalarToFloat(fm.fAscent); + metrics->fDescent = SkScalarToFloat(fm.fDescent); + metrics->fBottom = SkScalarToFloat(fm.fBottom); + metrics->fLeading = SkScalarToFloat(fm.fLeading); + } + return SkScalarToFloat(spacing); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void InitPaintInterface(ANPPaintInterfaceV0* i) { + ASSIGN(i, newPaint); + ASSIGN(i, deletePaint); + ASSIGN(i, getFlags); + ASSIGN(i, setFlags); + ASSIGN(i, getColor); + ASSIGN(i, setColor); + ASSIGN(i, getStyle); + ASSIGN(i, setStyle); + ASSIGN(i, getStrokeWidth); + ASSIGN(i, getStrokeMiter); + ASSIGN(i, getStrokeCap); + ASSIGN(i, getStrokeJoin); + ASSIGN(i, setStrokeWidth); + ASSIGN(i, setStrokeMiter); + ASSIGN(i, setStrokeCap); + ASSIGN(i, setStrokeJoin); + ASSIGN(i, getTextEncoding); + ASSIGN(i, getTextAlign); + ASSIGN(i, getTextSize); + ASSIGN(i, getTextScaleX); + ASSIGN(i, getTextSkewX); + ASSIGN(i, getTypeface); + ASSIGN(i, setTextEncoding); + ASSIGN(i, setTextAlign); + ASSIGN(i, setTextSize); + ASSIGN(i, setTextScaleX); + ASSIGN(i, setTextSkewX); + ASSIGN(i, setTypeface); + ASSIGN(i, measureText); + ASSIGN(i, getTextWidths); + ASSIGN(i, getFontMetrics); +} diff --git a/other-licenses/skia-npapi/ANPPath.cpp b/other-licenses/skia-npapi/ANPPath.cpp new file mode 100644 index 00000000000..7deb871efec --- /dev/null +++ b/other-licenses/skia-npapi/ANPPath.cpp @@ -0,0 +1,109 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "SkANP.h" + +static ANPPath* anp_newPath() { + return new ANPPath; +} + +static void anp_deletePath(ANPPath* path) { + delete path; +} + +static void anp_copy(ANPPath* dst, const ANPPath* src) { + *dst = *src; +} + +static bool anp_equal(const ANPPath* p0, const ANPPath* p1) { + return *p0 == *p1; +} + +static void anp_reset(ANPPath* path) { + path->reset(); +} + +static bool anp_isEmpty(const ANPPath* path) { + return path->isEmpty(); +} + +static void anp_getBounds(const ANPPath* path, ANPRectF* bounds) { + SkANP::SetRect(bounds, path->getBounds()); +} + +static void anp_moveTo(ANPPath* path, float x, float y) { + path->moveTo(SkFloatToScalar(x), SkFloatToScalar(y)); +} + +static void anp_lineTo(ANPPath* path, float x, float y) { + path->lineTo(SkFloatToScalar(x), SkFloatToScalar(y)); +} + +static void anp_quadTo(ANPPath* path, float x0, float y0, float x1, float y1) { + path->quadTo(SkFloatToScalar(x0), SkFloatToScalar(y0), + SkFloatToScalar(x1), SkFloatToScalar(y1)); +} + +static void anp_cubicTo(ANPPath* path, float x0, float y0, + float x1, float y1, float x2, float y2) { + path->cubicTo(SkFloatToScalar(x0), SkFloatToScalar(y0), + SkFloatToScalar(x1), SkFloatToScalar(y1), + SkFloatToScalar(x2), SkFloatToScalar(y2)); +} + +static void anp_close(ANPPath* path) { + path->close(); +} + +static void anp_offset(ANPPath* path, float dx, float dy, ANPPath* dst) { + path->offset(SkFloatToScalar(dx), SkFloatToScalar(dy), dst); +} + +static void anp_transform(ANPPath* src, const ANPMatrix* matrix, + ANPPath* dst) { + src->transform(*matrix, dst); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void InitPathInterface(ANPPathInterfaceV0* i) { + ASSIGN(i, newPath); + ASSIGN(i, deletePath); + ASSIGN(i, copy); + ASSIGN(i, equal); + ASSIGN(i, reset); + ASSIGN(i, isEmpty); + ASSIGN(i, getBounds); + ASSIGN(i, moveTo); + ASSIGN(i, lineTo); + ASSIGN(i, quadTo); + ASSIGN(i, cubicTo); + ASSIGN(i, close); + ASSIGN(i, offset); + ASSIGN(i, transform); +} diff --git a/other-licenses/skia-npapi/ANPTypeface.cpp b/other-licenses/skia-npapi/ANPTypeface.cpp new file mode 100644 index 00000000000..e095de9829f --- /dev/null +++ b/other-licenses/skia-npapi/ANPTypeface.cpp @@ -0,0 +1,101 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "SkANP.h" +#include "SkFontHost.h" + +static ANPTypeface* anp_createFromName(const char name[], ANPTypefaceStyle s) { + SkTypeface* tf = SkTypeface::CreateFromName(name, + static_cast(s)); + return reinterpret_cast(tf); +} + +static ANPTypeface* anp_createFromTypeface(const ANPTypeface* family, + ANPTypefaceStyle s) { + SkTypeface* tf = SkTypeface::CreateFromTypeface(family, + static_cast(s)); + return reinterpret_cast(tf); +} + +static int32_t anp_getRefCount(const ANPTypeface* tf) { + return tf ? tf->getRefCnt() : 0; +} + +static void anp_ref(ANPTypeface* tf) { + SkSafeRef(tf); +} + +static void anp_unref(ANPTypeface* tf) { + SkSafeUnref(tf); +} + +static ANPTypefaceStyle anp_getStyle(const ANPTypeface* tf) { + SkTypeface::Style s = tf ? tf->style() : SkTypeface::kNormal; + return static_cast(s); +} + +static int32_t anp_getFontPath(const ANPTypeface* tf, char fileName[], + int32_t length, int32_t* index) { + size_t size = SkFontHost::GetFileName(SkTypeface::UniqueID(tf), fileName, + length, index); + return static_cast(size); +} + +static const char* gFontDir; +#define FONT_DIR_SUFFIX "/fonts/" + +static const char* anp_getFontDirectoryPath() { + if (NULL == gFontDir) { + const char* root = getenv("ANDROID_ROOT"); + size_t len = strlen(root); + char* storage = (char*)malloc(len + sizeof(FONT_DIR_SUFFIX)); + if (NULL == storage) { + return NULL; + } + memcpy(storage, root, len); + memcpy(storage + len, FONT_DIR_SUFFIX, sizeof(FONT_DIR_SUFFIX)); + // save this assignment for last, so that if multiple threads call us + // (which should never happen), we never return an incomplete global. + // At worst, we would allocate storage for the path twice. + gFontDir = storage; + } + return gFontDir; +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void InitTypeFaceInterface(ANPTypefaceInterfaceV0* i) { + ASSIGN(i, createFromName); + ASSIGN(i, createFromTypeface); + ASSIGN(i, getRefCount); + ASSIGN(i, ref); + ASSIGN(i, unref); + ASSIGN(i, getStyle); + ASSIGN(i, getFontPath); + ASSIGN(i, getFontDirectoryPath); +} diff --git a/other-licenses/skia-npapi/Makefile.in b/other-licenses/skia-npapi/Makefile.in new file mode 100644 index 00000000000..c067c426077 --- /dev/null +++ b/other-licenses/skia-npapi/Makefile.in @@ -0,0 +1,72 @@ +# ***** 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 the Mozilla browser. +# +# 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): +# James Willcox +# +# 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 + +MODULE = skia_npapi +LIBRARY_NAME = skia_npapi +LIBXUL_LIBRARY = 1 +EXPORT_LIBRARY = 1 + +DEFINES += \ + -DSK_BUILD_FOR_ANDROID_NDK \ + $(NULL) + +LOCAL_INCLUDES += \ + -I$(topsrcdir)/dom/plugins/base \ + -I$(topsrcdir)/dom/plugins/base/android \ + -I$(topsrcdir)/gfx/skia/include/core \ + -I$(topsrcdir)/gfx/skia/include/config \ + $(NULL) + + +CPPSRCS = \ + SkANP.cpp \ + ANPCanvas.cpp \ + ANPPaint.cpp \ + ANPPath.cpp \ + ANPTypeface.cpp \ + $(NULL) + +EXPORTS = SkANP.h + +include $(topsrcdir)/config/rules.mk diff --git a/other-licenses/skia-npapi/SkANP.cpp b/other-licenses/skia-npapi/SkANP.cpp new file mode 100644 index 00000000000..ca02de9ffe5 --- /dev/null +++ b/other-licenses/skia-npapi/SkANP.cpp @@ -0,0 +1,104 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "SkANP.h" + +SkRect* SkANP::SetRect(SkRect* dst, const ANPRectF& src) { + dst->set(SkFloatToScalar(src.left), + SkFloatToScalar(src.top), + SkFloatToScalar(src.right), + SkFloatToScalar(src.bottom)); + return dst; +} + +SkIRect* SkANP::SetRect(SkIRect* dst, const ANPRectI& src) { + dst->set(src.left, src.top, src.right, src.bottom); + return dst; +} + +ANPRectI* SkANP::SetRect(ANPRectI* dst, const SkIRect& src) { + dst->left = src.fLeft; + dst->top = src.fTop; + dst->right = src.fRight; + dst->bottom = src.fBottom; + return dst; +} + +ANPRectF* SkANP::SetRect(ANPRectF* dst, const SkRect& src) { + dst->left = SkScalarToFloat(src.fLeft); + dst->top = SkScalarToFloat(src.fTop); + dst->right = SkScalarToFloat(src.fRight); + dst->bottom = SkScalarToFloat(src.fBottom); + return dst; +} + +SkBitmap* SkANP::SetBitmap(SkBitmap* dst, const ANPBitmap& src) { + SkBitmap::Config config = SkBitmap::kNo_Config; + + switch (src.format) { + case kRGBA_8888_ANPBitmapFormat: + config = SkBitmap::kARGB_8888_Config; + break; + case kRGB_565_ANPBitmapFormat: + config = SkBitmap::kRGB_565_Config; + break; + default: + break; + } + + dst->setConfig(config, src.width, src.height, src.rowBytes); + dst->setPixels(src.baseAddr); + return dst; +} + +bool SkANP::SetBitmap(ANPBitmap* dst, const SkBitmap& src) { + if (!(dst->baseAddr = src.getPixels())) { + SkDebugf("SkANP::SetBitmap - getPixels() returned null\n"); + return false; + } + + switch (src.config()) { + case SkBitmap::kARGB_8888_Config: + dst->format = kRGBA_8888_ANPBitmapFormat; + break; + case SkBitmap::kRGB_565_Config: + dst->format = kRGB_565_ANPBitmapFormat; + break; + default: + SkDebugf("SkANP::SetBitmap - unsupported src.config %d\n", src.config()); + return false; + } + + dst->width = src.width(); + dst->height = src.height(); + dst->rowBytes = src.rowBytes(); + return true; +} + +void SkANP::InitEvent(ANPEvent* event, ANPEventType et) { + event->inSize = sizeof(ANPEvent); + event->eventType = et; +} diff --git a/other-licenses/skia-npapi/SkANP.h b/other-licenses/skia-npapi/SkANP.h new file mode 100644 index 00000000000..5c2a936501b --- /dev/null +++ b/other-licenses/skia-npapi/SkANP.h @@ -0,0 +1,79 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SkANP_DEFINED +#define SkANP_DEFINED + +#include "android_npapi.h" +#include "SkCanvas.h" +#include "SkMatrix.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkTypeface.h" + +struct ANPMatrix : SkMatrix { +}; + +struct ANPPath : SkPath { +}; + +struct ANPPaint : SkPaint { +}; + +struct ANPTypeface : SkTypeface { +}; + +struct ANPCanvas { + SkCanvas* skcanvas; + + // draw into the specified bitmap + explicit ANPCanvas(const SkBitmap& bm) { + skcanvas = new SkCanvas(bm); + } + + // redirect all drawing to the specific SkCanvas + explicit ANPCanvas(SkCanvas* other) { + skcanvas = other; + skcanvas->ref(); + } + + ~ANPCanvas() { + skcanvas->unref(); + } +}; + +class SkANP { +public: + static SkRect* SetRect(SkRect* dst, const ANPRectF& src); + static SkIRect* SetRect(SkIRect* dst, const ANPRectI& src); + static ANPRectI* SetRect(ANPRectI* dst, const SkIRect& src); + static ANPRectF* SetRect(ANPRectF* dst, const SkRect& src); + static SkBitmap* SetBitmap(SkBitmap* dst, const ANPBitmap& src); + static bool SetBitmap(ANPBitmap* dst, const SkBitmap& src); + + static void InitEvent(ANPEvent* event, ANPEventType et); +}; + +#endif diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index b1ded450499..4032966b8ab 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -316,7 +316,7 @@ endif STATIC_LIBS += thebes gl ycbcr ifeq ($(OS_TARGET),Android) -STATIC_LIBS += profiler +STATIC_LIBS += profiler skia_npapi endif STATIC_LIBS += angle diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index c8672031dc5..4b731ff2314 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -290,6 +290,7 @@ DIST_FILES = \ libsoftokn3.so \ extensions \ application.ini \ + package-name.txt \ platform.ini \ greprefs.js \ browserconfig.properties \ diff --git a/toolkit/xre/Makefile.in b/toolkit/xre/Makefile.in index f15e0f9bcb9..5a3a2f96499 100644 --- a/toolkit/xre/Makefile.in +++ b/toolkit/xre/Makefile.in @@ -256,8 +256,20 @@ GRE_BUILDID := $(shell cat $(DEPTH)/config/buildid) DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID) +ifdef MOZILLA_OFFICIAL +DEFINES += -DMOZILLA_OFFICIAL +endif + +DEFINES += -DAPP_VERSION=$(MOZ_APP_VERSION) + +DEFINES += -DAPP_ID=$(MOZ_APP_ID) + $(srcdir)/nsAppRunner.cpp: $(DEPTH)/config/buildid $(topsrcdir)/config/milestone.txt +ifeq ($(OS_TARGET),Android) +nsAndroidStartup.o: $(DEPTH)/config/buildid $(topsrcdir)/config/milestone.txt +endif + platform.ini: FORCE $(PYTHON) $(srcdir)/make-platformini.py --buildid=$(shell cat $(DEPTH)/config/buildid) $(INIARGS) $(topsrcdir)/config/milestone.txt > $@ diff --git a/widget/src/android/AndroidBridge.cpp b/widget/src/android/AndroidBridge.cpp index 7799d54dfce..fd5235a28ad 100644 --- a/widget/src/android/AndroidBridge.cpp +++ b/widget/src/android/AndroidBridge.cpp @@ -105,8 +105,8 @@ bool AndroidBridge::Init(JNIEnv *jEnv, jclass jGeckoAppShellClass) { - ALOG_BRIDGE("AndroidBridge::Init"); jEnv->GetJavaVM(&mJavaVM); + ALOG_BRIDGE("AndroidBridge::Init1"); mJNIEnv = nsnull; mThread = nsnull; @@ -125,7 +125,6 @@ AndroidBridge::Init(JNIEnv *jEnv, jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V"); jReturnIMEQueryResult = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "returnIMEQueryResult", "(Ljava/lang/String;II)V"); jScheduleRestart = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scheduleRestart", "()V"); - jNotifyAppShellReady = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onAppShellReady", "()V"); jNotifyXreExit = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onXreExit", "()V"); jGetHandlersForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); jGetHandlersForURL = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForURL", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"); @@ -362,15 +361,6 @@ AndroidBridge::ReturnIMEQueryResult(const PRUnichar *aResult, PRUint32 aLen, jReturnIMEQueryResult, args); } -void -AndroidBridge::NotifyAppShellReady() -{ - ALOG_BRIDGE("AndroidBridge::NotifyAppShellReady"); - mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyAppShellReady); - - mURIFixup = do_GetService(NS_URIFIXUP_CONTRACTID); -} - void AndroidBridge::ScheduleRestart() { @@ -590,8 +580,10 @@ AndroidBridge::CanCreateFixupURI(const nsACString& aURIText) { ALOG_BRIDGE("AndroidBridge::CanCreateFixupURI"); - if (!mURIFixup) - return false; + if (!mURIFixup) { + mURIFixup = do_GetService(NS_URIFIXUP_CONTRACTID); + if (!mURIFixup) return false; + } nsCOMPtr targetURI; diff --git a/widget/src/android/AndroidBridge.h b/widget/src/android/AndroidBridge.h index 108fbb545ae..094a47af938 100644 --- a/widget/src/android/AndroidBridge.h +++ b/widget/src/android/AndroidBridge.h @@ -145,8 +145,6 @@ public: void ReturnIMEQueryResult(const PRUnichar *aResult, PRUint32 aLen, int aSelStart, int aSelLen); - void NotifyAppShellReady(); - void NotifyXreExit(); void ScheduleRestart(); diff --git a/widget/src/android/nsAppShell.cpp b/widget/src/android/nsAppShell.cpp index 4fb87b182fa..f1206b7a73e 100644 --- a/widget/src/android/nsAppShell.cpp +++ b/widget/src/android/nsAppShell.cpp @@ -121,8 +121,6 @@ nsAppShell::Init() nsresult rv = nsBaseAppShell::Init(); AndroidBridge* bridge = AndroidBridge::Bridge(); - if (bridge) - bridge->NotifyAppShellReady(); nsCOMPtr obsServ = mozilla::services::GetObserverService(); diff --git a/widget/src/android/nsWindow.cpp b/widget/src/android/nsWindow.cpp index 14a3132684d..7ada0dff4bd 100644 --- a/widget/src/android/nsWindow.cpp +++ b/widget/src/android/nsWindow.cpp @@ -79,7 +79,7 @@ using mozilla::unused; #include "nsStringGlue.h" -// NB: Keep these in sync with LayerController.java in embedding/android/. +// NB: Keep these in sync with LayerController.java in mobile/android/base and embedding/android/. #define TILE_WIDTH 1024 #define TILE_HEIGHT 2048