Merge mozilla-central to birch.

This commit is contained in:
L. David Baron 2011-11-24 15:28:46 -08:00
Родитель db43b8c8b1 142d9c080e
Коммит af9037bcd9
836 изменённых файлов: 47619 добавлений и 4555 удалений

Просмотреть файл

@ -66,7 +66,7 @@ tier_base_dirs = \
ifndef LIBXUL_SDK ifndef LIBXUL_SDK
ifeq (android,$(MOZ_WIDGET_TOOLKIT)) ifeq (android,$(MOZ_WIDGET_TOOLKIT))
tier_base_dirs += other-licenses/android tier_base_dirs += other-licenses/android other-licenses/skia-npapi
endif endif
tier_base_dirs += memory tier_base_dirs += memory

Просмотреть файл

@ -4721,6 +4721,7 @@ case "${target}" in
MOZ_THEME_FASTSTRIPE=1 MOZ_THEME_FASTSTRIPE=1
MOZ_TREE_FREETYPE=1 MOZ_TREE_FREETYPE=1
MOZ_MEMORY=1 MOZ_MEMORY=1
MOZ_SPELLCHECK=
MOZ_RAW=1 MOZ_RAW=1
;; ;;
esac esac

Просмотреть файл

@ -141,7 +141,7 @@ interface nsIContentViewManager : nsISupports
readonly attribute nsIContentView rootContentView; readonly attribute nsIContentView rootContentView;
}; };
[scriptable, uuid(12905a29-4246-475a-81d4-fc389197df02)] [scriptable, uuid(efc0b731-45dc-4189-8ffa-d3eeeb850977)]
interface nsIFrameLoader : nsISupports interface nsIFrameLoader : nsISupports
{ {
/** /**
@ -258,6 +258,13 @@ interface nsIFrameLoader : nsISupports
const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001; const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001;
attribute unsigned long eventMode; 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<nsFrameLoader>); native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);

Просмотреть файл

@ -145,6 +145,8 @@ public:
static void InvalidateFrame(nsIFrame* aFrame) static void InvalidateFrame(nsIFrame* aFrame)
{ {
if (!aFrame)
return;
nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size()); nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size());
// NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
// semantics the same for both in-process and out-of-process // 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 // XXX could be clever here and compute a smaller invalidation
// rect // rect
nsIFrame* frame = mFrameLoader->GetPrimaryFrameOfOwningContent(); InvalidateFrame(mFrameLoader->GetPrimaryFrameOfOwningContent());
InvalidateFrame(frame);
return NS_OK; return NS_OK;
} }
@ -328,6 +329,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
, mDelayRemoteDialogs(false) , mDelayRemoteDialogs(false)
, mRemoteBrowserShown(false) , mRemoteBrowserShown(false)
, mRemoteFrame(false) , mRemoteFrame(false)
, mClipSubdocument(true)
, mCurrentRemoteFrame(nsnull) , mCurrentRemoteFrame(nsnull)
, mRemoteBrowser(nsnull) , mRemoteBrowser(nsnull)
, mRenderMode(RENDER_MODE_DEFAULT) , mRenderMode(RENDER_MODE_DEFAULT)
@ -1711,6 +1713,38 @@ nsFrameLoader::SetEventMode(PRUint32 aEventMode)
return NS_OK; 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 nsIntSize
nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame) nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
{ {

Просмотреть файл

@ -287,6 +287,8 @@ public:
mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; } mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
void SetOwnerContent(mozilla::dom::Element* aContent); void SetOwnerContent(mozilla::dom::Element* aContent);
bool ShouldClipSubdocument() { return mClipSubdocument; }
private: private:
bool ShouldUseRemoteProcess(); bool ShouldUseRemoteProcess();
@ -338,7 +340,9 @@ private:
bool mDelayRemoteDialogs : 1; bool mDelayRemoteDialogs : 1;
bool mRemoteBrowserShown : 1; bool mRemoteBrowserShown : 1;
bool mRemoteFrame; bool mRemoteFrame : 1;
bool mClipSubdocument : 1;
// XXX leaking // XXX leaking
nsCOMPtr<nsIObserver> mChildHost; nsCOMPtr<nsIObserver> mChildHost;
RenderFrameParent* mCurrentRemoteFrame; RenderFrameParent* mCurrentRemoteFrame;

Просмотреть файл

@ -4580,6 +4580,9 @@ nsGlobalWindow::Dump(const nsAString& aStr)
nsMemory::Free(cstr); nsMemory::Free(cstr);
} }
#if defined(ANDROID) && defined(DEBUG)
__android_log_print(ANDROID_LOG_INFO, "GeckoDump", "%s", cstr);
#endif
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -133,7 +133,10 @@ endif
endif endif
LOCAL_INCLUDES += \ LOCAL_INCLUDES += \
-DSK_BUILD_FOR_ANDROID_NDK \
-I$(topsrcdir)/xpcom/base/ \ -I$(topsrcdir)/xpcom/base/ \
-I$(topsrcdir)/gfx/skia/include/core \
-I$(topsrcdir)/gfx/skia/include/config \
$(MOZ_CAIRO_CFLAGS) \ $(MOZ_CAIRO_CFLAGS) \
$(NULL) $(NULL)

Просмотреть файл

@ -39,7 +39,6 @@
#include "android_npapi.h" #include "android_npapi.h"
#include <stdlib.h> #include <stdlib.h>
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "gfxFont.h"
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
#define NOT_IMPLEMENTED_FATAL() do { \ #define NOT_IMPLEMENTED_FATAL() do { \
@ -54,8 +53,6 @@
"!!!!!!!!!!!!!! %s not implemented %s, %d", \ "!!!!!!!!!!!!!! %s not implemented %s, %d", \
__PRETTY_FUNCTION__, __FILE__, __LINE__); \ __PRETTY_FUNCTION__, __FILE__, __LINE__); \
class gfxFont;
void InitAudioTrackInterface(ANPAudioTrackInterfaceV0 *i); void InitAudioTrackInterface(ANPAudioTrackInterfaceV0 *i);
void InitBitmapInterface(ANPBitmapInterfaceV0 *i); void InitBitmapInterface(ANPBitmapInterfaceV0 *i);
void InitCanvasInterface(ANPCanvasInterfaceV0 *i); void InitCanvasInterface(ANPCanvasInterfaceV0 *i);
@ -68,25 +65,3 @@ void InitSurfaceInterface(ANPSurfaceInterfaceV0 *i);
void InitSystemInterface(ANPSystemInterfaceV0 *i); void InitSystemInterface(ANPSystemInterfaceV0 *i);
void InitTypeFaceInterface(ANPTypefaceInterfaceV0 *i); void InitTypeFaceInterface(ANPTypefaceInterfaceV0 *i);
void InitWindowInterface(ANPWindowInterfaceV0 *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;

Просмотреть файл

@ -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 <dougt@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "assert.h"
#include "ANPBase.h"
#include <android/log.h>
#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<unsigned char*>(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);
}

Просмотреть файл

@ -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 <dougt@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#include <assert.h>
#include <android/log.h>
#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);
}

Просмотреть файл

@ -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 <dougt@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "assert.h"
#include "ANPBase.h"
#include <android/log.h>
#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);
}

Просмотреть файл

@ -36,151 +36,256 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "assert.h" #include <dlfcn.h>
#include "ANPBase.h"
#include <android/log.h> #include <android/log.h>
#include "AndroidBridge.h" #include "ANPBase.h"
#include "gfxImageSurface.h"
#include "gfxContext.h"
#include "nsNPAPIPluginInstance.h"
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
#define ASSIGN(obj, name) (obj)->name = anp_surface_##name #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 // used to cache JNI method and field IDs for Surface Objects
static struct ANPSurfaceInterfaceJavaGlue { static struct ANPSurfaceInterfaceJavaGlue {
bool initialized; bool initialized;
jclass geckoAppShellClass; jmethodID getSurfaceHolder;
jclass surfaceInfoCls; jmethodID getSurface;
jmethodID getSurfaceInfo; jfieldID surfacePointer;
jfieldID jFormat;
jfieldID jWidth ;
jfieldID jHeight;
} gSurfaceJavaGlue; } gSurfaceJavaGlue;
#define getClassGlobalRef(env, cname) \ static struct ANPSurfaceFunctions {
(jClass = jclass(env->NewGlobalRef(env->FindClass(cname)))) bool initialized;
static void init(JNIEnv* env) { int (* lock)(void*, SurfaceInfo*, void*);
if (gSurfaceJavaGlue.initialized) int (* unlockAndPost)(void*);
return;
gSurfaceJavaGlue.geckoAppShellClass = mozilla::AndroidBridge::GetGeckoAppShellClass(); void* (* regionConstructor)(void*);
void (* setRegion)(void*, ARect const&);
} gSurfaceFunctions;
jmethodID getClass = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass,
"getSurfaceInfoClass",
"()Ljava/lang/Class;");
gSurfaceJavaGlue.surfaceInfoCls = (jclass) env->NewGlobalRef(env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, getClass)); static inline void* getSurface(JNIEnv* env, jobject view) {
if (!env || !view) {
return NULL;
}
gSurfaceJavaGlue.jFormat = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "format", "I"); if (!gSurfaceJavaGlue.initialized) {
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;"); jclass surfaceViewClass = env->FindClass("android/view/SurfaceView");
gSurfaceJavaGlue.initialized = true; 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) { static ANPBitmapFormat convertPixelFormat(int32_t format) {
LOG("%s", __PRETTY_FUNCTION__); 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) { if (!bitmap || !surfaceView) {
LOG("%s, null bitmap or surface, exiting", __PRETTY_FUNCTION__);
return false; return false;
} }
init(env); void* surface = getSurface(env, surfaceView);
jobject info = env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, if (!bitmap || !surface) {
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);
return false; return false;
} }
nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::FindByJavaSurface((void*)surfaceView); if (!init()) {
if (!pinst) {
LOG("Failed to get plugin instance");
return false; return false;
} }
NPRect lockRect; void* region = NULL;
if (dirtyRect) { if (dirtyRect) {
lockRect.top = dirtyRect->top; region = malloc(ANDROID_REGION_SIZE);
lockRect.left = dirtyRect->left; gSurfaceFunctions.regionConstructor(region);
lockRect.right = dirtyRect->right;
lockRect.bottom = dirtyRect->bottom; ARect rect;
} else { rect.left = dirtyRect->left;
// No dirty rect, use the whole bitmap rect.top = dirtyRect->top;
lockRect.top = lockRect.left = 0; rect.right = dirtyRect->right;
lockRect.right = bitmap->width; rect.bottom = dirtyRect->bottom;
lockRect.bottom = bitmap->height;
gSurfaceFunctions.setRegion(region, rect);
} }
gfxImageSurface* target = pinst->LockTargetSurface(bitmap->width, bitmap->height, targetFormat, &lockRect); SurfaceInfo info;
bitmap->baseAddr = target->Data(); int err = gSurfaceFunctions.lock(surface, &info, region);
if (err < 0) {
LOG("Failed to lock surface");
return false;
}
env->DeleteLocalRef(info); // 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; return true;
} }
static void anp_unlock(JNIEnv* env, jobject surfaceView) { static void anp_surface_unlock(JNIEnv* env, jobject surfaceView) {
LOG("%s", __PRETTY_FUNCTION__);
if (!surfaceView) { if (!surfaceView) {
LOG("null surface, exiting %s", __PRETTY_FUNCTION__);
return; return;
} }
nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::FindByJavaSurface((void*)surfaceView); if (!init()) {
if (!pinst) {
LOG("Could not find plugin instance!");
return; 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, lock);
ASSIGN(i, unlock); ASSIGN(i, unlock);
// setup the java glue struct // setup the java glue struct
gSurfaceJavaGlue.initialized = false; gSurfaceJavaGlue.initialized = false;
// setup the function struct
gSurfaceFunctions.initialized = false;
} }

Просмотреть файл

@ -52,8 +52,14 @@
const char* const char*
anp_system_getApplicationDataDirectory() anp_system_getApplicationDataDirectory()
{ {
LOG("getApplicationDataDirectory return /data/data/org.mozilla.%s", MOZ_APP_NAME); static char *dir = NULL;
return "/data/data/org.mozilla." MOZ_APP_NAME;
if (!dir) {
dir = getenv("ANDROID_PLUGIN_DATADIR");
}
LOG("getApplicationDataDirectory return %s", dir);
return dir;
} }
jclass anp_system_loadJavaClass(NPP instance, const char* className) jclass anp_system_loadJavaClass(NPP instance, const char* className)

Просмотреть файл

@ -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 <dougt@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "assert.h"
#include "ANPBase.h"
#include <android/log.h>
#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<gfxFont> 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);
}

Просмотреть файл

@ -57,21 +57,18 @@ EXPORTS = \
$(NULL) $(NULL)
CPPSRCS += ANPAudio.cpp \ CPPSRCS += ANPAudio.cpp \
ANPCanvas.cpp \
ANPEvent.cpp \ ANPEvent.cpp \
ANPMatrix.cpp \ ANPMatrix.cpp \
ANPPath.cpp \
ANPSystem.cpp \ ANPSystem.cpp \
ANPWindow.cpp \ ANPWindow.cpp \
ANPBitmap.cpp \ ANPBitmap.cpp \
ANPLog.cpp \ ANPLog.cpp \
ANPPaint.cpp \
ANPSurface.cpp \ ANPSurface.cpp \
ANPTypeface.cpp \
$(NULL) $(NULL)
LOCAL_INCLUDES += \ LOCAL_INCLUDES += \
-I$(topsrcdir)/dom/plugins/base \ -I$(topsrcdir)/dom/plugins/base \
-I$(topsrcdir)/dom/plugins/base/android/include \
$(MOZ_CAIRO_CFLAGS) \ $(MOZ_CAIRO_CFLAGS) \
$(NULL) $(NULL)

Просмотреть файл

@ -65,6 +65,7 @@
#include "ANPBase.h" #include "ANPBase.h"
#include <android/log.h> #include <android/log.h>
#include "android_npapi.h" #include "android_npapi.h"
#include "mozilla/Mutex.h"
#include "mozilla/CondVar.h" #include "mozilla/CondVar.h"
#include "AndroidBridge.h" #include "AndroidBridge.h"
#endif #endif
@ -72,11 +73,6 @@
using namespace mozilla; using namespace mozilla;
using namespace mozilla::plugins::parent; using namespace mozilla::plugins::parent;
#ifdef MOZ_WIDGET_ANDROID
#include <map>
static std::map<void*, nsNPAPIPluginInstance*> sSurfaceMap;
#endif
static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID); static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID); static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID);
@ -93,7 +89,6 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
#endif #endif
#ifdef MOZ_WIDGET_ANDROID #ifdef MOZ_WIDGET_ANDROID
mSurface(nsnull), mSurface(nsnull),
mTargetSurface(nsnull),
mDrawingModel(0), mDrawingModel(0),
#endif #endif
mRunning(NOT_STARTED), mRunning(NOT_STARTED),
@ -128,10 +123,6 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
mUsePluginLayersPref = useLayersPref; mUsePluginLayersPref = useLayersPref;
} }
#ifdef MOZ_WIDGET_ANDROID
mTargetSurfaceLock = new Mutex("nsNPAPIPluginInstance::SurfaceLock");
#endif
PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this)); PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
} }
@ -143,22 +134,6 @@ nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
PR_Free((void *)mMIMEType); PR_Free((void *)mMIMEType);
mMIMEType = nsnull; 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 void
@ -760,40 +735,25 @@ void nsNPAPIPluginInstance::SetDrawingModel(PRUint32 aModel)
{ {
mDrawingModel = aModel; mDrawingModel = aModel;
} }
class SurfaceGetter : public nsRunnable { class SurfaceGetter : public nsRunnable {
public: public:
SurfaceGetter(NPPluginFuncs* aPluginFunctions, NPP_t aNPP) : SurfaceGetter(nsNPAPIPluginInstance* aInstance, NPPluginFuncs* aPluginFunctions, NPP_t aNPP) :
mHaveSurface(false), mPluginFunctions(aPluginFunctions), mNPP(aNPP) { mInstance(aInstance), mPluginFunctions(aPluginFunctions), mNPP(aNPP) {
mLock = new Mutex("SurfaceGetter::Lock");
mCondVar = new CondVar(*mLock, "SurfaceGetter::CondVar");
} }
~SurfaceGetter() { ~SurfaceGetter() {
delete mLock;
delete mCondVar;
} }
nsresult Run() { nsresult Run() {
MutexAutoLock lock(*mLock); void* surface;
(*mPluginFunctions->getvalue)(&mNPP, kJavaSurface_ANPGetValue, &mSurface); (*mPluginFunctions->getvalue)(&mNPP, kJavaSurface_ANPGetValue, &surface);
mHaveSurface = true; mInstance->SetJavaSurface(surface);
mCondVar->Notify();
return NS_OK; return NS_OK;
} }
void* GetSurface() { void RequestSurface() {
MutexAutoLock lock(*mLock); mozilla::AndroidBridge::Bridge()->PostToJavaThread(this);
mHaveSurface = false;
AndroidBridge::Bridge()->PostToJavaThread(this);
while (!mHaveSurface)
mCondVar->Wait();
return mSurface;
} }
private: private:
nsNPAPIPluginInstance* mInstance;
NPP_t mNPP; NPP_t mNPP;
void* mSurface;
Mutex* mLock;
CondVar* mCondVar;
bool mHaveSurface;
NPPluginFuncs* mPluginFunctions; NPPluginFuncs* mPluginFunctions;
}; };
@ -803,64 +763,22 @@ void* nsNPAPIPluginInstance::GetJavaSurface()
if (mDrawingModel != kSurface_ANPDrawingModel) if (mDrawingModel != kSurface_ANPDrawingModel)
return nsnull; return nsnull;
if (mSurface)
return mSurface;
nsCOMPtr<SurfaceGetter> sg = new SurfaceGetter(mPlugin->PluginFuncs(), mNPP);
mSurface = sg->GetSurface();
sSurfaceMap[mSurface] = this;
return mSurface; return mSurface;
} }
gfxImageSurface* void nsNPAPIPluginInstance::SetJavaSurface(void* aSurface)
nsNPAPIPluginInstance::LockTargetSurface()
{ {
mTargetSurfaceLock->Lock(); mSurface = aSurface;
return mTargetSurface;
} }
gfxImageSurface* void nsNPAPIPluginInstance::RequestJavaSurface()
nsNPAPIPluginInstance::LockTargetSurface(PRUint32 aWidth, PRUint32 aHeight, gfxImageFormat aFormat,
NPRect* aRect)
{ {
mTargetSurfaceLock->Lock(); if (mSurfaceGetter.get())
if (!mTargetSurface || return;
mTargetSurface->Width() != aWidth ||
mTargetSurface->Height() != aHeight ||
mTargetSurface->Format() != aFormat) {
if (mTargetSurface) { mSurfaceGetter = new SurfaceGetter(this, mPlugin->PluginFuncs(), mNPP);
delete mTargetSurface;
}
mTargetSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight), aFormat); ((SurfaceGetter*)mSurfaceGetter.get())->RequestSurface();
}
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];
} }
#endif #endif

Просмотреть файл

@ -49,17 +49,13 @@
#include "nsIChannel.h" #include "nsIChannel.h"
#include "nsInterfaceHashtable.h" #include "nsInterfaceHashtable.h"
#include "nsHashKeys.h" #include "nsHashKeys.h"
#ifdef MOZ_WIDGET_ANDROID
#include "gfxASurface.h" #include "nsIRunnable.h"
#include "gfxImageSurface.h" #endif
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "mozilla/PluginLibrary.h" #include "mozilla/PluginLibrary.h"
#ifdef ANDROID
#include "mozilla/Mutex.h"
#endif
struct JSObject; struct JSObject;
class nsPluginStreamListenerPeer; // browser-initiated stream class class nsPluginStreamListenerPeer; // browser-initiated stream class
@ -156,13 +152,8 @@ public:
#ifdef MOZ_WIDGET_ANDROID #ifdef MOZ_WIDGET_ANDROID
void SetDrawingModel(PRUint32 aModel); void SetDrawingModel(PRUint32 aModel);
void* GetJavaSurface(); void* GetJavaSurface();
void SetJavaSurface(void* aSurface);
gfxImageSurface* LockTargetSurface(); void RequestJavaSurface();
gfxImageSurface* LockTargetSurface(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat,
NPRect* aRect);
void UnlockTargetSurface(bool aInvalidate);
static nsNPAPIPluginInstance* FindByJavaSurface(void* aJavaSurface);
#endif #endif
nsresult NewStreamListener(const char* aURL, void* notifyData, nsresult NewStreamListener(const char* aURL, void* notifyData,
@ -239,6 +230,7 @@ protected:
#ifdef MOZ_WIDGET_ANDROID #ifdef MOZ_WIDGET_ANDROID
PRUint32 mDrawingModel; PRUint32 mDrawingModel;
nsCOMPtr<nsIRunnable> mSurfaceGetter;
#endif #endif
enum { enum {
@ -290,12 +282,7 @@ private:
bool mUsePluginLayersPref; bool mUsePluginLayersPref;
#ifdef MOZ_WIDGET_ANDROID #ifdef MOZ_WIDGET_ANDROID
void InvalidateTargetRect();
void* mSurface; void* mSurface;
gfxImageSurface *mTargetSurface;
mozilla::Mutex* mTargetSurfaceLock;
NPRect mTargetLockRect;
#endif #endif
}; };

Просмотреть файл

@ -331,6 +331,11 @@ nsPluginInstanceOwner::nsPluginInstanceOwner()
#endif #endif
mWaitingForPaint = false; mWaitingForPaint = false;
#ifdef MOZ_WIDGET_ANDROID
mPluginViewAdded = false;
mLastPluginRect = gfxRect(0, 0, 0, 0);
#endif
} }
nsPluginInstanceOwner::~nsPluginInstanceOwner() nsPluginInstanceOwner::~nsPluginInstanceOwner()
@ -1673,18 +1678,27 @@ void nsPluginInstanceOwner::ScrollPositionDidChange(nscoord aX, nscoord aY)
} }
#ifdef MOZ_WIDGET_ANDROID #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) void* javaSurface = mInstance->GetJavaSurface();
return; if (!javaSurface) {
mInstance->RequestJavaSurface();
return false;
}
if (aRect.IsEqualEdges(mLastPluginRect)) {
// Already added and in position, no work to do
return true;
}
JNIEnv* env = GetJNIForThread(); JNIEnv* env = GetJNIForThread();
jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell"); jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
jmethodID method = env->GetStaticMethodID(cls, jmethodID method = env->GetStaticMethodID(cls,
"addPluginView", "addPluginView",
"(Landroid/view/View;DDDD)V"); "(Landroid/view/View;DDDD)V");
env->CallStaticVoidMethod(cls, env->CallStaticVoidMethod(cls,
method, method,
javaSurface, javaSurface,
@ -1692,11 +1706,27 @@ void nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect)
aRect.y, aRect.y,
aRect.width, aRect.width,
aRect.height); 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() void nsPluginInstanceOwner::RemovePluginView()
{ {
if (mInstance && mObjectFrame) { AndroidBridge::AutoLocalJNIFrame frame(1);
if (mInstance && mObjectFrame && mPluginViewAdded) {
mPluginViewAdded = false;
void* surface = mInstance->GetJavaSurface(); void* surface = mInstance->GetJavaSurface();
if (surface) { if (surface) {
JNIEnv* env = GetJNIForThread(); JNIEnv* env = GetJNIForThread();
@ -1706,6 +1736,14 @@ void nsPluginInstanceOwner::RemovePluginView()
"removePluginView", "removePluginView",
"(Landroid/view/View;)V"); "(Landroid/view/View;)V");
env->CallStaticVoidMethod(cls, method, surface); 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); mInstance->GetDrawingModel(&model);
if (model == kSurface_ANPDrawingModel) { if (model == kSurface_ANPDrawingModel) {
AddPluginView(aFrameRect); if (!AddPluginView(aFrameRect)) {
NPRect rect;
gfxImageSurface* pluginSurface = mInstance->LockTargetSurface(); rect.left = rect.top = 0;
if (!pluginSurface) { rect.right = aFrameRect.width;
mInstance->UnlockTargetSurface(false); rect.bottom = aFrameRect.height;
return; InvalidateRect(&rect);
} }
aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y));
aContext->Clip(aDirtyRect);
aContext->Paint();
mInstance->UnlockTargetSurface(false);
return; return;
} }
@ -3556,26 +3587,10 @@ void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow)
if (mPluginWindowVisible && mPluginDocumentActiveState) { if (mPluginWindowVisible && mPluginDocumentActiveState) {
mPluginWindow->clipRect.right = mPluginWindow->width; mPluginWindow->clipRect.right = mPluginWindow->width;
mPluginWindow->clipRect.bottom = mPluginWindow->height; 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 { } else {
mPluginWindow->clipRect.right = 0; mPluginWindow->clipRect.right = 0;
mPluginWindow->clipRect.bottom = 0; mPluginWindow->clipRect.bottom = 0;
#ifdef MOZ_WIDGET_ANDROID #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(); RemovePluginView();
#endif #endif
} }

Просмотреть файл

@ -310,8 +310,10 @@ private:
void FixUpURLS(const nsString &name, nsAString &value); void FixUpURLS(const nsString &name, nsAString &value);
#ifdef ANDROID #ifdef ANDROID
void AddPluginView(const gfxRect& aRect); bool AddPluginView(const gfxRect& aRect);
void RemovePluginView(); void RemovePluginView();
bool mPluginViewAdded;
gfxRect mLastPluginRect;
#endif #endif
nsPluginNativeWindow *mPluginWindow; nsPluginNativeWindow *mPluginWindow;

Просмотреть файл

@ -46,6 +46,10 @@ ifdef ENABLE_TESTS
DIRS += tests DIRS += tests
endif endif
ifdef MOZ_SPELLCHECK
DEFINES += -DMOZ_SPELLCHECK
endif
MODULE = editor MODULE = editor
LIBRARY_NAME = editorbase_s LIBRARY_NAME = editorbase_s
LIBXUL_LIBRARY = 1 LIBXUL_LIBRARY = 1

Просмотреть файл

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

Просмотреть файл

@ -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 <blassey@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#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<String, String> mExtrasStringMap;
boolean moveFile(File inFile, File outFile)
{
Log.i("GeckoCrashReporter", "moving " + inFile + " to " + outFile);
if (inFile.renameTo(outFile))
return true;
try {
outFile.createNewFile();
Log.i("GeckoCrashReporter", "couldn't rename minidump file");
// so copy it instead
FileChannel inChannel = new FileInputStream(inFile).getChannel();
FileChannel outChannel = new FileOutputStream(outFile).getChannel();
long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
outChannel.close();
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<String, String>();
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<String, String> extras,
File extrasFile)
{
Log.i("GeckoCrashReport", "sendReport: " + minidumpFile.getPath());
final CheckBox includeURLCheckbox = (CheckBox) findViewById(R.id.include_url);
String spec = extras.get("ServerURL");
if (spec == null)
doFinish();
Log.i("GeckoCrashReport", "server url: " + spec);
try {
URL url = new URL(spec);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
String boundary = generateBoundary();
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
OutputStream os = conn.getOutputStream();
Iterator<String> keys = extras.keySet().iterator();
while (keys.hasNext()) {
String key = keys.next();
if (key.equals(kPageURLKey)) {
if (includeURLCheckbox.isChecked())
sendPart(os, boundary, key, extras.get(key));
} else if (!key.equals("ServerURL") && !key.equals(kNotesKey)) {
sendPart(os, boundary, key, extras.get(key));
}
}
// Add some extra information to notes so its displayed by
// crash-stats.mozilla.org. Remove this when bug 607942 is fixed.
String notes = extras.containsKey(kNotesKey) ? extras.get(kNotesKey) +
"\n" : "";
if (@MOZ_MIN_CPU_VERSION@ < 7)
notes += "nothumb Build\n";
notes += Build.MANUFACTURER + " ";
notes += Build.MODEL + "\n";
notes += Build.FINGERPRINT;
sendPart(os, boundary, kNotesKey, notes);
sendPart(os, boundary, "Min_ARM_Version", "@MOZ_MIN_CPU_VERSION@");
sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER);
sendPart(os, boundary, "Android_Model", Build.MODEL);
sendPart(os, boundary, "Android_Board", Build.BOARD);
sendPart(os, boundary, "Android_Brand", Build.BRAND);
sendPart(os, boundary, "Android_Device", Build.DEVICE);
sendPart(os, boundary, "Android_Display", Build.DISPLAY);
sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT);
sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI);
if (Build.VERSION.SDK_INT >= 8) {
try {
sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2);
sendPart(os, boundary, "Android_Hardware", Build.HARDWARE);
} catch (Exception ex) {
Log.e("GeckoCrashReporter", "Exception while sending SDK version 8 keys", ex);
}
}
sendPart(os, boundary, "Android_Version", Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
sendFile(os, boundary, kMiniDumpPathKey, minidumpFile);
os.write(("\r\n--" + boundary + "--\r\n").getBytes());
os.flush();
os.close();
BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
HashMap<String, String> responseMap = new HashMap<String, String>();
readStringsFromReader(br, responseMap);
if (conn.getResponseCode() == conn.HTTP_OK) {
File submittedDir = new File(
"/data/data/@ANDROID_PACKAGE_NAME@/files/mozilla/Crash Reports/submitted");
submittedDir.mkdirs();
minidumpFile.delete();
extrasFile.delete();
String crashid = responseMap.get("CrashID");
File file = new File(submittedDir, crashid + ".txt");
FileOutputStream fos = new FileOutputStream(file);
fos.write("Crash ID: ".getBytes());
fos.write(crashid.getBytes());
fos.close();
}
} catch (IOException e) {
Log.e("GeckoCrashReporter", "exception during send: ", e);
}
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");
}
}

Просмотреть файл

@ -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 <vladimir@pobox.com>
* Matt Brubeck <mbrubeck@mozilla.com>
* Vivien Nicolas <vnicolas@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.io.*;
import 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<PackageInfo> mPackageInfoCache = new ArrayList<PackageInfo>();
String[] getPluginDirectories() {
ArrayList<String> directories = new ArrayList<String>();
PackageManager pm = this.mAppContext.getPackageManager();
List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
synchronized(mPackageInfoCache) {
// clear the list of existing packageInfo objects
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<? extends ZipEntry> zipEntries = zip.entries();
while (zipEntries.hasMoreElements()) {
ZipEntry entry = zipEntries.nextElement();
if (entry.getName().startsWith("extensions/") && entry.getName().endsWith(".xpi")) {
Log.i("GeckoAppJava", "installing extension : " + entry.getName());
unpackFile(zip, buf, entry, entry.getName());
}
}
}
void removeFiles() throws IOException {
BufferedReader reader = new BufferedReader(
new FileReader(new File(sGREDir, "removed-files")));
try {
for (String removedFileName = reader.readLine();
removedFileName != null; removedFileName = reader.readLine()) {
File removedFile = new File(sGREDir, removedFileName);
if (removedFile.exists())
removedFile.delete();
}
} finally {
reader.close();
}
}
private boolean unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry,
String name)
throws IOException, FileNotFoundException
{
if (fileEntry == null)
fileEntry = zip.getEntry(name);
if (fileEntry == null)
throw new FileNotFoundException("Can't find " + name + " in " +
zip.getName());
File outFile = new File(sGREDir, name);
if (outFile.lastModified() == fileEntry.getTime() &&
outFile.length() == fileEntry.getSize())
return false;
File dir = outFile.getParentFile();
if (!dir.exists())
dir.mkdirs();
InputStream fileStream;
fileStream = zip.getInputStream(fileEntry);
OutputStream outStream = new FileOutputStream(outFile);
while (fileStream.available() > 0) {
int read = fileStream.read(buf, 0, buf.length);
outStream.write(buf, 0, read);
}
fileStream.close();
outStream.close();
outFile.setLastModified(fileEntry.getTime());
return true;
}
public void addEnvToIntent(Intent intent) {
Map<String,String> envMap = System.getenv();
Set<Map.Entry<String,String>> envSet = envMap.entrySet();
Iterator<Map.Entry<String,String>> envIter = envSet.iterator();
StringBuffer envstr = new StringBuffer();
int c = 0;
while (envIter.hasNext()) {
Map.Entry<String,String> entry = envIter.next();
intent.putExtra("env" + c, entry.getKey() + "="
+ entry.getValue());
c++;
}
}
public void doRestart() {
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<String> 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);
}
}
}

Просмотреть файл

@ -1,833 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import java.util.concurrent.atomic.*;
import java.util.zip.*;
import java.nio.*;
import android.os.*;
import android.app.*;
import android.text.*;
import android.text.method.*;
import android.view.*;
import android.view.inputmethod.*;
import android.content.*;
import android.graphics.*;
import android.widget.*;
import android.hardware.*;
import android.location.*;
import android.graphics.drawable.*;
import android.content.res.*;
import android.util.*;
/*
* GeckoSurfaceView implements a GL surface view,
* similar to GLSurfaceView. However, since we
* already have a thread for Gecko, we don't really want
* a separate renderer thread that GLSurfaceView provides.
*/
class GeckoSurfaceView
extends SurfaceView
implements SurfaceHolder.Callback, SensorEventListener, LocationListener
{
private static final String LOG_FILE_NAME = "GeckoSurfaceView";
public GeckoSurfaceView(Context context) {
super(context);
getHolder().addCallback(this);
inputConnection = new GeckoInputConnection(this);
setFocusable(true);
setFocusableInTouchMode(true);
DisplayMetrics metrics = new DisplayMetrics();
GeckoApp.mAppContext.getWindowManager().
getDefaultDisplay().getMetrics(metrics);
mWidth = metrics.widthPixels;
mHeight = metrics.heightPixels;
mBufferWidth = 0;
mBufferHeight = 0;
mSurfaceLock = new ReentrantLock();
mEditableFactory = Editable.Factory.getInstance();
initEditable("");
mIMEState = IME_STATE_DISABLED;
mIMETypeHint = "";
mIMEActionHint = "";
}
protected void finalize() throws Throwable {
super.finalize();
}
void drawSplashScreen() {
this.drawSplashScreen(getHolder(), mWidth, mHeight);
}
void drawSplashScreen(SurfaceHolder holder, int width, int height) {
// No splash screen for Honeycomb or greater
if (Build.VERSION.SDK_INT >= 11) {
Log.i(LOG_FILE_NAME, "skipping splash screen");
return;
}
Canvas c = holder.lockCanvas();
if (c == null) {
Log.i(LOG_FILE_NAME, "canvas is null");
return;
}
Resources res = getResources();
File watchDir = new File(GeckoApp.sGREDir, "components");
if (watchDir.exists() == false) {
// Just show the simple splash screen for "new profile" startup
c.drawColor(res.getColor(R.color.splash_background));
Drawable drawable = res.getDrawable(R.drawable.splash);
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
int x = (width - w) / 2;
int y = (height - h) / 2 - 16;
drawable.setBounds(x, y, x + w, y + h);
drawable.draw(c);
Paint p = new Paint();
p.setTextAlign(Paint.Align.CENTER);
p.setTextSize(32f);
p.setAntiAlias(true);
p.setColor(res.getColor(R.color.splash_msgfont));
c.drawText(res.getString(R.string.splash_firstrun), width / 2, y + h + 16, p);
} else {
// Show the static UI for normal startup
DisplayMetrics metrics = new DisplayMetrics();
GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
// Default to DENSITY_HIGH sizes
int toolbarHeight = 80;
int faviconOffset = 25;
float urlHeight = 24f;
int urlOffsetX = 80;
int urlOffsetY = 48;
if (metrics.densityDpi == DisplayMetrics.DENSITY_MEDIUM) {
toolbarHeight = 53;
faviconOffset = 10;
urlHeight = 16f;
urlOffsetX = 53;
urlOffsetY = 32;
}
c.drawColor(res.getColor(R.color.splash_content));
Drawable toolbar = res.getDrawable(Build.VERSION.SDK_INT > 8 ?
R.drawable.splash_v9 :
R.drawable.splash_v8);
toolbar.setBounds(0, 0, width, toolbarHeight);
toolbar.draw(c);
// XUL/CSS always uses 32px width and height for favicon
Drawable favicon = res.getDrawable(R.drawable.favicon32);
favicon.setBounds(faviconOffset, faviconOffset, 32 + faviconOffset, 32 + faviconOffset);
favicon.draw(c);
if (GeckoSurfaceView.mSplashURL != "") {
TextPaint p = new TextPaint();
p.setTextAlign(Paint.Align.LEFT);
p.setTextSize(urlHeight);
p.setAntiAlias(true);
p.setColor(res.getColor(R.color.splash_urlfont));
String url = TextUtils.ellipsize(GeckoSurfaceView.mSplashURL, p, width - urlOffsetX * 2, TextUtils.TruncateAt.END).toString();
c.drawText(url, urlOffsetX, urlOffsetY, p);
}
}
holder.unlockCanvasAndPost(c);
}
/*
* Called on main thread
*/
public void draw(SurfaceHolder holder, ByteBuffer buffer) {
if (buffer == null || buffer.capacity() != (mWidth * mHeight * 2))
return;
synchronized (mSoftwareBuffer) {
if (buffer != mSoftwareBuffer || mSoftwareBufferCopy == null)
return;
Canvas c = holder.lockCanvas();
if (c == null)
return;
mSoftwareBufferCopy.copyPixelsFromBuffer(buffer);
c.drawBitmap(mSoftwareBufferCopy, 0, 0, null);
holder.unlockCanvasAndPost(c);
}
}
public void draw(SurfaceHolder holder, Bitmap bitmap) {
if (bitmap == null ||
bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight)
return;
synchronized (mSoftwareBitmap) {
if (bitmap != mSoftwareBitmap)
return;
Canvas c = holder.lockCanvas();
if (c == null)
return;
c.drawBitmap(bitmap, 0, 0, null);
holder.unlockCanvasAndPost(c);
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// On pre-Honeycomb, force exactly one frame of the previous size
// to render because the surface change is only seen by GLES after we
// have swapped the back buffer (i.e. the buffer size only changes
// after the next swap buffer). We need to make sure Gecko's view
// resizes when Android's buffer resizes.
// In Honeycomb, the buffer size changes immediately, so rendering a
// frame of the previous size is unnecessary (and wrong).
if (mDrawMode == DRAW_GLES_2 &&
(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)) {
// When we get a surfaceChange event, we have 0 to n paint events
// waiting in the Gecko event queue. We will make the first
// succeed and the abort the others.
mDrawSingleFrame = true;
if (!mInDrawing) {
// Queue at least one paint event in case none are queued.
GeckoAppShell.scheduleRedraw();
}
GeckoAppShell.geckoEventSync();
mDrawSingleFrame = false;
mAbortDraw = false;
}
if (mShowingSplashScreen)
drawSplashScreen(holder, width, height);
mSurfaceLock.lock();
if (mInDrawing) {
Log.w(LOG_FILE_NAME, "surfaceChanged while mInDrawing is true!");
}
boolean invalidSize;
if (width == 0 || height == 0) {
mSoftwareBitmap = null;
mSoftwareBuffer = null;
mSoftwareBufferCopy = null;
invalidSize = true;
} else {
invalidSize = false;
}
boolean doSyncDraw =
mDrawMode == DRAW_2D &&
!invalidSize &&
GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning);
mSyncDraw = doSyncDraw;
mFormat = format;
mWidth = width;
mHeight = height;
mSurfaceValid = true;
Log.i(LOG_FILE_NAME, "surfaceChanged: fmt: " + format + " dim: " + width + " " + height);
try {
DisplayMetrics metrics = new DisplayMetrics();
GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
GeckoEvent e = new GeckoEvent(GeckoEvent.SIZE_CHANGED, width, height,
metrics.widthPixels, metrics.heightPixels);
GeckoAppShell.sendEventToGecko(e);
} finally {
mSurfaceLock.unlock();
}
if (doSyncDraw) {
GeckoAppShell.scheduleRedraw();
Object syncDrawObject = null;
try {
syncDrawObject = mSyncDraws.take();
} catch (InterruptedException ie) {
Log.e(LOG_FILE_NAME, "Threw exception while getting sync draw bitmap/buffer: ", ie);
}
if (syncDrawObject != null) {
if (syncDrawObject instanceof Bitmap)
draw(holder, (Bitmap)syncDrawObject);
else
draw(holder, (ByteBuffer)syncDrawObject);
} else {
Log.e("GeckoSurfaceViewJava", "Synchronised draw object is null");
}
} else if (!mShowingSplashScreen) {
// Make sure a frame is drawn before we return
// otherwise we see artifacts or a black screen
GeckoAppShell.scheduleRedraw();
GeckoAppShell.geckoEventSync();
}
}
public void surfaceCreated(SurfaceHolder holder) {
Log.i(LOG_FILE_NAME, "surface created");
GeckoEvent e = new GeckoEvent(GeckoEvent.SURFACE_CREATED);
GeckoAppShell.sendEventToGecko(e);
if (mShowingSplashScreen)
drawSplashScreen();
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(LOG_FILE_NAME, "surface destroyed");
mSurfaceValid = false;
mSoftwareBuffer = null;
mSoftwareBufferCopy = null;
mSoftwareBitmap = null;
GeckoEvent e = new GeckoEvent(GeckoEvent.SURFACE_DESTROYED);
if (mDrawMode == DRAW_GLES_2) {
// Ensure GL cleanup occurs before we return.
GeckoAppShell.sendEventToGeckoSync(e);
} else {
GeckoAppShell.sendEventToGecko(e);
}
}
public Bitmap getSoftwareDrawBitmap() {
if (mSoftwareBitmap == null ||
mSoftwareBitmap.getHeight() != mHeight ||
mSoftwareBitmap.getWidth() != mWidth) {
mSoftwareBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565);
}
mDrawMode = DRAW_2D;
return mSoftwareBitmap;
}
public ByteBuffer getSoftwareDrawBuffer() {
// We store pixels in 565 format, so two bytes per pixel (explaining
// the * 2 in the following check/allocation)
if (mSoftwareBuffer == null ||
mSoftwareBuffer.capacity() != (mWidth * mHeight * 2)) {
mSoftwareBuffer = ByteBuffer.allocateDirect(mWidth * mHeight * 2);
}
if (mSoftwareBufferCopy == null ||
mSoftwareBufferCopy.getHeight() != mHeight ||
mSoftwareBufferCopy.getWidth() != mWidth) {
mSoftwareBufferCopy = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565);
}
mDrawMode = DRAW_2D;
return mSoftwareBuffer;
}
public Surface getSurface() {
return getHolder().getSurface();
}
/*
* Called on Gecko thread
*/
public static final int DRAW_ERROR = 0;
public static final int DRAW_GLES_2 = 1;
public static final int DRAW_2D = 2;
// Drawing is disable when the surface buffer
// has changed size but we haven't yet processed the
// resize event.
public static final int DRAW_DISABLED = 3;
public int beginDrawing() {
if (mInDrawing) {
Log.e(LOG_FILE_NAME, "Recursive beginDrawing call!");
return DRAW_ERROR;
}
// Once we drawn our first frame after resize we can ignore
// the other draw events until we handle the resize events.
if (mAbortDraw) {
return DRAW_DISABLED;
}
/* Grab the lock, which we'll hold while we're drawing.
* It gets released in endDrawing(), and is also used in surfaceChanged
* to make sure that we don't change our surface details while
* we're in the middle of drawing (and especially in the middle of
* executing beginDrawing/endDrawing).
*
* We might not need to hold this lock in between
* beginDrawing/endDrawing, and might just be able to make
* surfaceChanged, beginDrawing, and endDrawing synchronized,
* but this way is safer for now.
*/
mSurfaceLock.lock();
if (!mSurfaceValid) {
Log.e(LOG_FILE_NAME, "Surface not valid");
mSurfaceLock.unlock();
return DRAW_ERROR;
}
mInDrawing = true;
mDrawMode = DRAW_GLES_2;
return DRAW_GLES_2;
}
public void endDrawing() {
if (!mInDrawing) {
Log.e(LOG_FILE_NAME, "endDrawing without beginDrawing!");
return;
}
if (mDrawSingleFrame)
mAbortDraw = true;
try {
if (!mSurfaceValid) {
Log.e(LOG_FILE_NAME, "endDrawing with false mSurfaceValid");
return;
}
} finally {
mInDrawing = false;
if (!mSurfaceLock.isHeldByCurrentThread())
Log.e(LOG_FILE_NAME, "endDrawing while mSurfaceLock not held by current thread!");
mSurfaceLock.unlock();
}
}
/* How this works:
* Whenever we want to draw, we want to be sure that we do not lock
* the canvas unless we're sure we can draw. Locking the canvas clears
* the canvas to black in most cases, causing a black flash.
* At the same time, the surface can resize/disappear at any moment
* unless the canvas is locked.
* Draws originate from a different thread so the surface could change
* at any moment while we try to draw until we lock the canvas.
*
* Also, never try to lock the canvas while holding the surface lock
* unless you're in SurfaceChanged, in which case the canvas was already
* locked. Surface lock -> Canvas lock will lead to AB-BA deadlocks.
*/
public void draw2D(Bitmap bitmap, int width, int height) {
// mSurfaceLock ensures that we get mSyncDraw/mSoftwareBitmap/etc.
// set correctly before determining whether we should do a sync draw
mSurfaceLock.lock();
try {
if (mSyncDraw) {
if (bitmap != mSoftwareBitmap || width != mWidth || height != mHeight)
return;
mSyncDraw = false;
try {
mSyncDraws.put(bitmap);
} catch (InterruptedException ie) {
Log.e(LOG_FILE_NAME, "Threw exception while getting sync draws queue: ", ie);
}
return;
}
} finally {
mSurfaceLock.unlock();
}
draw(getHolder(), bitmap);
}
public void draw2D(ByteBuffer buffer, int stride) {
mSurfaceLock.lock();
try {
if (mSyncDraw) {
if (buffer != mSoftwareBuffer || stride != (mWidth * 2))
return;
mSyncDraw = false;
try {
mSyncDraws.put(buffer);
} catch (InterruptedException ie) {
Log.e(LOG_FILE_NAME, "Threw exception while getting sync bitmaps queue: ", ie);
}
return;
}
} finally {
mSurfaceLock.unlock();
}
draw(getHolder(), buffer);
}
@Override
public boolean onCheckIsTextEditor () {
return false;
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE;
outAttrs.actionLabel = null;
mKeyListener = TextKeyListener.getInstance();
if (mIMEState == IME_STATE_PASSWORD)
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
else if (mIMETypeHint.equalsIgnoreCase("url"))
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_URI;
else if (mIMETypeHint.equalsIgnoreCase("email"))
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
else if (mIMETypeHint.equalsIgnoreCase("search"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
else if (mIMETypeHint.equalsIgnoreCase("tel"))
outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
else if (mIMETypeHint.equalsIgnoreCase("number") ||
mIMETypeHint.equalsIgnoreCase("range"))
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER;
else if (mIMETypeHint.equalsIgnoreCase("datetime") ||
mIMETypeHint.equalsIgnoreCase("datetime-local"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_NORMAL;
else if (mIMETypeHint.equalsIgnoreCase("date"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_DATE;
else if (mIMETypeHint.equalsIgnoreCase("time"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_TIME;
if (mIMEActionHint.equalsIgnoreCase("go"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_GO;
else if (mIMEActionHint.equalsIgnoreCase("done"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE;
else if (mIMEActionHint.equalsIgnoreCase("next"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_NEXT;
else if (mIMEActionHint.equalsIgnoreCase("search"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_SEARCH;
else if (mIMEActionHint.equalsIgnoreCase("send"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_SEND;
else if (mIMEActionHint != null && mIMEActionHint.length() != 0)
outAttrs.actionLabel = mIMEActionHint;
if (mIMELandscapeFS == false)
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
inputConnection.reset();
return inputConnection;
}
public void setEditable(String contents)
{
mEditable.removeSpan(inputConnection);
mEditable.replace(0, mEditable.length(), contents);
mEditable.setSpan(inputConnection, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
Selection.setSelection(mEditable, contents.length());
}
public void initEditable(String contents)
{
mEditable = mEditableFactory.newEditable(contents);
mEditable.setSpan(inputConnection, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
Selection.setSelection(mEditable, contents.length());
}
// accelerometer
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
public void onSensorChanged(SensorEvent event)
{
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
}
private class GeocoderTask extends AsyncTask<Location, Void, Void> {
protected Void doInBackground(Location... location) {
try {
List<Address> addresses = mGeocoder.getFromLocation(location[0].getLatitude(),
location[0].getLongitude(), 1);
// grab the first address. in the future,
// may want to expose multiple, or filter
// for best.
mLastGeoAddress = addresses.get(0);
GeckoAppShell.sendEventToGecko(new GeckoEvent(location[0], mLastGeoAddress));
} catch (Exception e) {
Log.w(LOG_FILE_NAME, "GeocoderTask "+e);
}
return null;
}
}
// geolocation
public void onLocationChanged(Location location)
{
if (mGeocoder == null)
mGeocoder = new Geocoder(getContext(), Locale.getDefault());
if (mLastGeoAddress == null) {
new GeocoderTask().execute(location);
}
else {
float[] results = new float[1];
Location.distanceBetween(location.getLatitude(),
location.getLongitude(),
mLastGeoAddress.getLatitude(),
mLastGeoAddress.getLongitude(),
results);
// pfm value. don't want to slam the
// geocoder with very similar values, so
// only call after about 100m
if (results[0] > 100)
new GeocoderTask().execute(location);
}
GeckoAppShell.sendEventToGecko(new GeckoEvent(location, mLastGeoAddress));
}
public void onProviderDisabled(String provider)
{
}
public void onProviderEnabled(String provider)
{
}
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
// event stuff
public boolean onTouchEvent(MotionEvent event) {
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.isSystem())
return super.onKeyPreIme(keyCode, event);
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
return processKeyDown(keyCode, event, true);
case KeyEvent.ACTION_UP:
return processKeyUp(keyCode, event, true);
case KeyEvent.ACTION_MULTIPLE:
return onKeyMultiple(keyCode, event.getRepeatCount(), event);
}
return super.onKeyPreIme(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return processKeyDown(keyCode, event, false);
}
private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (event.getRepeatCount() == 0) {
event.startTracking();
return true;
} else {
return false;
}
case KeyEvent.KEYCODE_MENU:
if (event.getRepeatCount() == 0) {
event.startTracking();
break;
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
break;
}
// Ignore repeats for KEYCODE_MENU; they confuse the widget code.
return false;
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_SEARCH:
return false;
case KeyEvent.KEYCODE_DEL:
// See comments in GeckoInputConnection.onKeyDel
if (inputConnection != null &&
inputConnection.onKeyDel()) {
return true;
}
break;
case KeyEvent.KEYCODE_ENTER:
if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 &&
mIMEActionHint.equalsIgnoreCase("next"))
event = new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB);
break;
default:
break;
}
if (isPreIme && mIMEState != IME_STATE_DISABLED &&
(event.getMetaState() & KeyEvent.META_ALT_ON) == 0)
// Let active IME process pre-IME key events
return false;
// KeyListener returns true if it handled the event for us.
if (mIMEState == IME_STATE_DISABLED ||
keyCode == KeyEvent.KEYCODE_ENTER ||
keyCode == KeyEvent.KEYCODE_DEL ||
(event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 ||
!mKeyListener.onKeyDown(this, mEditable, keyCode, event))
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
return processKeyUp(keyCode, event, false);
}
private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (!event.isTracking() || event.isCanceled())
return false;
break;
default:
break;
}
if (isPreIme && mIMEState != IME_STATE_DISABLED &&
(event.getMetaState() & KeyEvent.META_ALT_ON) == 0)
// Let active IME process pre-IME key events
return false;
if (mIMEState == IME_STATE_DISABLED ||
keyCode == KeyEvent.KEYCODE_ENTER ||
keyCode == KeyEvent.KEYCODE_DEL ||
(event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 ||
!mKeyListener.onKeyUp(this, mEditable, keyCode, event))
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
case KeyEvent.KEYCODE_MENU:
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInputFromWindow(getWindowToken(),
imm.SHOW_FORCED, 0);
return true;
default:
break;
}
return false;
}
// Is this surface valid for drawing into?
boolean mSurfaceValid;
// Are we actively between beginDrawing/endDrawing?
boolean mInDrawing;
// Used to finish the current buffer before changing the surface size
boolean mDrawSingleFrame = false;
boolean mAbortDraw = false;
// Are we waiting for a buffer to draw in surfaceChanged?
boolean mSyncDraw;
// True if gecko requests a buffer
int mDrawMode;
static boolean mShowingSplashScreen = true;
static String mSplashURL = "";
// let's not change stuff around while we're in the middle of
// starting drawing, ending drawing, or changing surface
// characteristics
ReentrantLock mSurfaceLock;
// Surface format, from surfaceChanged. Largely
// useless.
int mFormat;
// the dimensions of the surface
int mWidth;
int mHeight;
// the dimensions of the buffer we're using for drawing,
// that is the software buffer or the EGLSurface
int mBufferWidth;
int mBufferHeight;
// IME stuff
public static final int IME_STATE_DISABLED = 0;
public static final int IME_STATE_ENABLED = 1;
public static final int IME_STATE_PASSWORD = 2;
public static final int IME_STATE_PLUGIN = 3;
GeckoInputConnection inputConnection;
KeyListener mKeyListener;
Editable mEditable;
Editable.Factory mEditableFactory;
int mIMEState;
String mIMETypeHint;
String mIMEActionHint;
boolean mIMELandscapeFS;
// Software rendering
Bitmap mSoftwareBitmap;
ByteBuffer mSoftwareBuffer;
Bitmap mSoftwareBufferCopy;
Geocoder mGeocoder;
Address mLastGeoAddress;
final SynchronousQueue<Object> mSyncDraws = new SynchronousQueue<Object>();
}

Просмотреть файл

@ -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 <vladimir@pobox.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
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)

Просмотреть файл

@ -1,7 +0,0 @@
package org.mozilla.gecko;
public class SurfaceInfo {
public int format;
public int width;
public int height;
}

Просмотреть файл

@ -1,21 +0,0 @@
<!ENTITY splash_firstrun "Setting up &brandShortName;\u2026">
<!ENTITY no_space_to_start_error "There is not enough space available for &brandShortName; to start.">
<!ENTITY error_loading_file "An error occurred when trying to load files required to run &brandShortName;">
<!ENTITY crash_reporter_title "&brandShortName; Crash Reporter">
<!ENTITY crash_message "&brandShortName; has crashed. Your tabs should be listed on the &brandShortName; Start page when you restart.">
<!ENTITY crash_help_message "Please help us fix this problem!">
<!ENTITY crash_send_report_message "Send Mozilla a crash report">
<!ENTITY crash_include_url "Include page address">
<!ENTITY crash_close_label "Close">
<!ENTITY crash_restart_label "Restart &brandShortName;">
<!ENTITY sending_crash_report "Sending crash report\u2026">
<!ENTITY exit_label "Exit">
<!ENTITY continue_label "Continue">
<!ENTITY launcher_shortcuts_title "&brandShortName; Web Apps">
<!ENTITY launcher_shortcuts_empty "No web apps were found">
<!ENTITY choose_file "Choose File">

Просмотреть файл

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="10px" >
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10px"
android:textStyle="bold"
android:text="@string/crash_message"/>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10px"
android:text="@string/crash_help_message"/>
<CheckBox android:id="@+id/send_report"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/crash_send_report_message" />
<CheckBox android:id="@+id/include_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/crash_include_url" />
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10px"
android:gravity="center_horizontal" >
<Button android:id="@+id/close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10px"
android:minWidth="120sp"
android:onClick="onCloseClick"
android:text="@string/crash_close_label" />
<Button android:id="@+id/restart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10px"
android:minWidth="120sp"
android:onClick="onRestartClick"
android:text="@string/crash_restart_label" />
</LinearLayout>
</LinearLayout>

Просмотреть файл

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="3dip"
android:orientation="vertical"
android:windowIsFloating="true">
</LinearLayout>

Просмотреть файл

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:orientation="horizontal"
android:gravity="left">
<ImageView
android:id="@+id/favicon"
android:layout_width="48dip"
android:layout_height="48dip"
android:layout_marginRight="12dip"
android:layout_gravity="center_vertical"
android:adjustViewBounds="true"
android:scaleType="fitCenter"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceLargeInverse"
android:ellipsize="marquee"
android:fadingEdge="horizontal"/>
</LinearLayout>

Просмотреть файл

@ -1,34 +0,0 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingLeft="5dp"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView android:id="@+id/notificationImage"
android:layout_width="25dp"
android:layout_height="25dp"
android:scaleType="fitCenter" />
<TextView android:id="@+id/notificationTitle"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:paddingLeft="4dp"
/>
</LinearLayout>
<TextView android:id="@+id/notificationText"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="4dp"
/>
</LinearLayout>

Просмотреть файл

@ -1,53 +0,0 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingTop="7dp"
android:paddingLeft="5dp"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView android:id="@+id/notificationImage"
android:layout_width="25dp"
android:layout_height="25dp"
android:scaleType="fitCenter" />
<TextView android:id="@+id/notificationTitle"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:paddingLeft="10dp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView android:id="@+id/notificationText"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="3dp"
/>
<ProgressBar android:id="@+id/notificationProgressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dip"
android:layout_marginBottom="1dip"
android:layout_marginLeft="4dip"
android:layout_marginRight="10dip"
android:layout_centerHorizontal="true" />
</LinearLayout>
</LinearLayout>

Просмотреть файл

@ -1,46 +0,0 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingLeft="5dp"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView android:id="@+id/notificationImage"
android:layout_width="25dp"
android:layout_height="25dp"
android:scaleType="fitCenter" />
<TextView android:id="@+id/notificationTitle"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:paddingLeft="4dp"
/>
</LinearLayout>
<ProgressBar android:id="@+id/notificationProgressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="16dip"
android:layout_marginTop="1dip"
android:layout_marginBottom="1dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:layout_centerHorizontal="true" />
<TextView android:id="@+id/notificationText"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="4dp"
/>
</LinearLayout>

Просмотреть файл

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="GreyTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">@color/splash_background</item>
</style>
</resources>

Просмотреть файл

@ -1,27 +0,0 @@
#filter substitution
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
#includesubst @BRANDPATH@
#includesubst @STRINGSPATH@
]>
<resources>
<string name="splash_firstrun">&splash_firstrun;</string>
<string name="no_space_to_start_error">&no_space_to_start_error;</string>
<string name="error_loading_file">&error_loading_file;</string>
<string name="crash_reporter_title">&crash_reporter_title;</string>
<string name="crash_message">&crash_message;</string>
<string name="crash_help_message">&crash_help_message;</string>
<string name="crash_send_report_message">&crash_send_report_message;</string>
<string name="crash_include_url">&crash_include_url;</string>
<string name="crash_close_label">&crash_close_label;</string>
<string name="crash_restart_label">&crash_restart_label;</string>
<string name="sending_crash_report">&sending_crash_report;</string>
<string name="exit_label">&exit_label;</string>
<string name="continue_label">&continue_label;</string>
<string name="launcher_shortcuts_title">&launcher_shortcuts_title;</string>
<string name="launcher_shortcuts_empty">&launcher_shortcuts_empty;</string>
<string name="choose_file">&choose_file;</string>
</resources>

Просмотреть файл

@ -7287,14 +7287,14 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
desiredSize.height == size.height), desiredSize.height == size.height),
"non-root frame's desired size changed during an " "non-root frame's desired size changed during an "
"incremental reflow"); "incremental reflow");
NS_ASSERTION(desiredSize.VisualOverflow().IsEqualInterior( NS_ASSERTION(target == rootFrame || desiredSize.VisualOverflow().IsEqualInterior(
nsRect(nsPoint(0, 0), nsRect(nsPoint(0, 0),
nsSize(desiredSize.width, desiredSize.height))), nsSize(desiredSize.width, desiredSize.height))),
"reflow roots must not have visible overflow"); "non-root reflow roots must not have visible overflow");
NS_ASSERTION(desiredSize.ScrollableOverflow().IsEqualEdges( NS_ASSERTION(target == rootFrame || desiredSize.ScrollableOverflow().IsEqualEdges(
nsRect(nsPoint(0, 0), nsRect(nsPoint(0, 0),
nsSize(desiredSize.width, desiredSize.height))), nsSize(desiredSize.width, desiredSize.height))),
"reflow roots must not have scrollable overflow"); "non-root reflow roots must not have scrollable overflow");
NS_ASSERTION(status == NS_FRAME_COMPLETE, NS_ASSERTION(status == NS_FRAME_COMPLETE,
"reflow roots should never split"); "reflow roots should never split");

Просмотреть файл

@ -62,6 +62,12 @@ _CHROME_FILES = \
test_default_background.xul \ test_default_background.xul \
default_background_window.xul \ default_background_window.xul \
test_leaf_layers_partition_browser_window.xul \ test_leaf_layers_partition_browser_window.xul \
test_no_clip_iframe.xul \
no_clip_iframe_window.xul \
no_clip_iframe_subdoc.html \
test_no_clip_iframe_2.xul \
no_clip_iframe_window_2.xul \
no_clip_iframe_subdoc_2.html \
test_printpreview.xul \ test_printpreview.xul \
printpreview_helper.xul \ printpreview_helper.xul \
test_printpreview_bug396024.xul \ test_printpreview_bug396024.xul \

Просмотреть файл

@ -0,0 +1,7 @@
<!DOCTYPE HTML>
<html>
<body style="margin:0; background:lime;">
<div id="d" style="position:relative; top:-50px; width:150px; height:250px; background:yellow;"></div>
<div id="p" style="margin-top:-50px; width:150px; height:50px;"></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1 @@
<html><body style="margin: 0"><div style="background-color: black; width: 1000px; height: 1000px;"></div></body></html>

Просмотреть файл

@ -0,0 +1,137 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="runTests()">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
<div id="container" xmlns="http://www.w3.org/1999/xhtml" style="height:400px; overflow:auto; background:gray">
<div style="height:0">
<iframe type="content" id="f" src="no_clip_iframe_subdoc.html"
style="margin-top:50px; border:1px solid black; width:100px; height:100px;"/>
</div>
<div id="ref" style="background:gray;">
<div style="border:1px solid black; margin-top:50px; width:100px; height:100px;">
<div id="ref-d" style="background:lime; height:250px; width:150px;">
<div style="position:relative; top:-50px; width:150px; height:100%; background:yellow;"/>
</div>
</div>
</div>
</div>
<vbox flex="1"/>
<script type="application/javascript">
<![CDATA[
var imports = [ "SimpleTest", "is", "isnot", "ok", "onerror" ];
for each (var name in imports) {
window[name] = window.opener.wrappedJSObject[name];
}
SimpleTest.waitForExplicitFinish();
var accumulatedRect = null;
var onpaint = function() {};
function paintListener(event) {
if (event.target != window)
return;
dump("got MozAfterPaint: " + event.boundingClientRect.left + "," + event.boundingClientRect.top + "," +
event.boundingClientRect.right + "," + event.boundingClientRect.bottom + "\n");
if (accumulatedRect) {
accumulatedRect[0] = Math.min(accumulatedRect[0], event.boundingClientRect.left);
accumulatedRect[1] = Math.min(accumulatedRect[1], event.boundingClientRect.top);
accumulatedRect[2] = Math.max(accumulatedRect[2], event.boundingClientRect.right);
accumulatedRect[3] = Math.max(accumulatedRect[3], event.boundingClientRect.bottom);
} else {
accumulatedRect = [event.boundingClientRect.left, event.boundingClientRect.top,
event.boundingClientRect.right, event.boundingClientRect.bottom];
}
onpaint();
}
window.addEventListener("MozAfterPaint", paintListener, false);
function waitForAllPaintsFlushed(callback) {
document.documentElement.getBoundingClientRect();
var CI = Components.interfaces;
var utils = window.QueryInterface(CI.nsIInterfaceRequestor)
.getInterface(CI.nsIDOMWindowUtils);
if (!utils.isMozAfterPaintPending) {
dump("done...\n");
var result = accumulatedRect;
accumulatedRect = null;
onpaint = function() {};
if (!result) {
result = [0,0,0,0];
}
callback(result[0], result[1], result[2], result[3]);
return;
}
dump("waiting for paint...\n");
onpaint = function() { waitForAllPaintsFlushed(callback); };
}
var Ci = Components.interfaces;
var frame = document.getElementById("f");
var fl = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
is(fl.clipSubdocument, true, "clipSubdocument should default to true");
fl.clipSubdocument = false;
is(fl.clipSubdocument, false, "clipSubdocument should have been set to false");
function runTests() {
var ref = document.getElementById("ref");
frame.contentWindow.scrollTo(0,0);
ref.style.visibility = "hidden";
var testCanvas = snapshotWindow(window);
ref.style.visibility = "";
var refCanvas = snapshotWindow(window);
var comparison = compareSnapshots(testCanvas, refCanvas, true);
ok(comparison[0], "Basic overflow drawing; got " + comparison[1] + ", expected " + comparison[2]);
document.getElementById("container").style.height = "200px";
ref.style.visibility = "hidden";
testCanvas = snapshotWindow(window);
ref.style.visibility = "";
refCanvas = snapshotWindow(window);
comparison = compareSnapshots(testCanvas, refCanvas, true);
ok(comparison[0], "Drawing with vertical scrollbar to show overflow area computation; got " +
comparison[1] + ", expected " + comparison[2]);
frame.contentDocument.getElementById("d").style.height = "350px";
document.getElementById("ref-d").style.height = "350px";
ref.style.visibility = "hidden";
testCanvas = snapshotWindow(window);
ref.style.visibility = "";
refCanvas = snapshotWindow(window);
comparison = compareSnapshots(testCanvas, refCanvas, true);
ok(comparison[0], "testing dynamic overflow area change affecting scrollbar; got " +
comparison[1] + ", expected " + comparison[2]);
// Now do invalidation tests
ref.style.visibility = "hidden";
document.getElementById("container").style.height = "400px";
waitForAllPaintsFlushed(function() {
dump("Scrolling\n");
frame.contentWindow.scrollTo(0,80);
waitForAllPaintsFlushed(function(x1, y1, x2, y2) {
ok(x1 <= 1 && x2 >= 151 && y1 <= 0 && y2 >= 400,
"Entire scrolled region is painted: " + x1 + "," + y1 + "," + x2 + "," + y2);
frame.contentDocument.getElementById("p").style.background = "cyan";
waitForAllPaintsFlushed(function(x1, y1, x2, y2) {
ok(x1 <= 1 && x2 >= 151 && y1 <= 271 && y2 >= 320,
"Entire updated region is painted: " + x1 + "," + y1 + "," + x2 + "," + y2);
var tester = window.SimpleTest;
window.close();
tester.finish();
});
});
});
}
]]>
</script>
</window>

Просмотреть файл

@ -0,0 +1,21 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
minWidth="800" width="800" minHeight="600" height="600"
onload="onload();" title="Test 2">
<script type="application/javascript">
let Ci = Components.interfaces;
function onload() {
let frame = document.getElementById("frame");
let fl = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
fl.clipSubdocument = false;
}
</script>
<div id="container" xmlns="http://www.w3.org/1999/xhtml" style="width: 800px; height:600px; overflow:auto; background:red">
<iframe style="width:100px; height: 100px;" src="no_clip_iframe_subdoc_2.html" id="frame"/>
</div>
</window>

Просмотреть файл

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
// Run the test in a separate window so that the test runs as a chrome
// window
window.open("no_clip_iframe_window.xul", "no_clip_iframe",
"chrome,width=200,height=400");
]]>
</script>
</window>

Просмотреть файл

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
// Run the test in a separate window so that the test runs as a chrome
// window
window.open("no_clip_iframe_window_2.xul", "no_clip_iframe",
"chrome,width=200,height=400,resizable");
]]>
</script>
</window>

Просмотреть файл

@ -6439,13 +6439,17 @@ nsFrame::CreateAccessible()
NS_DECLARE_FRAME_PROPERTY(OverflowAreasProperty, NS_DECLARE_FRAME_PROPERTY(OverflowAreasProperty,
nsIFrame::DestroyOverflowAreas) nsIFrame::DestroyOverflowAreas)
void bool
nsIFrame::ClearOverflowRects() nsIFrame::ClearOverflowRects()
{ {
if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
return false;
}
if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) { if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
Properties().Delete(OverflowAreasProperty()); Properties().Delete(OverflowAreasProperty());
} }
mOverflow.mType = NS_FRAME_OVERFLOW_NONE; mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
return true;
} }
/** Create or retrieve the previously stored overflow area, if the frame does /** Create or retrieve the previously stored overflow area, if the frame does
@ -6473,17 +6477,18 @@ nsIFrame::GetOverflowAreasProperty()
/** Set the overflowArea rect, storing it as deltas or a separate rect /** Set the overflowArea rect, storing it as deltas or a separate rect
* depending on its size in relation to the primary frame rect. * depending on its size in relation to the primary frame rect.
*/ */
void bool
nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas) nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
{ {
if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) { if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
nsOverflowAreas *overflow = nsOverflowAreas *overflow =
static_cast<nsOverflowAreas*>(Properties().Get(OverflowAreasProperty())); static_cast<nsOverflowAreas*>(Properties().Get(OverflowAreasProperty()));
bool changed = *overflow != aOverflowAreas;
*overflow = aOverflowAreas; *overflow = aOverflowAreas;
// Don't bother with converting to the deltas form if we already // Don't bother with converting to the deltas form if we already
// have a property. // have a property.
return; return changed;
} }
const nsRect& vis = aOverflowAreas.VisualOverflow(); const nsRect& vis = aOverflowAreas.VisualOverflow();
@ -6505,6 +6510,7 @@ nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
// so that our eventual SetRect/SetSize will know that it has to // so that our eventual SetRect/SetSize will know that it has to
// reset our overflow areas. // reset our overflow areas.
(l | t | r | b) != 0) { (l | t | r | b) != 0) {
VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
// It's a "small" overflow area so we store the deltas for each edge // It's a "small" overflow area so we store the deltas for each edge
// directly in the frame, rather than allocating a separate rect. // directly in the frame, rather than allocating a separate rect.
// If they're all zero, that's fine; we're setting things to // If they're all zero, that's fine; we're setting things to
@ -6513,12 +6519,18 @@ nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
mOverflow.mVisualDeltas.mTop = t; mOverflow.mVisualDeltas.mTop = t;
mOverflow.mVisualDeltas.mRight = r; mOverflow.mVisualDeltas.mRight = r;
mOverflow.mVisualDeltas.mBottom = b; mOverflow.mVisualDeltas.mBottom = b;
// There was no scrollable overflow before, and there isn't now.
return oldDeltas != mOverflow.mVisualDeltas;
} else { } else {
bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
!aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
// it's a large overflow area that we need to store as a property // it's a large overflow area that we need to store as a property
mOverflow.mType = NS_FRAME_OVERFLOW_LARGE; mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
nsOverflowAreas* overflow = GetOverflowAreasProperty(); nsOverflowAreas* overflow = GetOverflowAreasProperty();
NS_ASSERTION(overflow, "should have created areas"); NS_ASSERTION(overflow, "should have created areas");
*overflow = aOverflowAreas; *overflow = aOverflowAreas;
return changed;
} }
} }
@ -6529,7 +6541,7 @@ IsInlineFrame(nsIFrame *aFrame)
return type == nsGkAtoms::inlineFrame; return type == nsGkAtoms::inlineFrame;
} }
void bool
nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
nsSize aNewSize) nsSize aNewSize)
{ {
@ -6638,11 +6650,11 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
bool visualOverflowChanged = bool visualOverflowChanged =
!GetVisualOverflowRect().IsEqualInterior(aOverflowAreas.VisualOverflow()); !GetVisualOverflowRect().IsEqualInterior(aOverflowAreas.VisualOverflow());
bool anyOverflowChanged;
if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) { if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
SetOverflowAreas(aOverflowAreas); anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
} else { } else {
ClearOverflowRects(); anyOverflowChanged = ClearOverflowRects();
} }
if (visualOverflowChanged) { if (visualOverflowChanged) {
@ -6687,6 +6699,8 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
nsDisplayItem::TYPE_TRANSFORM); nsDisplayItem::TYPE_TRANSFORM);
} }
} }
return anyOverflowChanged;
} }
/* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on /* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on

Просмотреть файл

@ -82,6 +82,7 @@
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "FrameLayerBuilder.h" #include "FrameLayerBuilder.h"
#include "nsSMILKeySpline.h" #include "nsSMILKeySpline.h"
#include "nsSubDocumentFrame.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
@ -196,16 +197,20 @@ nsHTMLScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
nsRect damage = aDamageRect + nsPoint(aX, aY); nsRect damage = aDamageRect + nsPoint(aX, aY);
// This is the damage rect that we're going to pass up to our parent. // This is the damage rect that we're going to pass up to our parent.
nsRect parentDamage; nsRect parentDamage;
// If we're using a displayport, we might be displaying an area if (mInner.IsIgnoringViewportClipping()) {
// different than our scroll port and the damage needs to be parentDamage = damage;
// clipped to that instead.
nsRect displayport;
bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
&displayport);
if (usingDisplayport) {
parentDamage.IntersectRect(damage, displayport);
} else { } else {
parentDamage.IntersectRect(damage, mInner.mScrollPort); // If we're using a displayport, we might be displaying an area
// different than our scroll port and the damage needs to be
// clipped to that instead.
nsRect displayport;
bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
&displayport);
if (usingDisplayport) {
parentDamage.IntersectRect(damage, displayport);
} else {
parentDamage.IntersectRect(damage, mInner.mScrollPort);
}
} }
if (IsScrollingActive()) { if (IsScrollingActive()) {
@ -283,7 +288,7 @@ struct ScrollReflowState {
nsMargin mComputedBorder; nsMargin mComputedBorder;
// === Filled in by ReflowScrolledFrame === // === Filled in by ReflowScrolledFrame ===
nsRect mContentsOverflowArea; nsOverflowAreas mContentsOverflowAreas;
bool mReflowedContentsWithHScrollbar; bool mReflowedContentsWithHScrollbar;
bool mReflowedContentsWithVScrollbar; bool mReflowedContentsWithVScrollbar;
@ -427,7 +432,8 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowState* aState,
if (!aForce) { if (!aForce) {
nsRect scrolledRect = nsRect scrolledRect =
mInner.GetScrolledRectInternal(aState->mContentsOverflowArea, scrollPortSize); mInner.GetScrolledRectInternal(aState->mContentsOverflowAreas.ScrollableOverflow(),
scrollPortSize);
nscoord oneDevPixel = aState->mBoxState.PresContext()->DevPixelsToAppUnits(1); nscoord oneDevPixel = aState->mBoxState.PresContext()->DevPixelsToAppUnits(1);
// If the style is HIDDEN then we already know that aAssumeHScroll is false // If the style is HIDDEN then we already know that aAssumeHScroll is false
@ -566,7 +572,7 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
// overflow area doesn't include the frame bounds. // overflow area doesn't include the frame bounds.
aMetrics->UnionOverflowAreasWithDesiredBounds(); aMetrics->UnionOverflowAreasWithDesiredBounds();
aState->mContentsOverflowArea = aMetrics->ScrollableOverflow(); aState->mContentsOverflowAreas = aMetrics->mOverflowAreas;
aState->mReflowedContentsWithHScrollbar = aAssumeHScroll; aState->mReflowedContentsWithHScrollbar = aAssumeHScroll;
aState->mReflowedContentsWithVScrollbar = aAssumeVScroll; aState->mReflowedContentsWithVScrollbar = aAssumeVScroll;
@ -718,7 +724,9 @@ nsHTMLScrollFrame::PlaceScrollArea(const ScrollReflowState& aState,
nsRect scrolledArea; nsRect scrolledArea;
// Preserve the width or height of empty rects // Preserve the width or height of empty rects
nsSize portSize = mInner.mScrollPort.Size(); nsSize portSize = mInner.mScrollPort.Size();
nsRect scrolledRect = mInner.GetScrolledRectInternal(aState.mContentsOverflowArea, portSize); nsRect scrolledRect =
mInner.GetScrolledRectInternal(aState.mContentsOverflowAreas.ScrollableOverflow(),
portSize);
scrolledArea.UnionRectEdges(scrolledRect, scrolledArea.UnionRectEdges(scrolledRect,
nsRect(nsPoint(0,0), portSize)); nsRect(nsPoint(0,0), portSize));
@ -925,6 +933,10 @@ nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext,
state.mComputedBorder.TopBottom(); state.mComputedBorder.TopBottom();
aDesiredSize.SetOverflowAreasToDesiredBounds(); aDesiredSize.SetOverflowAreasToDesiredBounds();
if (mInner.IsIgnoringViewportClipping()) {
aDesiredSize.mOverflowAreas.UnionWith(
state.mContentsOverflowAreas + mInner.mScrolledFrame->GetPosition());
}
CheckInvalidateSizeChange(aDesiredSize); CheckInvalidateSizeChange(aDesiredSize);
@ -1687,6 +1699,15 @@ InvalidateFixedBackgroundFrames(nsIFrame* aRootFrame,
list.DeleteAll(); list.DeleteAll();
} }
bool nsGfxScrollFrameInner::IsIgnoringViewportClipping() const
{
if (!mIsRoot)
return false;
nsSubDocumentFrame* subdocFrame = static_cast<nsSubDocumentFrame*>
(nsLayoutUtils::GetCrossDocParentFrame(mOuter->PresContext()->PresShell()->GetRootFrame()));
return subdocFrame && !subdocFrame->ShouldClipSubdocument();
}
bool nsGfxScrollFrameInner::IsAlwaysActive() const bool nsGfxScrollFrameInner::IsAlwaysActive() const
{ {
// The root scrollframe for a non-chrome document which is the direct // The root scrollframe for a non-chrome document which is the direct
@ -1721,7 +1742,7 @@ void nsGfxScrollFrameInner::MarkActive()
} }
} }
void nsGfxScrollFrameInner::ScrollVisual() void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos)
{ {
nsRootPresContext* rootPresContext = mOuter->PresContext()->GetRootPresContext(); nsRootPresContext* rootPresContext = mOuter->PresContext()->GetRootPresContext();
if (!rootPresContext) { if (!rootPresContext) {
@ -1748,9 +1769,15 @@ void nsGfxScrollFrameInner::ScrollVisual()
} }
nsRect invalidateRect, displayport; nsRect invalidateRect, displayport;
invalidateRect = if (IsIgnoringViewportClipping()) {
(nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayport)) ? nsRect visualOverflow = mScrolledFrame->GetVisualOverflowRect();
displayport : mScrollPort; invalidateRect.UnionRect(visualOverflow + mScrolledFrame->GetPosition(),
visualOverflow + aOldScrolledFramePos);
} else {
invalidateRect =
(nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayport)) ?
displayport : mScrollPort;
}
mOuter->InvalidateWithFlags(invalidateRect, flags); mOuter->InvalidateWithFlags(invalidateRect, flags);
@ -1821,11 +1848,12 @@ nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt)
mListeners[i]->ScrollPositionWillChange(pt.x, pt.y); mListeners[i]->ScrollPositionWillChange(pt.x, pt.y);
} }
nsPoint oldScrollFramePos = mScrolledFrame->GetPosition();
// Update frame position for scrolling // Update frame position for scrolling
mScrolledFrame->SetPosition(mScrollPort.TopLeft() - pt); mScrolledFrame->SetPosition(mScrollPort.TopLeft() - pt);
// We pass in the amount to move visually // We pass in the amount to move visually
ScrollVisual(); ScrollVisual(oldScrollFramePos);
presContext->PresShell()->SynthesizeMouseMove(true); presContext->PresShell()->SynthesizeMouseMove(true);
UpdateScrollbarPosition(); UpdateScrollbarPosition();
@ -1937,7 +1965,7 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
} }
} }
if (aBuilder->GetIgnoreScrollFrame() == mOuter) { if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) {
// Don't clip the scrolled child, and don't paint scrollbars/scrollcorner. // Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
// The scrolled frame shouldn't have its own background/border, so we // The scrolled frame shouldn't have its own background/border, so we
// can just pass aLists directly. // can just pass aLists directly.

Просмотреть файл

@ -182,7 +182,7 @@ public:
static void AsyncScrollCallback(nsITimer *aTimer, void* anInstance); static void AsyncScrollCallback(nsITimer *aTimer, void* anInstance);
void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode); void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode);
void ScrollToImpl(nsPoint aScrollPosition); void ScrollToImpl(nsPoint aScrollPosition);
void ScrollVisual(); void ScrollVisual(nsPoint aOldScrolledFramePosition);
void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit, void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit,
nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow); nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow);
void ScrollToRestoredPosition(); void ScrollToRestoredPosition();
@ -256,6 +256,8 @@ public:
const nsRect& aContentArea, const nsRect& aContentArea,
const nsRect& aOldScrollArea); const nsRect& aOldScrollArea);
bool IsIgnoringViewportClipping() const;
bool IsAlwaysActive() const; bool IsAlwaysActive() const;
void MarkActive(); void MarkActive();
void MarkInactive(); void MarkInactive();

Просмотреть файл

@ -2274,14 +2274,15 @@ public:
/** /**
* Store the overflow area in the frame's mOverflow.mVisualDeltas * Store the overflow area in the frame's mOverflow.mVisualDeltas
* fields or as a frame property in the frame manager so that it can * fields or as a frame property in the frame manager so that it can
* be retrieved later without reflowing the frame. * be retrieved later without reflowing the frame. Returns true if either of
* the overflow areas changed.
*/ */
void FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, bool FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
nsSize aNewSize); nsSize aNewSize);
void FinishAndStoreOverflow(nsHTMLReflowMetrics* aMetrics) { bool FinishAndStoreOverflow(nsHTMLReflowMetrics* aMetrics) {
FinishAndStoreOverflow(aMetrics->mOverflowAreas, return FinishAndStoreOverflow(aMetrics->mOverflowAreas,
nsSize(aMetrics->width, aMetrics->height)); nsSize(aMetrics->width, aMetrics->height));
} }
/** /**
@ -2294,8 +2295,9 @@ public:
/** /**
* Removes any stored overflow rects (visual and scrollable) from the frame. * Removes any stored overflow rects (visual and scrollable) from the frame.
* Returns true if the overflow changed.
*/ */
void ClearOverflowRects(); bool ClearOverflowRects();
/** /**
* Determine whether borders should not be painted on certain sides of the * Determine whether borders should not be painted on certain sides of the
@ -2822,14 +2824,24 @@ protected:
// If mOverflow.mType == NS_FRAME_OVERFLOW_LARGE, then the // If mOverflow.mType == NS_FRAME_OVERFLOW_LARGE, then the
// delta values are not meaningful and the overflow area is stored // delta values are not meaningful and the overflow area is stored
// as a separate rect property. // as a separate rect property.
struct VisualDeltas {
PRUint8 mLeft;
PRUint8 mTop;
PRUint8 mRight;
PRUint8 mBottom;
bool operator==(const VisualDeltas& aOther) const
{
return mLeft == aOther.mLeft && mTop == aOther.mTop &&
mRight == aOther.mRight && mBottom == aOther.mBottom;
}
bool operator!=(const VisualDeltas& aOther) const
{
return !(*this == aOther);
}
};
union { union {
PRUint32 mType; PRUint32 mType;
struct { VisualDeltas mVisualDeltas;
PRUint8 mLeft;
PRUint8 mTop;
PRUint8 mRight;
PRUint8 mBottom;
} mVisualDeltas;
} mOverflow; } mOverflow;
// Helpers // Helpers
@ -2944,7 +2956,10 @@ private:
mRect.height + mOverflow.mVisualDeltas.mBottom + mRect.height + mOverflow.mVisualDeltas.mBottom +
mOverflow.mVisualDeltas.mTop); mOverflow.mVisualDeltas.mTop);
} }
void SetOverflowAreas(const nsOverflowAreas& aOverflowAreas); /**
* Returns true if any overflow changed.
*/
bool SetOverflowAreas(const nsOverflowAreas& aOverflowAreas);
nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther, const PRInt32 aAPD) const; nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther, const PRInt32 aAPD) const;
#ifdef NS_DEBUG #ifdef NS_DEBUG

Просмотреть файл

@ -411,18 +411,21 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
childItems.AppendToTop(layerItem); childItems.AppendToTop(layerItem);
} }
nsDisplayList list; if (ShouldClipSubdocument()) {
// Clip children to the child root frame's rectangle nsDisplayClip* item =
rv = list.AppendNewToTop(
new (aBuilder) nsDisplayClip(aBuilder, this, &childItems, new (aBuilder) nsDisplayClip(aBuilder, this, &childItems,
subdocBoundsInParentUnits)); subdocBoundsInParentUnits);
// Clip children to the child root frame's rectangle
childItems.AppendToTop(item);
}
if (mIsInline) { if (mIsInline) {
WrapReplacedContentForBorderRadius(aBuilder, &list, aLists); WrapReplacedContentForBorderRadius(aBuilder, &childItems, aLists);
} else { } else {
aLists.Content()->AppendToTop(&list); aLists.Content()->AppendToTop(&childItems);
} }
} }
// delete childItems in case of OOM // delete childItems in case of OOM
childItems.DeleteAll(); childItems.DeleteAll();
@ -617,6 +620,14 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), true); vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), true);
} }
aDesiredSize.SetOverflowAreasToDesiredBounds();
if (!ShouldClipSubdocument()) {
nsIFrame* subdocRootFrame = GetSubdocumentRootFrame();
if (subdocRootFrame) {
aDesiredSize.mOverflowAreas.UnionWith(subdocRootFrame->GetOverflowAreas() + offset);
}
}
// Determine if we need to repaint our border, background or outline // Determine if we need to repaint our border, background or outline
CheckInvalidateSizeChange(aDesiredSize); CheckInvalidateSizeChange(aDesiredSize);

Просмотреть файл

@ -124,6 +124,12 @@ public:
virtual bool ReflowFinished(); virtual bool ReflowFinished();
virtual void ReflowCallbackCanceled(); virtual void ReflowCallbackCanceled();
bool ShouldClipSubdocument()
{
nsFrameLoader* frameLoader = FrameLoader();
return !frameLoader || frameLoader->ShouldClipSubdocument();
}
protected: protected:
friend class AsyncFrameInit; friend class AsyncFrameInit;

Просмотреть файл

@ -47,6 +47,7 @@
#include "nsIScrollableFrame.h" #include "nsIScrollableFrame.h"
#include "nsDisplayList.h" #include "nsDisplayList.h"
#include "FrameLayerBuilder.h" #include "FrameLayerBuilder.h"
#include "nsSubDocumentFrame.h"
#include "nsAbsoluteContainingBlock.h" #include "nsAbsoluteContainingBlock.h"
using namespace mozilla; using namespace mozilla;
@ -210,6 +211,8 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
nsresult rv = NS_OK; nsresult rv = NS_OK;
aDesiredSize.SetOverflowAreasToDesiredBounds();
if (mFrames.NotEmpty()) { if (mFrames.NotEmpty()) {
// Deal with a non-incremental reflow or an incremental reflow // Deal with a non-incremental reflow or an incremental reflow
// targeted at our one-and-only principal child frame. // targeted at our one-and-only principal child frame.
@ -234,6 +237,7 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
} else { } else {
kidHeight = mFrames.FirstChild()->GetSize().height; kidHeight = mFrames.FirstChild()->GetSize().height;
} }
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mFrames.FirstChild());
} }
NS_ASSERTION(aReflowState.availableWidth != NS_UNCONSTRAINEDSIZE, NS_ASSERTION(aReflowState.availableWidth != NS_UNCONSTRAINEDSIZE,
@ -252,22 +256,18 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowState reflowState(aReflowState); nsHTMLReflowState reflowState(aReflowState);
nsPoint offset = AdjustReflowStateForScrollbars(&reflowState); nsPoint offset = AdjustReflowStateForScrollbars(&reflowState);
#ifdef DEBUG
if (IsAbsoluteContainer()) { if (IsAbsoluteContainer()) {
NS_ASSERTION(GetAbsoluteContainingBlock()->GetChildList().IsEmpty() || NS_ASSERTION(GetAbsoluteContainingBlock()->GetChildList().IsEmpty() ||
(offset.x == 0 && offset.y == 0), (offset.x == 0 && offset.y == 0),
"We don't handle correct positioning of fixed frames with " "We don't handle correct positioning of fixed frames with "
"scrollbars in odd positions"); "scrollbars in odd positions");
}
#endif
if (IsAbsoluteContainer()) {
// Just reflow all the fixed-pos frames. // Just reflow all the fixed-pos frames.
rv = GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus, rv = GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus,
reflowState.ComputedWidth(), reflowState.ComputedWidth(),
reflowState.ComputedHeight(), reflowState.ComputedHeight(),
false, true, true, // XXX could be optimized false, true, true, // XXX could be optimized
nsnull /* ignore overflow */); &aDesiredSize.mOverflowAreas);
} }
// If we were dirty then do a repaint // If we were dirty then do a repaint
@ -276,8 +276,19 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
Invalidate(damageRect); Invalidate(damageRect);
} }
// XXX Should we do something to clip our children to this? // Clipping is handled by the document container (e.g., nsSubDocumentFrame),
aDesiredSize.SetOverflowAreasToDesiredBounds(); // so we don't need to change our overflow areas.
bool overflowChanged = FinishAndStoreOverflow(&aDesiredSize);
if (overflowChanged) {
// We may need to alert our container to get it to pick up the
// overflow change.
nsSubDocumentFrame* container = static_cast<nsSubDocumentFrame*>
(nsLayoutUtils::GetCrossDocParentFrame(this));
if (container && !container->ShouldClipSubdocument()) {
container->PresContext()->PresShell()->
FrameNeedsReflow(container, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
}
}
NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus); NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus);
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);

1333
mobile/android/LICENSE Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,58 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla.
#
# The Initial Developer of the Original Code is
# the Mozilla Foundation <http://www.mozilla.org/>.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mark Finkle <mfinkle@mozilla.com>
# Joel Maher <jmaher@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = base chrome locales components modules themes/core app
ifndef LIBXUL_SDK
PARALLEL_DIRS += $(DEPTH)/xulrunner/tools/redit
endif
include $(topsrcdir)/config/rules.mk
include $(topsrcdir)/testing/testsuite-targets.mk
package-mobile-tests:
$(MAKE) stage-mochitest DIST_BIN=$(DEPTH)/$(DIST)/bin/xulrunner
$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
@(cd $(PKG_STAGE) && tar $(TAR_CREATE_FLAGS) - *) | bzip2 -f > $(DIST)/$(PKG_PATH)$(TEST_PACKAGE)

Просмотреть файл

@ -0,0 +1,170 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla.
#
# The Initial Developer of the Original Code is
# the Mozilla Foundation <http://www.mozilla.org/>.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mark Finkle <mfinkle@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = profile/extensions
PREF_JS_EXPORTS = $(srcdir)/mobile.js
ifndef LIBXUL_SDK
ifneq (Android,$(OS_TARGET))
PROGRAM=$(MOZ_APP_NAME)$(BIN_SUFFIX)
LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/build
LOCAL_INCLUDES += -I$(DEPTH)/build
DEFINES += -DXPCOM_GLUE
STL_FLAGS=
LIBS += \
$(EXTRA_DSO_LIBS) \
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
$(NULL)
ifeq ($(MOZ_PLATFORM_MAEMO),6)
LIBS += \
$(LIBXUL_DIST)/../widget/src/qt/faststartupqt/$(LIB_PREFIX)faststartupqt.$(LIB_SUFFIX) \
$(MOZ_QT_LIBS) \
$(NULL)
LOCAL_INCLUDES += -I$(topsrcdir)/widget/src/qt/faststartupqt $(TK_CFLAGS)
endif
ifeq ($(OS_ARCH),WINNT)
OS_LIBS += $(call EXPAND_LIBNAME,version)
endif
ifdef _MSC_VER
# Always enter a Windows program through wmain, whether or not we're
# a console application.
WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
endif
endif
endif #LIBXUL_SDK
# Make sure the standalone glue doesn't try to get libxpcom.so from mobile/app.
NSDISTMODE = copy
include $(topsrcdir)/config/rules.mk
APP_ICON = mobile
DEFINES += \
-DAPP_NAME=$(MOZ_APP_NAME) \
-DAPP_VERSION=$(MOZ_APP_VERSION) \
-DMOZ_UPDATER=$(MOZ_UPDATER) \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
REDIT_PATH = $(LIBXUL_DIST)/bin
endif
APP_BINARY = $(MOZ_APP_NAME)$(BIN_SUFFIX)
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
APP_NAME = $(MOZ_APP_DISPLAYNAME)
APP_VERSION = $(MOZ_APP_VERSION)
ifdef MOZ_DEBUG
APP_NAME := $(APP_NAME)Debug
endif
AB_CD = $(MOZ_UI_LOCALE)
AB := $(firstword $(subst -, ,$(AB_CD)))
clean clobber repackage::
rm -rf $(DIST)/$(APP_NAME).app
ifdef LIBXUL_SDK
APPFILES = Resources
else
APPFILES = MacOS
endif
libs repackage::
mkdir -p $(DIST)/$(APP_NAME).app/Contents/MacOS
rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents $(DIST)/$(APP_NAME).app --exclude English.lproj
mkdir -p $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj
rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj
sed -e "s/%APP_VERSION%/$(APP_VERSION)/" -e "s/%APP_NAME%/$(APP_NAME)/" -e "s/%APP_BINARY%/$(APP_BINARY)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(DIST)/$(APP_NAME).app/Contents/Info.plist
sed -e "s/%APP_VERSION%/$(APP_VERSION)/" -e "s/%APP_NAME%/$(APP_NAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj/InfoPlist.strings
rsync -a $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
$(RM) $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/mangle $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/shlibsign
ifdef LIBXUL_SDK
cp $(LIBXUL_DIST)/bin/xulrunner$(BIN_SUFFIX) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(APP_BINARY)
rsync -a --exclude nsinstall --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(DIST)/$(APP_NAME).app/Contents/Frameworks
else
rm -f $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM)
rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS
endif
printf "APPLMOZB" > $(DIST)/$(APP_NAME).app/Contents/PkgInfo
else # MOZ_WIDGET_TOOLKIT != cocoa
libs::
ifdef LIBXUL_SDK
cp $(LIBXUL_DIST)/bin/xulrunner-stub$(BIN_SUFFIX) $(DIST)/bin/$(APP_BINARY)
endif
ifndef SKIP_COPY_XULRUNNER
ifdef LIBXUL_SDK
$(NSINSTALL) -D $(DIST)/bin/xulrunner
(cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -)
endif
endif # SKIP_COPY_XULRUNNER
ifeq ($(MOZ_PLATFORM_MAEMO),6)
$(NSINSTALL) -D $(DIST)/bin/res/drawable
cp $(topsrcdir)/mobile/app/maemo/* $(DIST)/bin/res/drawable/
cp $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/favicon32.png $(DIST)/bin/res/drawable/
endif
$(NSINSTALL) -D $(DIST)/bin/chrome/icons/default
ifeq ($(OS_ARCH),WINNT)
cp $(srcdir)/$(APP_ICON).ico $(DIST)/bin/chrome/icons/default/$(APP_ICON).ico
$(REDIT_PATH)/redit$(HOST_BIN_SUFFIX) $(DIST)/bin/$(APP_BINARY) $(srcdir)/$(APP_ICON).ico
endif
endif

Двоичные данные
mobile/android/app/android/drawable-hdpi/alertaddons.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичные данные
mobile/android/app/android/drawable-hdpi/alertdownloads.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичные данные
mobile/android/app/android/drawable/alertaddons.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичные данные
mobile/android/app/android/drawable/alertdownloads.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Просмотреть файл

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>html</string>
<string>htm</string>
<string>shtml</string>
<string>xht</string>
<string>xhtml</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>HTML Document</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>HTML</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>text</string>
<string>txt</string>
<string>js</string>
<string>log</string>
<string>css</string>
<string>xul</string>
<string>rdf</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>Text Document</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>TEXT</string>
<string>utxt</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>jpeg</string>
<string>jpg</string>
<string>png</string>
<string>gif</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>fileBookmark.icns</string>
<key>CFBundleTypeName</key>
<string>document.icns</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>GIFf</string>
<string>JPEG</string>
<string>PNGf</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>fennec</string>
<key>CFBundleGetInfoString</key>
<string>%APP_NAME% %APP_VERSION%</string>
<key>CFBundleIconFile</key>
<string>fennec</string>
<key>CFBundleIdentifier</key>
<string>org.mozilla.fennec</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>%APP_NAME%</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>%APP_VERSION%</string>
<key>CFBundleSignature</key>
<string>MOZB</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLIconFile</key>
<string>document.icns</string>
<key>CFBundleURLName</key>
<string>http URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>http</string>
</array>
</dict>
<dict>
<key>CFBundleURLIconFile</key>
<string>document.icns</string>
<key>CFBundleURLName</key>
<string>https URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>https</string>
</array>
</dict>
<dict>
<key>CFBundleURLName</key>
<string>ftp URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>ftp</string>
</array>
</dict>
<dict>
<key>CFBundleURLName</key>
<string>file URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>file</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>%APP_VERSION%</string>
<key>NSAppleScriptEnabled</key>
<true/>
<key>CGDisableCoalescedUpdates</key>
<true/>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1 @@
CFBundleName = "%APP_NAME%";

Двоичные данные
mobile/android/app/maemo/toolbar_splash.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.9 KiB

Двоичные данные
mobile/android/app/mobile.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.2 KiB

Просмотреть файл

@ -0,0 +1,689 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Mobile Browser.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Brubeck <mbrubeck@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#filter substitution
// For browser.xml binding
//
// cacheRatio* is a ratio that determines the amount of pixels to cache. The
// ratio is multiplied by the viewport width or height to get the displayport's
// width or height, respectively.
//
// (divide integer value by 1000 to get the ratio)
//
// For instance: cachePercentageWidth is 1500
// viewport height is 500
// => display port height will be 500 * 1.5 = 750
//
pref("toolkit.browser.cacheRatioWidth", 2000);
pref("toolkit.browser.cacheRatioHeight", 3000);
// How long before a content view (a handle to a remote scrollable object)
// expires.
pref("toolkit.browser.contentViewExpire", 3000);
pref("toolkit.defaultChromeURI", "chrome://browser/content/browser.xul");
pref("general.useragent.compatMode.firefox", true);
pref("browser.chromeURL", "chrome://browser/content/");
pref("browser.tabs.warnOnClose", true);
pref("browser.tabs.remote", true);
pref("toolkit.screen.lock", false);
// From libpref/src/init/all.js, extended to allow a slightly wider zoom range.
pref("zoom.minPercent", 20);
pref("zoom.maxPercent", 400);
pref("toolkit.zoomManager.zoomValues", ".2,.3,.5,.67,.8,.9,1,1.1,1.2,1.33,1.5,1.7,2,2.4,3,4");
// Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
pref("browser.viewport.scaleRatio", -1);
pref("browser.viewport.desktopWidth", 980);
#ifndef ANDROID
#ifndef MOZ_PLATFORM_MAEMO
// On desktop builds, simulate an MDPI tablet by default.
pref("layout.css.dpi", 160);
#else
// Maemo X11 lies about its dpi
pref("layout.css.dpi", 240);
#endif
#endif
/* allow scrollbars to float above chrome ui */
pref("ui.scrollbarsCanOverlapContent", 1);
/* cache prefs */
pref("browser.cache.disk.enable", true);
pref("browser.cache.disk.capacity", 10240); // kilobytes
pref("browser.cache.disk.smart_size.enabled", false);
pref("browser.cache.disk.smart_size.first_run", false);
pref("browser.cache.memory.enable", true);
pref("browser.cache.memory.capacity", 1024); // kilobytes
/* image cache prefs */
pref("image.cache.size", 1048576); // bytes
/* offline cache prefs */
pref("browser.offline-apps.notify", true);
pref("browser.cache.offline.enable", true);
pref("browser.cache.offline.capacity", 5120); // kilobytes
pref("offline-apps.quota.max", 2048); // kilobytes
pref("offline-apps.quota.warn", 1024); // kilobytes
/* protocol warning prefs */
pref("network.protocol-handler.warn-external.tel", false);
pref("network.protocol-handler.warn-external.mailto", false);
pref("network.protocol-handler.warn-external.vnd.youtube", false);
/* http prefs */
pref("network.http.pipelining", true);
pref("network.http.pipelining.ssl", true);
pref("network.http.proxy.pipelining", true);
pref("network.http.pipelining.maxrequests" , 6);
pref("network.http.keep-alive.timeout", 600);
pref("network.http.max-connections", 6);
pref("network.http.max-connections-per-server", 4);
pref("network.http.max-persistent-connections-per-server", 4);
pref("network.http.max-persistent-connections-per-proxy", 4);
#ifdef MOZ_PLATFORM_MAEMO
pref("network.autodial-helper.enabled", true);
#endif
// See bug 545869 for details on why these are set the way they are
pref("network.buffer.cache.count", 24);
pref("network.buffer.cache.size", 16384);
/* history max results display */
pref("browser.display.history.maxresults", 100);
/* How many times should have passed before the remote tabs list is refreshed */
pref("browser.display.remotetabs.timeout", 10);
/* session history */
pref("browser.sessionhistory.max_total_viewers", 1);
pref("browser.sessionhistory.max_entries", 50);
/* session store */
pref("browser.sessionstore.resume_session_once", false);
pref("browser.sessionstore.resume_from_crash", true);
pref("browser.sessionstore.resume_from_crash_timeout", 60); // minutes
pref("browser.sessionstore.interval", 10000); // milliseconds
pref("browser.sessionstore.max_tabs_undo", 1);
/* these should help performance */
pref("mozilla.widget.force-24bpp", true);
pref("mozilla.widget.use-buffer-pixmap", true);
pref("mozilla.widget.disable-native-theme", true);
pref("layout.reflow.synthMouseMove", false);
/* download manager (don't show the window or alert) */
pref("browser.download.useDownloadDir", true);
pref("browser.download.folderList", 1); // Default to ~/Downloads
pref("browser.download.manager.showAlertOnComplete", false);
pref("browser.download.manager.showAlertInterval", 2000);
pref("browser.download.manager.retention", 2);
pref("browser.download.manager.showWhenStarting", false);
pref("browser.download.manager.closeWhenDone", true);
pref("browser.download.manager.openDelay", 0);
pref("browser.download.manager.focusWhenStarting", false);
pref("browser.download.manager.flashCount", 2);
pref("browser.download.manager.displayedHistoryDays", 7);
/* download alerts (disabled above) */
pref("alerts.slideIncrement", 1);
pref("alerts.slideIncrementTime", 10);
pref("alerts.totalOpenTime", 6000);
pref("alerts.height", 50);
/* download helper */
pref("browser.helperApps.deleteTempFileOnExit", false);
/* password manager */
pref("signon.rememberSignons", true);
pref("signon.expireMasterPassword", false);
pref("signon.SignonFileName", "signons.txt");
pref("signon.debug", false);
/* form helper */
// 0 = disabled, 1 = enabled, 2 = dynamic depending on screen size
pref("formhelper.mode", 2);
pref("formhelper.autozoom", true);
pref("formhelper.autozoom.caret", true);
pref("formhelper.restore", false);
/* find helper */
pref("findhelper.autozoom", true);
/* autocomplete */
pref("browser.formfill.enable", true);
/* spellcheck */
pref("layout.spellcheckDefault", 0);
/* extension manager and xpinstall */
pref("xpinstall.whitelist.add", "addons.mozilla.org");
pref("extensions.enabledScopes", 1);
pref("extensions.autoupdate.enabled", true);
pref("extensions.autoupdate.interval", 86400);
pref("extensions.update.enabled", false);
pref("extensions.update.interval", 86400);
pref("extensions.dss.enabled", false);
pref("extensions.dss.switchPending", false);
pref("extensions.ignoreMTimeChanges", false);
pref("extensions.logging.enabled", false);
pref("extensions.hideInstallButton", true);
pref("extensions.showMismatchUI", false);
pref("extensions.hideUpdateButton", false);
pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%");
/* preferences for the Get Add-ons pane */
pref("extensions.getAddons.cache.enabled", true);
pref("extensions.getAddons.maxResults", 15);
pref("extensions.getAddons.recommended.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/recommended/");
pref("extensions.getAddons.recommended.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/list/featured/all/%MAX_RESULTS%/%OS%/%VERSION%");
pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/search?q=%TERMS%");
pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%");
pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/mobile/");
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/guid:%IDS%?src=mobile&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
/* preference for the locale picker */
pref("extensions.getLocales.get.url", "");
pref("extensions.compatability.locales.buildid", "0");
/* blocklist preferences */
pref("extensions.blocklist.enabled", true);
pref("extensions.blocklist.interval", 86400);
pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
/* block popups by default, and notify the user about blocked popups */
pref("dom.disable_open_during_load", true);
pref("privacy.popups.showBrowserMessage", true);
pref("keyword.enabled", true);
pref("keyword.URL", "http://www.google.com/m?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q=");
pref("accessibility.typeaheadfind", false);
pref("accessibility.typeaheadfind.timeout", 5000);
pref("accessibility.typeaheadfind.flashBar", 1);
pref("accessibility.typeaheadfind.linksonly", false);
pref("accessibility.typeaheadfind.casesensitive", 0);
// zoom key(F7) conflicts with caret browsing on maemo
pref("accessibility.browsewithcaret_shortcut.enabled", false);
// Whether or not we show a dialog box informing the user that the update was
// successfully applied.
pref("app.update.showInstalledUI", false);
// Whether the character encoding menu is under the main Firefox button. This
// preference is a string so that localizers can alter it.
pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties");
pref("intl.charsetmenu.browser.static", "chrome://browser/locale/browser.properties");
// pointer to the default engine name
pref("browser.search.defaultenginename", "chrome://browser/locale/region.properties");
// SSL error page behaviour
pref("browser.ssl_override_behavior", 2);
pref("browser.xul.error_pages.expert_bad_cert", false);
// disable logging for the search service by default
pref("browser.search.log", false);
// ordering of search engines in the engine list.
pref("browser.search.order.1", "chrome://browser/locale/region.properties");
pref("browser.search.order.2", "chrome://browser/locale/region.properties");
// disable updating
pref("browser.search.update", false);
pref("browser.search.update.log", false);
pref("browser.search.updateinterval", 6);
// enable search suggestions by default
pref("browser.search.suggest.enabled", true);
// Tell the search service to load search plugins from the locale JAR
pref("browser.search.loadFromJars", true);
pref("browser.search.jarURIs", "chrome://browser/locale/searchplugins/");
// tell the search service that we don't really expose the "current engine"
pref("browser.search.noCurrentEngine", true);
// enable xul error pages
pref("browser.xul.error_pages.enabled", true);
// Specify emptyRestriction = 0 so that bookmarks appear in the list by default
pref("browser.urlbar.default.behavior", 0);
pref("browser.urlbar.default.behavior.emptyRestriction", 0);
// Let the faviconservice know that we display favicons as 32x32px so that it
// uses the right size when optimizing favicons
pref("places.favicons.optimizeToDimension", 32);
// various and sundry awesomebar prefs (should remove/re-evaluate
// these once bug 447900 is fixed)
pref("browser.urlbar.clickSelectsAll", true);
pref("browser.urlbar.doubleClickSelectsAll", true);
pref("browser.urlbar.autoFill", false);
pref("browser.urlbar.matchOnlyTyped", false);
pref("browser.urlbar.matchBehavior", 1);
pref("browser.urlbar.filter.javascript", true);
pref("browser.urlbar.maxRichResults", 24); // increased so we see more results when portrait
pref("browser.urlbar.search.chunkSize", 1000);
pref("browser.urlbar.search.timeout", 100);
pref("browser.urlbar.restrict.history", "^");
pref("browser.urlbar.restrict.bookmark", "*");
pref("browser.urlbar.restrict.tag", "+");
pref("browser.urlbar.match.title", "#");
pref("browser.urlbar.match.url", "@");
pref("browser.urlbar.autocomplete.search_threshold", 5);
pref("browser.history.grouping", "day");
pref("browser.history.showSessions", false);
pref("browser.sessionhistory.max_entries", 50);
pref("browser.history_expire_days", 180);
pref("browser.history_expire_days_min", 90);
pref("browser.history_expire_sites", 40000);
pref("browser.places.migratePostDataAnnotations", true);
pref("browser.places.updateRecentTagsUri", true);
pref("places.frecency.numVisits", 10);
pref("places.frecency.numCalcOnIdle", 50);
pref("places.frecency.numCalcOnMigrate", 50);
pref("places.frecency.updateIdleTime", 60000);
pref("places.frecency.firstBucketCutoff", 4);
pref("places.frecency.secondBucketCutoff", 14);
pref("places.frecency.thirdBucketCutoff", 31);
pref("places.frecency.fourthBucketCutoff", 90);
pref("places.frecency.firstBucketWeight", 100);
pref("places.frecency.secondBucketWeight", 70);
pref("places.frecency.thirdBucketWeight", 50);
pref("places.frecency.fourthBucketWeight", 30);
pref("places.frecency.defaultBucketWeight", 10);
pref("places.frecency.embedVisitBonus", 0);
pref("places.frecency.linkVisitBonus", 100);
pref("places.frecency.typedVisitBonus", 2000);
pref("places.frecency.bookmarkVisitBonus", 150);
pref("places.frecency.downloadVisitBonus", 0);
pref("places.frecency.permRedirectVisitBonus", 0);
pref("places.frecency.tempRedirectVisitBonus", 0);
pref("places.frecency.defaultVisitBonus", 0);
pref("places.frecency.unvisitedBookmarkBonus", 140);
pref("places.frecency.unvisitedTypedBonus", 200);
// disable color management
pref("gfx.color_management.mode", 0);
// don't allow JS to move and resize existing windows
pref("dom.disable_window_move_resize", true);
// prevent click image resizing for nsImageDocument
pref("browser.enable_click_image_resizing", false);
// open in tab preferences
// 0=default window, 1=current window/tab, 2=new window, 3=new tab in most window
pref("browser.link.open_external", 3);
pref("browser.link.open_newwindow", 3);
// 0=force all new windows to tabs, 1=don't force, 2=only force those with no features set
pref("browser.link.open_newwindow.restriction", 0);
// controls which bits of private data to clear. by default we clear them all.
pref("privacy.item.cache", true);
pref("privacy.item.cookies", true);
pref("privacy.item.offlineApps", true);
pref("privacy.item.history", true);
pref("privacy.item.formdata", true);
pref("privacy.item.downloads", true);
pref("privacy.item.passwords", true);
pref("privacy.item.sessions", true);
pref("privacy.item.geolocation", true);
pref("privacy.item.siteSettings", true);
pref("privacy.item.syncAccount", true);
#ifdef MOZ_PLATFORM_MAEMO
pref("plugins.force.wmode", "opaque");
#endif
// URL to the Learn More link XXX this is the firefox one. Bug 495578 fixes this.
pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/");
// enable geo
pref("geo.enabled", true);
// content sink control -- controls responsiveness during page load
// see https://bugzilla.mozilla.org/show_bug.cgi?id=481566#c9
pref("content.sink.enable_perf_mode", 2); // 0 - switch, 1 - interactive, 2 - perf
pref("content.sink.pending_event_mode", 0);
pref("content.sink.perf_deflect_count", 1000000);
pref("content.sink.perf_parse_time", 50000000);
// Disable methodjit in chrome to save memory
pref("javascript.options.methodjit.chrome", false);
pref("javascript.options.mem.high_water_mark", 32);
// Disable the JS engine's gc on memory pressure, since we do one in the mobile
// browser (bug 669346).
pref("javascript.options.gc_on_memory_pressure", false);
pref("dom.max_chrome_script_run_time", 0); // disable slow script dialog for chrome
pref("dom.max_script_run_time", 20);
// JS error console
pref("devtools.errorconsole.enabled", false);
pref("browser.ui.layout.tablet", -1); // on: 1, off: 0, auto: -1
// kinetic tweakables
pref("browser.ui.kinetic.updateInterval", 16);
pref("browser.ui.kinetic.exponentialC", 1400);
pref("browser.ui.kinetic.polynomialC", 100);
pref("browser.ui.kinetic.swipeLength", 160);
// zooming
pref("browser.ui.zoom.pageFitGranularity", 9); // don't zoom to fit by less than 1/9 (11%)
pref("browser.ui.zoom.animationDuration", 200); // ms duration of double-tap zoom animation
pref("browser.ui.zoom.reflow", false); // Change text wrapping on double-tap
pref("browser.ui.zoom.reflow.fontSize", 720);
// pinch gesture
pref("browser.ui.pinch.maxGrowth", 150); // max pinch distance growth
pref("browser.ui.pinch.maxShrink", 200); // max pinch distance shrinkage
pref("browser.ui.pinch.scalingFactor", 500); // scaling factor for above pinch limits
// Touch radius (area around the touch location to look for target elements),
// in 1/240-inch pixels:
pref("browser.ui.touch.left", 8);
pref("browser.ui.touch.right", 8);
pref("browser.ui.touch.top", 12);
pref("browser.ui.touch.bottom", 4);
pref("browser.ui.touch.weight.visited", 120); // percentage
// plugins
#if MOZ_PLATFORM_MAEMO == 6
pref("plugin.disable", false);
pref("dom.ipc.plugins.enabled", true);
#elifdef ANDROID
pref("plugin.disable", false);
pref("dom.ipc.plugins.enabled", false);
#else
pref("plugin.disable", true);
pref("dom.ipc.plugins.enabled", true);
#endif
// process priority
// higher values give content process less CPU time
#if MOZ_PLATFORM_MAEMO == 5
pref("dom.ipc.content.nice", 10);
#else
pref("dom.ipc.content.nice", 1);
#endif
// product URLs
// The breakpad report server to link to in about:crashes
pref("breakpad.reportURL", "http://crash-stats.mozilla.com/report/index/");
pref("app.releaseNotesURL", "http://www.mozilla.com/%LOCALE%/mobile/%VERSION%/releasenotes/");
pref("app.sync.tutorialURL", "https://support.mozilla.com/kb/sync-firefox-between-desktop-and-mobile");
pref("app.support.baseURL", "http://support.mozilla.com/mobile");
pref("app.feedbackURL", "http://input.mozilla.com/feedback/");
pref("app.privacyURL", "http://www.mozilla.com/%LOCALE%/m/privacy.html");
pref("app.creditsURL", "http://www.mozilla.org/credits/");
pref("app.channelURL", "http://www.mozilla.org/%LOCALE%/firefox/channel/");
#if MOZ_UPDATE_CHANNEL == beta
pref("app.featuresURL", "http://www.mozilla.com/%LOCALE%/mobile/beta/features/");
pref("app.faqURL", "http://www.mozilla.com/%LOCALE%/mobile/beta/faq/");
#else
pref("app.featuresURL", "http://www.mozilla.com/%LOCALE%/mobile/features/");
pref("app.faqURL", "http://www.mozilla.com/%LOCALE%/mobile/faq/");
#endif
// Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror)
pref("security.alternate_certificate_error_page", "certerror");
pref("security.warn_viewing_mixed", false); // Warning is disabled. See Bug 616712.
// Override some named colors to avoid inverse OS themes
pref("ui.-moz-dialog", "#efebe7");
pref("ui.-moz-dialogtext", "#101010");
pref("ui.-moz-field", "#fff");
pref("ui.-moz-fieldtext", "#1a1a1a");
pref("ui.-moz-buttonhoverface", "#f3f0ed");
pref("ui.-moz-buttonhovertext", "#101010");
pref("ui.-moz-combobox", "#fff");
pref("ui.-moz-comboboxtext", "#101010");
pref("ui.buttonface", "#ece7e2");
pref("ui.buttonhighlight", "#fff");
pref("ui.buttonshadow", "#aea194");
pref("ui.buttontext", "#101010");
pref("ui.captiontext", "#101010");
pref("ui.graytext", "#b1a598");
pref("ui.highlight", "#fad184");
pref("ui.highlighttext", "#1a1a1a");
pref("ui.infobackground", "#f5f5b5");
pref("ui.infotext", "#000");
pref("ui.menu", "#f7f5f3");
pref("ui.menutext", "#101010");
pref("ui.threeddarkshadow", "#000");
pref("ui.threedface", "#ece7e2");
pref("ui.threedhighlight", "#fff");
pref("ui.threedlightshadow", "#ece7e2");
pref("ui.threedshadow", "#aea194");
pref("ui.window", "#efebe7");
pref("ui.windowtext", "#101010");
pref("ui.windowframe", "#efebe7");
#ifdef MOZ_OFFICIAL_BRANDING
pref("browser.search.param.yahoo-fr", "moz35");
pref("browser.search.param.yahoo-fr-cjkt", "moz35");
pref("browser.search.param.yahoo-fr-ja", "mozff");
#endif
/* app update prefs */
pref("app.update.timer", 60000); // milliseconds (1 min)
#ifdef MOZ_UPDATER
pref("app.update.enabled", true);
pref("app.update.timerFirstInterval", 20000); // milliseconds
pref("app.update.auto", false);
pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@");
pref("app.update.mode", 1);
pref("app.update.silent", false);
pref("app.update.url", "https://aus2.mozilla.org/update/4/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PLATFORM_VERSION%/update.xml");
pref("app.update.promptWaitTime", 43200);
pref("app.update.idletime", 60);
pref("app.update.showInstalledUI", false);
pref("app.update.incompatible.mode", 0);
pref("app.update.download.backgroundInterval", 0);
#ifdef MOZ_OFFICIAL_BRANDING
pref("app.update.interval", 86400);
pref("app.update.url.manual", "http://www.mozilla.com/%LOCALE%/m/");
pref("app.update.url.details", "http://www.mozilla.com/%LOCALE%/mobile/releases/");
#else
pref("app.update.interval", 28800);
pref("app.update.url.manual", "http://www.mozilla.com/%LOCALE%/mobile/");
pref("app.update.url.details", "http://www.mozilla.com/%LOCALE%/mobile/");
#endif
#endif
// replace newlines with spaces on paste into single-line text boxes
pref("editor.singleLine.pasteNewlines", 2);
#ifdef MOZ_PLATFORM_MAEMO
// update fonts for better readability
pref("font.default.x-baltic", "SwissA");
pref("font.default.x-central-euro", "SwissA");
pref("font.default.x-cyrillic", "SwissA");
pref("font.default.x-unicode", "SwissA");
pref("font.default.x-user-def", "SwissA");
pref("font.default.x-western", "SwissA");
#endif
#ifdef MOZ_SERVICES_SYNC
// sync service
pref("services.sync.client.type", "mobile");
pref("services.sync.registerEngines", "Tab,Bookmarks,Form,History,Password,Prefs");
pref("services.sync.autoconnectDelay", 5);
// prefs to sync by default
pref("services.sync.prefs.sync.browser.startup.homepage.title", true);
pref("services.sync.prefs.sync.browser.startup.homepage", true);
pref("services.sync.prefs.sync.browser.tabs.warnOnClose", true);
pref("services.sync.prefs.sync.browser.ui.zoom.reflow", true);
pref("services.sync.prefs.sync.devtools.errorconsole.enabled", true);
pref("services.sync.prefs.sync.javascript.enabled", true);
pref("services.sync.prefs.sync.lightweightThemes.isThemeSelected", true);
pref("services.sync.prefs.sync.lightweightThemes.usedThemes", true);
pref("services.sync.prefs.sync.network.cookie.cookieBehavior", true);
pref("services.sync.prefs.sync.permissions.default.image", true);
pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
pref("services.sync.prefs.sync.signon.rememberSignons", true);
#endif
// threshold where a tap becomes a drag, in 1/240" reference pixels
// The names of the preferences are to be in sync with nsEventStateManager.cpp
pref("ui.dragThresholdX", 25);
pref("ui.dragThresholdY", 25);
#if MOZ_PLATFORM_MAEMO == 6
pref("layers.acceleration.disabled", false);
#elifdef ANDROID
pref("layers.acceleration.disabled", false);
#else
pref("layers.acceleration.disabled", true);
#endif
pref("notification.feature.enabled", true);
// prevent tooltips from showing up
pref("browser.chrome.toolbar_tips", false);
pref("indexedDB.feature.enabled", true);
pref("dom.indexedDB.warningQuota", 5);
// prevent video elements from preloading too much data
pref("media.preload.default", 1); // default to preload none
pref("media.preload.auto", 2); // preload metadata if preload=auto
// 0: don't show fullscreen keyboard
// 1: always show fullscreen keyboard
// -1: show fullscreen keyboard based on threshold pref
pref("widget.ime.android.landscape_fullscreen", -1);
pref("widget.ime.android.fullscreen_threshold", 250); // in hundreths of inches
// optimize images memory usage
pref("image.mem.decodeondraw", true);
pref("content.image.allow_locking", false);
pref("image.mem.min_discard_timeout_ms", 10000);
// enable touch events interfaces
pref("dom.w3c_touch_events.enabled", true);
pref("dom.w3c_touch_events.safetyX", 5); // escape borders in units of 1/240"
pref("dom.w3c_touch_events.safetyY", 20); // escape borders in units of 1/240"
#ifdef MOZ_SAFE_BROWSING
// Safe browsing does nothing unless this pref is set
pref("browser.safebrowsing.enabled", true);
// Prevent loading of pages identified as malware
pref("browser.safebrowsing.malware.enabled", true);
// Non-enhanced mode (local url lists) URL list to check for updates
pref("browser.safebrowsing.provider.0.updateURL", "http://safebrowsing.clients.google.com/safebrowsing/downloads?client={moz:client}&appver={moz:version}&pver=2.2");
pref("browser.safebrowsing.dataProvider", 0);
// Does the provider name need to be localizable?
pref("browser.safebrowsing.provider.0.name", "Google");
pref("browser.safebrowsing.provider.0.keyURL", "https://sb-ssl.google.com/safebrowsing/newkey?client={moz:client}&appver={moz:version}&pver=2.2");
pref("browser.safebrowsing.provider.0.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/report?");
pref("browser.safebrowsing.provider.0.gethashURL", "http://safebrowsing.clients.google.com/safebrowsing/gethash?client={moz:client}&appver={moz:version}&pver=2.2");
// HTML report pages
pref("browser.safebrowsing.provider.0.reportGenericURL", "http://{moz:locale}.phish-generic.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportErrorURL", "http://{moz:locale}.phish-error.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportPhishURL", "http://{moz:locale}.phish-report.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportMalwareURL", "http://{moz:locale}.malware-report.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:locale}.malware-error.mozilla.com/?hl={moz:locale}");
// FAQ URLs
pref("browser.safebrowsing.warning.infoURL", "http://www.mozilla.com/%LOCALE%/%APP%/phishing-protection/");
pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/%APP%/geolocation/");
// Name of the about: page contributed by safebrowsing to handle display of error
// pages on phishing/malware hits. (bug 399233)
pref("urlclassifier.alternate_error_page", "blocked");
// The number of random entries to send with a gethash request.
pref("urlclassifier.gethashnoise", 4);
// The list of tables that use the gethash request to confirm partial results.
pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
// If an urlclassifier table has not been updated in this number of seconds,
// a gethash request will be forced to check that the result is still in
// the database.
pref("urlclassifier.confirm-age", 2700);
// Maximum size of the sqlite3 cache during an update, in bytes
pref("urlclassifier.updatecachemax", 4194304);
// URL for checking the reason for a malware warning.
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
#endif
// True if this is the first time we are showing about:firstrun
pref("browser.firstrun.show.uidiscovery", true);
pref("browser.firstrun.show.localepicker", false);
// True if you always want dump() to work
//
// On Android, you also need to do the following for the output
// to show up in logcat:
//
// $ adb shell stop
// $ adb shell setprop log.redirect-stdio true
// $ adb shell start
pref("browser.dom.window.dump.enabled", true);
// controls if we want camera support
pref("device.camera.enabled", true);
pref("media.realtime_decoder.enabled", true);
pref("dom.report_all_js_exceptions", true);
pref("javascript.options.showInConsole", true);
pref("full-screen-api.enabled", true);

Просмотреть файл

@ -0,0 +1,67 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla.
#
# The Initial Developer of the Original Code is
# the Mozilla Foundation <http://www.mozilla.org/>.
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mark Finkle <mfinkle@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
EXTENSIONS_DIR = $(call core_abspath,$(DIST))/bin/extensions
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
ifneq (,$(filter nightly aurora beta,$(MOZ_UPDATE_CHANNEL)))
EXTENSIONS = \
feedback@mobile.mozilla.org \
$(NULL)
define _INSTALL_EXTENSION
$(NSINSTALL) -D $(dir) && \
$(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(srcdir)/$(dir)/install.rdf.in > $(dir)/install.rdf && \
cd $(dir) && \
$(ZIP) -r9XD $(EXTENSIONS_DIR)/$(dir).xpi install.rdf && \
cd $(srcdir)/$(dir) && \
$(ZIP) -r9XD $(EXTENSIONS_DIR)/$(dir).xpi * -x install.rdf.in
endef # do not remove the blank line!
libs::
$(NSINSTALL) -D $(EXTENSIONS_DIR)
$(foreach dir,$(EXTENSIONS),$(_INSTALL_EXTENSION))
endif

Просмотреть файл

@ -0,0 +1,5 @@
content feedback content/
skin feedback classic/1.0 skin/
locale feedback en-US locale/en-US/
overlay chrome://browser/content/browser.xul chrome://feedback/content/overlay.xul

Просмотреть файл

@ -0,0 +1,33 @@
function populateFeedback(aMessage) {
let json = aMessage.json;
let referrer = json.referrer;
let URLElem = content.document.getElementById("id_url");
if (URLElem)
URLElem.value = referrer;
let URLElems = content.document.getElementsByClassName("url");
for (let index=0; index<URLElems.length; index++)
URLElems[index].value = referrer;
let device = json.device || "";
let deviceElem = content.document.getElementById("id_device");
if (deviceElem)
deviceElem.value = device;
let deviceElems = content.document.getElementsByClassName("device");
for (let index=0; index<deviceElems.length; index++)
deviceElems[index].value = device;
let manufacturer = json.manufacturer || "";
let manufacturerElem = content.document.getElementById("id_manufacturer");
if (manufacturerElem)
manufacturerElem.value = manufacturer;
let manufacturerElems = content.document.getElementsByClassName("manufacturer");
for (let index=0; index<manufacturerElems.length; index++)
manufacturerElems[index].value = manufacturer;
}
addMessageListener("Feedback:InitPage", populateFeedback);

Просмотреть файл

@ -0,0 +1,148 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Feedback.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Finkle <mark.finkle@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var Feedback = {
_prefs: [],
_device: "",
_manufacturer: "",
init: function(aEvent) {
// Delay the widget initialization during startup.
let panel = document.getElementById("feedback-container");
panel.addEventListener("ToolPanelShown", function delayedInit(aEvent) {
panel.removeEventListener("ToolPanelShown", delayedInit, false);
// A simple frame script to fill in the referrer page and device info
messageManager.loadFrameScript("chrome://feedback/content/content.js", true);
let setting = document.getElementById("feedback-checkCompatibility");
setting.setAttribute("pref", Feedback.compatibilityPref);
setting.preferenceChanged();
document.getElementById("feedback-container").hidden = false;
let feedbackPrefs = document.getElementById("feedback-tools").childNodes;
for (let i = 0; i < feedbackPrefs.length; i++) {
let pref = feedbackPrefs[i].getAttribute("pref");
if (!pref)
continue;
let value = Services.prefs.getPrefType(pref) == Ci.nsIPrefBranch.PREF_INVALID ? false : Services.prefs.getBoolPref(pref);
Feedback._prefs.push({ "name": pref, "value": value });
}
let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
Feedback._device = sysInfo.get("device");
Feedback._manufacturer = sysInfo.get("manufacturer");
}, false);
},
get compatibilityPref() {
let result = "extensions.checkCompatibility.";
let channel = Services.prefs.getCharPref("app.update.channel");
if (channel == "nightly") {
result += "nightly";
} else {
// Copied from toolkit/mozapps/extensions/XPIProvider.jsm
const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi;
result += Services.appinfo.version.replace(BRANCH_REGEXP, "$1");
}
delete this.compatibilityPref;
return this.compatibilityPref = result;
},
openFeedback: function(aName) {
let pref = "extensions.feedback.url." + aName;
let url = Services.prefs.getPrefType(pref) == Ci.nsIPrefBranch.PREF_INVALID ? "" : Services.prefs.getCharPref(pref);
if (!url)
return;
let currentURL = Browser.selectedBrowser.currentURI.spec;
let newTab = BrowserUI.newTab(url, Browser.selectedTab);
// Tell the feedback page to fill in the referrer URL
newTab.browser.messageManager.addMessageListener("DOMContentLoaded", function() {
newTab.browser.messageManager.removeMessageListener("DOMContentLoaded", arguments.callee, true);
newTab.browser.messageManager.sendAsyncMessage("Feedback:InitPage", { referrer: currentURL, device: Feedback._device, manufacturer: Feedback._manufacturer });
});
},
updateRestart: function updateRestart() {
let msg = document.getElementById("feedback-messages");
if (msg) {
let value = "restart-app";
let notification = msg.getNotificationWithValue(value);
if (notification) {
// Check if the prefs are back to the initial state dismiss the restart
// notification because if does not make sense anymore
for each (let pref in this._prefs) {
let value = Services.prefs.getPrefType(pref.name) == Ci.nsIPrefBranch.PREF_INVALID ? false : Services.prefs.getBoolPref(pref.name);
if (value != pref.value)
return;
}
notification.close();
return;
}
let restartCallback = function(aNotification, aDescription) {
// Notify all windows that an application quit has been requested
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
// If nothing aborted, quit the app
if (cancelQuit.data == false) {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
}
};
let strings = Strings.browser;
let buttons = [ {
label: strings.GetStringFromName("notificationRestart.button"),
accessKey: "",
callback: restartCallback
} ];
let message = strings.GetStringFromName("notificationRestart.normal");
msg.appendNotification(message, value, "", msg.PRIORITY_WARNING_LOW, buttons);
}
}
};
window.addEventListener("load", Feedback.init, false);

Просмотреть файл

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Feedback.
-
- The Initial Developer of the Original Code is
- Mozilla Corporation.
- Portions created by the Initial Developer are Copyright (C) 2010
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Mark Finkle <mark.finkle@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<?xml-stylesheet href="chrome://feedback/skin/overlay.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % feedbackDTD SYSTEM "chrome://browser/locale/feedback.dtd">
%feedbackDTD;
]>
<overlay id="feedback-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://feedback/content/overlay.js"/>
<box id="panel-controls">
<toolbarbutton id="tool-feedback" class="panel-row-button" autocheck="true" type="radio" label="&feedbackHeader2.label;" group="1" linkedpanel="feedback-container" insertafter="tool-addons"/>
</box>
<deck id="panel-items">
<vbox id="feedback-container" flex="1" hidden="true">
<notificationbox id="feedback-messages" flex="1">
<richlistbox id="feedback-list" flex="1" onselect="this.ensureSelectedElementIsVisible()">
<label id="feedback-list-header" class="panel-header" value="&feedbackHeader2.label;"/>
<settings id="feedback-communicate" label="&feedback.communicate.title;">
<setting title="&feedback.feedback.title;" type="control">
<button id="feedback-feedback-happy" oncommand="Feedback.openFeedback('happy');"/>
<button id="feedback-feedback-sad" oncommand="Feedback.openFeedback('sad');"/>
</setting>
</settings>
<settings id="feedback-tools" label="&feedback.tools.title;">
<setting pref="toolkit.telemetry.enabled" title="&feedback.allowTelemetry.title;" type="bool"/>
<setting id="feedback-checkCompatibility" title="&feedback.forceCompat.title;" type="bool" inverted="true" oninputchanged="Feedback.updateRestart();"/>
<setting pref="devtools.errorconsole.enabled" title="&feedback.errorConsole.title;" type="bool"/>
</settings>
</richlistbox>
</notificationbox>
</vbox>
</deck>
</overlay>

Просмотреть файл

@ -0,0 +1,2 @@
pref("extensions.feedback.url.happy", "http://input.mozilla.com/happy");
pref("extensions.feedback.url.sad", "http://input.mozilla.com/sad");

Просмотреть файл

@ -0,0 +1,28 @@
<?xml version="1.0"?>
#filter substitution
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>feedback@mobile.mozilla.org</em:id>
<em:version>1.0.1</em:version>
<em:type>2</em:type>
<!-- Target Application this extension can install into,
with minimum and maximum supported versions. -->
<em:targetApplication>
<Description>
<em:id>{a23983c0-fd0e-11dc-95ff-0800200c9a66}</em:id>
<em:minVersion>4.0</em:minVersion>
<em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>Feedback</em:name>
<em:description>Help make Firefox better by giving feedback.</em:description>
<em:creator>Mozilla Corporation</em:creator>
<em:iconURL>chrome://feedback/skin/dino-32.png</em:iconURL>
</Description>
</RDF>

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.4 KiB

Просмотреть файл

@ -0,0 +1,11 @@
#tool-feedback {
list-style-image: url("chrome://feedback/skin/beta-hdpi.png");
}
#feedback-feedback-happy {
list-style-image: url("chrome://feedback/skin/happy-32.png");
}
#feedback-feedback-sad {
list-style-image: url("chrome://feedback/skin/sad-32.png");
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.3 KiB

Просмотреть файл

@ -50,30 +50,31 @@ import java.text.NumberFormat;
public class AlertNotification public class AlertNotification
extends Notification extends Notification
{ {
Context mContext; private static final String LOGTAG = "GeckoAlertNotification";
int mId;
int mIcon; private final int mId;
String mTitle; private final int mIcon;
String mText; private final String mTitle;
boolean mProgressStyle; private final String mText;
NotificationManager mNotificationManager; private final NotificationManager mNotificationManager;
double mPrevPercent = -1;
String mPrevAlertText = ""; private boolean mProgressStyle; // = false
static final double UPDATE_THRESHOLD = .01; private double mPrevPercent = -1;
private String mPrevAlertText = "";
private static final double UPDATE_THRESHOLD = .01;
public AlertNotification(Context aContext, int aNotificationId, int aIcon, public AlertNotification(Context aContext, int aNotificationId, int aIcon,
String aTitle, String aText, long aWhen) { String aTitle, String aText, long aWhen) {
super(aIcon, (aText.length() > 0) ? aText : aTitle, aWhen); super(aIcon, (aText.length() > 0) ? aText : aTitle, aWhen);
mContext = aContext;
mIcon = aIcon; mIcon = aIcon;
mTitle = aTitle; mTitle = aTitle;
mText = aText; mText = aText;
mProgressStyle = false;
mId = aNotificationId; mId = aNotificationId;
mNotificationManager = (NotificationManager) mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE); aContext.getSystemService(Context.NOTIFICATION_SERVICE);
} }
public boolean isProgressStyle() { public boolean isProgressStyle() {
@ -94,15 +95,15 @@ public class AlertNotification
try { try {
URL url = new URL(aIconUri.toString()); URL url = new URL(aIconUri.toString());
Bitmap bm = BitmapFactory.decodeStream(url.openStream()); Bitmap bm = BitmapFactory.decodeStream(url.openStream());
view.setImageViewBitmap(R.id.notificationImage, bm); view.setImageViewBitmap(R.id.notification_image, bm);
view.setTextViewText(R.id.notificationTitle, mTitle); view.setTextViewText(R.id.notification_title, mTitle);
if (mText.length() > 0) { if (mText.length() > 0) {
view.setTextViewText(R.id.notificationText, mText); view.setTextViewText(R.id.notification_text, mText);
} }
contentView = view; contentView = view;
mNotificationManager.notify(mId, this); mNotificationManager.notify(mId, this);
} catch(Exception ex) { } catch(Exception ex) {
Log.e("GeckoAlert", "failed to create bitmap", ex); Log.e(LOGTAG, "failed to create bitmap", ex);
} }
} }
@ -112,8 +113,8 @@ public class AlertNotification
int layout = aAlertText.length() > 0 ? R.layout.notification_progress_text : R.layout.notification_progress; int layout = aAlertText.length() > 0 ? R.layout.notification_progress_text : R.layout.notification_progress;
RemoteViews view = new RemoteViews(GeckoApp.mAppContext.getPackageName(), layout); RemoteViews view = new RemoteViews(GeckoApp.mAppContext.getPackageName(), layout);
view.setImageViewResource(R.id.notificationImage, mIcon); view.setImageViewResource(R.id.notification_image, mIcon);
view.setTextViewText(R.id.notificationTitle, mTitle); view.setTextViewText(R.id.notification_title, mTitle);
contentView = view; contentView = view;
flags |= FLAG_ONGOING_EVENT | FLAG_ONLY_ALERT_ONCE; flags |= FLAG_ONGOING_EVENT | FLAG_ONLY_ALERT_ONCE;
@ -133,8 +134,8 @@ public class AlertNotification
if (mPrevAlertText.equals(text) && Math.abs(mPrevPercent - percent) < UPDATE_THRESHOLD) if (mPrevAlertText.equals(text) && Math.abs(mPrevPercent - percent) < UPDATE_THRESHOLD)
return; return;
contentView.setTextViewText(R.id.notificationText, text); contentView.setTextViewText(R.id.notification_text, text);
contentView.setProgressBar(R.id.notificationProgressbar, (int)aProgressMax, (int)aProgress, false); contentView.setProgressBar(R.id.notification_progressbar, (int)aProgressMax, (int)aProgress, false);
// Update the notification // Update the notification
mNotificationManager.notify(mId, this); mNotificationManager.notify(mId, this);

Просмотреть файл

@ -21,6 +21,9 @@
<uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
<uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"/>
<uses-feature android:name="android.hardware.location" android:required="false"/> <uses-feature android:name="android.hardware.location" android:required="false"/>
<uses-feature android:name="android.hardware.location.gps" android:required="false"/> <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
<uses-feature android:name="android.hardware.touchscreen"/> <uses-feature android:name="android.hardware.touchscreen"/>
@ -39,10 +42,10 @@
<activity android:name="App" <activity android:name="App"
android:label="@MOZ_APP_DISPLAYNAME@" android:label="@MOZ_APP_DISPLAYNAME@"
android:configChanges="keyboard|keyboardHidden|mcc|mnc" android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation"
android:windowSoftInputMode="stateUnspecified|adjustResize" android:windowSoftInputMode="stateUnspecified|adjustResize"
android:launchMode="singleTask" android:launchMode="singleTask"
android:theme="@style/GreyTheme"> android:theme="@style/Gecko">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
@ -94,7 +97,7 @@
<activity android:name="Restarter" <activity android:name="Restarter"
android:process="@ANDROID_PACKAGE_NAME@Restarter" android:process="@ANDROID_PACKAGE_NAME@Restarter"
android:theme="@style/GreyTheme" android:theme="@style/Gecko"
android:excludeFromRecents="true"> android:excludeFromRecents="true">
<intent-filter> <intent-filter>
<action android:name="org.mozilla.gecko.restart"/> <action android:name="org.mozilla.gecko.restart"/>
@ -105,6 +108,7 @@
<activity android:name="CrashReporter" <activity android:name="CrashReporter"
android:label="@string/crash_reporter_title" android:label="@string/crash_reporter_title"
android:icon="@drawable/crash_reporter" android:icon="@drawable/crash_reporter"
android:theme="@style/Gecko"
android:excludeFromRecents="true"> android:excludeFromRecents="true">
<intent-filter> <intent-filter>
<action android:name="org.mozilla.gecko.reportCrash" /> <action android:name="org.mozilla.gecko.reportCrash" />
@ -114,12 +118,26 @@
<activity android:name="LauncherShortcuts" <activity android:name="LauncherShortcuts"
android:label="@string/launcher_shortcuts_title" android:label="@string/launcher_shortcuts_title"
android:theme="@android:style/Theme.Translucent"> android:theme="@style/Gecko.Translucent">
<!-- This intent-filter allows your shortcuts to be created in the launcher. --> <!-- This intent-filter allows your shortcuts to be created in the launcher. -->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" /> <action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="org.mozilla.gecko.AwesomeBar"
android:theme="@style/Gecko.Light.NoActionBar"
android:configChanges="orientation"
android:windowSoftInputMode="stateAlwaysVisible|adjustResize"/>
<activity android:name="org.mozilla.gecko.TabsTray"
android:theme="@style/Gecko.Translucent"/>
<activity android:name="org.mozilla.gecko.GeckoPreferences"
android:theme="@style/Gecko.TitleBar"
android:label="@string/preferences_title"
android:excludeFromRecents="true"/>
</application> </application>
</manifest> </manifest>

Просмотреть файл

@ -44,6 +44,7 @@ public class App extends GeckoApp {
public String getPackageName() { public String getPackageName() {
return "@ANDROID_PACKAGE_NAME@"; return "@ANDROID_PACKAGE_NAME@";
} }
public String getContentProcessName() { public String getContentProcessName() {
return "@MOZ_CHILD_PROCESS_NAME@"; return "@MOZ_CHILD_PROCESS_NAME@";
} }

Просмотреть файл

@ -0,0 +1,289 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Wes Johnston <wjohnston@mozilla.com>
* Mark Finkle <mfinkle@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.io.File;
import android.app.Activity;
import android.content.Intent;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Configuration;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
public class AwesomeBar extends Activity {
private static final String LOGTAG = "GeckoAwesomeBar";
static final String URL_KEY = "url";
static final String TITLE_KEY = "title";
static final String CURRENT_URL_KEY = "currenturl";
static final String TYPE_KEY = "type";
static enum Type { ADD, EDIT };
private String mType;
private AwesomeBarTabs mAwesomeTabs;
private AwesomeBarEditText mText;
private ImageButton mGoButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(LOGTAG, "creating awesomebar");
setContentView(R.layout.awesomebar_search);
mAwesomeTabs = (AwesomeBarTabs) findViewById(R.id.awesomebar_tabs);
mAwesomeTabs.setOnUrlOpenListener(new AwesomeBarTabs.OnUrlOpenListener() {
public void onUrlOpen(AwesomeBarTabs tabs, String url) {
openUrlAndFinish(url);
}
});
mGoButton = (ImageButton) findViewById(R.id.awesomebar_button);
mGoButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
openUrlAndFinish(mText.getText().toString());
}
});
mText = (AwesomeBarEditText) findViewById(R.id.awesomebar_text);
Resources resources = getResources();
int padding[] = { mText.getPaddingLeft(),
mText.getPaddingTop(),
mText.getPaddingRight(),
mText.getPaddingBottom() };
GeckoStateListDrawable states = new GeckoStateListDrawable();
states.initializeFilter(GeckoApp.mBrowserToolbar.getHighlightColor());
states.addState(new int[] { android.R.attr.state_focused }, resources.getDrawable(R.drawable.address_bar_url_pressed));
states.addState(new int[] { android.R.attr.state_pressed }, resources.getDrawable(R.drawable.address_bar_url_pressed));
states.addState(new int[] { }, resources.getDrawable(R.drawable.address_bar_url_default));
mText.setBackgroundDrawable(states);
mText.setPadding(padding[0], padding[1], padding[2], padding[3]);
Intent intent = getIntent();
String currentUrl = intent.getStringExtra(CURRENT_URL_KEY);
mType = intent.getStringExtra(TYPE_KEY);
if (currentUrl != null) {
mText.setText(currentUrl);
mText.selectAll();
}
mText.setOnKeyPreImeListener(new AwesomeBarEditText.OnKeyPreImeListener() {
public boolean onKeyPreIme(View v, int keyCode, KeyEvent event) {
InputMethodManager imm =
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
// If input method is in fullscreen mode, we want to dismiss
// it instead of closing awesomebar straight away.
if (!imm.isFullscreenMode() && keyCode == KeyEvent.KEYCODE_BACK) {
cancelAndFinish();
return true;
}
return false;
}
});
mText.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
// do nothing
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// do nothing
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
String text = s.toString();
mAwesomeTabs.filter(text);
updateGoButton(text);
}
});
mText.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ENTER) {
if (event.getAction() != KeyEvent.ACTION_DOWN)
return true;
openUrlAndFinish(mText.getText().toString());
return true;
} else {
return false;
}
}
});
mText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
});
}
@Override
public void onConfigurationChanged(Configuration newConfiguration) {
super.onConfigurationChanged(newConfiguration);
}
@Override
public boolean onSearchRequested() {
cancelAndFinish();
return true;
}
private void updateGoButton(String text) {
if (text.length() == 0) {
mGoButton.setVisibility(View.GONE);
return;
}
mGoButton.setVisibility(View.VISIBLE);
int imageResource = R.drawable.ic_awesomebar_go;
if (!GeckoAppShell.canCreateFixupURI(text)) {
imageResource = R.drawable.ic_awesomebar_search;
}
mGoButton.setImageResource(imageResource);
}
private void cancelAndFinish() {
setResult(Activity.RESULT_CANCELED);
finish();
}
private void openUrlAndFinish(String url) {
Intent resultIntent = new Intent();
resultIntent.putExtra(URL_KEY, url);
resultIntent.putExtra(TYPE_KEY, mType);
setResult(Activity.RESULT_OK, resultIntent);
finish();
overridePendingTransition(0, 0);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// This method is called only if the key event was not handled
// by any of the views, which usually means the edit box lost focus
if (keyCode == KeyEvent.KEYCODE_BACK ||
keyCode == KeyEvent.KEYCODE_MENU ||
keyCode == KeyEvent.KEYCODE_SEARCH ||
keyCode == KeyEvent.KEYCODE_DPAD_UP ||
keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
return super.onKeyDown(keyCode, event);
} else {
int selStart = -1;
int selEnd = -1;
if (mText.hasSelection()) {
selStart = mText.getSelectionStart();
selEnd = mText.getSelectionEnd();
}
// Return focus to the edit box, and dispatch the event to it
mText.requestFocusFromTouch();
if (selStart >= 0) {
// Restore the selection, which gets lost due to the focus switch
mText.setSelection(selStart, selEnd);
}
mText.dispatchKeyEvent(event);
return true;
}
}
@Override
public void onDestroy() {
super.onDestroy();
mAwesomeTabs.destroy();
}
public static class AwesomeBarEditText extends EditText {
OnKeyPreImeListener mOnKeyPreImeListener;
public interface OnKeyPreImeListener {
public boolean onKeyPreIme(View v, int keyCode, KeyEvent event);
}
public AwesomeBarEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mOnKeyPreImeListener = null;
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (mOnKeyPreImeListener != null)
return mOnKeyPreImeListener.onKeyPreIme(this, keyCode, event);
return false;
}
public void setOnKeyPreImeListener(OnKeyPreImeListener listener) {
mOnKeyPreImeListener = listener;
}
}
}

Просмотреть файл

@ -0,0 +1,624 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009-2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Lucas Rocha <lucasr@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.LightingColorFilter;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.provider.Browser;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ExpandableListView;
import android.widget.FilterQueryProvider;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.SimpleExpandableListAdapter;
import android.widget.TabHost;
import android.widget.TextView;
import java.lang.ref.WeakReference;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class AwesomeBarTabs extends TabHost {
private static final String LOGTAG = "GeckoAwesomeBarTabs";
private static final String ALL_PAGES_TAB = "all";
private static final String BOOKMARKS_TAB = "bookmarks";
private static final String HISTORY_TAB = "history";
private static enum HistorySection { TODAY, YESTERDAY, WEEK, OLDER };
private Context mContext;
private OnUrlOpenListener mUrlOpenListener;
private View.OnTouchListener mListTouchListener;
private SimpleCursorAdapter mAllPagesAdapter;
private SimpleCursorAdapter mBookmarksAdapter;
private SimpleExpandableListAdapter mHistoryAdapter;
// FIXME: This value should probably come from a
// prefs key (just like XUL-based fennec)
private static final int MAX_RESULTS = 100;
public interface OnUrlOpenListener {
public abstract void onUrlOpen(AwesomeBarTabs tabs, String url);
}
private class HistoryListAdapter extends SimpleExpandableListAdapter {
public HistoryListAdapter(Context context, List<? extends Map<String, ?>> groupData,
int groupLayout, String[] groupFrom, int[] groupTo,
List<? extends List<? extends Map<String, ?>>> childData,
int childLayout, String[] childFrom, int[] childTo) {
super(context, groupData, groupLayout, groupFrom, groupTo,
childData, childLayout, childFrom, childTo);
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
View childView =
super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);
@SuppressWarnings("unchecked")
Map<String,Object> historyItem =
(Map<String,Object>) mHistoryAdapter.getChild(groupPosition, childPosition);
byte[] b = (byte[]) historyItem.get(Browser.BookmarkColumns.FAVICON);
ImageView favicon = (ImageView) childView.findViewById(R.id.favicon);
if (b == null) {
favicon.setImageResource(R.drawable.favicon);
} else {
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
favicon.setImageBitmap(bitmap);
}
return childView;
}
}
private class AwesomeCursorViewBinder implements SimpleCursorAdapter.ViewBinder {
private boolean updateFavicon(View view, Cursor cursor, int faviconIndex) {
byte[] b = cursor.getBlob(faviconIndex);
ImageView favicon = (ImageView) view;
if (b == null) {
favicon.setImageResource(R.drawable.favicon);
} else {
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
favicon.setImageBitmap(bitmap);
}
return true;
}
private boolean updateTitle(View view, Cursor cursor, int titleIndex) {
String title = cursor.getString(titleIndex);
TextView titleView = (TextView)view;
// Use the URL instead of an empty title for consistency with the normal URL
// bar view - this is the equivalent of getDisplayTitle() in Tab.java
if (title == null || title.length() == 0) {
int urlIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.URL);
title = cursor.getString(urlIndex);
}
titleView.setText(title);
return true;
}
@Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
int faviconIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON);
if (columnIndex == faviconIndex) {
return updateFavicon(view, cursor, faviconIndex);
}
int titleIndex = cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.TITLE);
if (columnIndex == titleIndex) {
return updateTitle(view, cursor, titleIndex);
}
// Other columns are handled automatically
return false;
}
}
private class BookmarksQueryTask extends AsyncTask<Void, Void, Cursor> {
protected Cursor doInBackground(Void... arg0) {
ContentResolver resolver = mContext.getContentResolver();
return resolver.query(Browser.BOOKMARKS_URI,
null,
// Select all bookmarks with a non-empty URL. When the history
// is empty there appears to be a dummy entry in the database
// which has a title of "Bookmarks" and no URL; the length restriction
// is to avoid picking that up specifically.
Browser.BookmarkColumns.BOOKMARK + " = 1 AND LENGTH(" + Browser.BookmarkColumns.URL + ") > 0",
null,
Browser.BookmarkColumns.TITLE);
}
protected void onPostExecute(Cursor cursor) {
// Load the list using a custom adapter so we can create the bitmaps
mBookmarksAdapter = new SimpleCursorAdapter(
mContext,
R.layout.awesomebar_row,
cursor,
new String[] { AwesomeBar.TITLE_KEY,
AwesomeBar.URL_KEY,
Browser.BookmarkColumns.FAVICON },
new int[] { R.id.title, R.id.url, R.id.favicon }
);
mBookmarksAdapter.setViewBinder(new AwesomeCursorViewBinder());
final ListView bookmarksList = (ListView) findViewById(R.id.bookmarks_list);
bookmarksList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
handleItemClick(bookmarksList, position);
}
});
bookmarksList.setAdapter(mBookmarksAdapter);
}
}
private class HistoryQueryTask extends AsyncTask<Void, Void, Pair<List,List>> {
private static final long MS_PER_DAY = 86400000;
private static final long MS_PER_WEEK = MS_PER_DAY * 7;
protected Pair<List,List> doInBackground(Void... arg0) {
Pair<List,List> result = null;
ContentResolver resolver = mContext.getContentResolver();
Cursor cursor =
resolver.query(Browser.BOOKMARKS_URI,
null,
// Bookmarks that have not been visited have a date value
// of 0, so don't pick them up in the history view.
Browser.BookmarkColumns.DATE + " > 0",
null,
Browser.BookmarkColumns.DATE + " DESC LIMIT " + MAX_RESULTS);
Date now = new Date();
now.setHours(0);
now.setMinutes(0);
now.setSeconds(0);
long today = now.getTime();
// Split the list of urls into separate date range groups
// and show it in an expandable list view.
List<List<Map<String,?>>> childrenLists = null;
List<Map<String,?>> children = null;
List<Map<String,?>> groups = null;
HistorySection section = null;
// Move cursor before the first row in preparation
// for the iteration.
cursor.moveToPosition(-1);
// Split the history query results into adapters per time
// section (today, yesterday, week, older). Queries on content
// Browser content provider don't support limitting the number
// of returned rows so we limit it here.
while (cursor.moveToNext()) {
long time = cursor.getLong(cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.DATE));
HistorySection itemSection = getSectionForTime(time, today);
if (groups == null)
groups = new LinkedList<Map<String,?>>();
if (childrenLists == null)
childrenLists = new LinkedList<List<Map<String,?>>>();
if (section != itemSection) {
if (section != null) {
groups.add(createGroupItem(section));
childrenLists.add(children);
}
section = itemSection;
children = new LinkedList<Map<String,?>>();
}
children.add(createHistoryItem(cursor));
}
// Add any remaining section to the list if it hasn't
// been added to the list after the loop.
if (section != null && children != null) {
groups.add(createGroupItem(section));
childrenLists.add(children);
}
// Close the query cursor as we won't use it anymore
cursor.close();
if (groups != null && childrenLists != null) {
result = Pair.create((List) groups, (List) childrenLists);
}
return result;
}
public Map<String,?> createHistoryItem(Cursor cursor) {
Map<String,Object> historyItem = new HashMap<String,Object>();
String url = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.URL_KEY));
String title = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.TITLE_KEY));
byte[] favicon = cursor.getBlob(cursor.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON));
// Use the URL instead of an empty title for consistency with the normal URL
// bar view - this is the equivalent of getDisplayTitle() in Tab.java
if (title == null || title.length() == 0)
title = url;
historyItem.put(AwesomeBar.URL_KEY, url);
historyItem.put(AwesomeBar.TITLE_KEY, title);
if (favicon != null)
historyItem.put(Browser.BookmarkColumns.FAVICON, favicon);
return historyItem;
}
public Map<String,?> createGroupItem(HistorySection section) {
Map<String,String> groupItem = new HashMap<String,String>();
groupItem.put(AwesomeBar.TITLE_KEY, getSectionName(section));
return groupItem;
}
private String getSectionName(HistorySection section) {
Resources resources = mContext.getResources();
switch (section) {
case TODAY:
return resources.getString(R.string.history_today_section);
case YESTERDAY:
return resources.getString(R.string.history_yesterday_section);
case WEEK:
return resources.getString(R.string.history_week_section);
case OLDER:
return resources.getString(R.string.history_older_section);
}
return null;
}
private void expandAllGroups(ExpandableListView historyList) {
int groupCount = mHistoryAdapter.getGroupCount();
for (int i = 0; i < groupCount; i++) {
historyList.expandGroup(i);
}
}
private HistorySection getSectionForTime(long time, long today) {
long delta = today - time;
if (delta < 0) {
return HistorySection.TODAY;
} else if (delta > 0 && delta < MS_PER_DAY) {
return HistorySection.YESTERDAY;
} else if (delta > MS_PER_DAY && delta < MS_PER_WEEK) {
return HistorySection.WEEK;
}
return HistorySection.OLDER;
}
@SuppressWarnings("unchecked")
protected void onPostExecute(Pair<List,List> result) {
// FIXME: display some sort of message when there's no history
if (result == null)
return;
mHistoryAdapter = new HistoryListAdapter(
mContext,
result.first,
R.layout.awesomebar_header_row,
new String[] { AwesomeBar.TITLE_KEY },
new int[] { R.id.title },
result.second,
R.layout.awesomebar_row,
new String[] { AwesomeBar.TITLE_KEY, AwesomeBar.URL_KEY },
new int[] { R.id.title, R.id.url }
);
final ExpandableListView historyList =
(ExpandableListView) findViewById(R.id.history_list);
historyList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
public boolean onChildClick(ExpandableListView parent, View view,
int groupPosition, int childPosition, long id) {
handleHistoryItemClick(groupPosition, childPosition);
return true;
}
});
// This is to disallow collapsing the expandable groups in the
// history expandable list view to mimic simpler sections. We should
// Remove this if we decide to allow expanding/collapsing groups.
historyList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
return true;
}
});
historyList.setAdapter(mHistoryAdapter);
expandAllGroups(historyList);
}
}
public AwesomeBarTabs(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(LOGTAG, "Creating AwesomeBarTabs");
mContext = context;
// Load layout into the custom view
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.awesomebar_tabs, this);
// This should be called before adding any tabs
// to the TabHost.
setup();
mListTouchListener = new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
hideSoftInput(view);
return false;
}
};
addAllPagesTab();
addBookmarksTab();
addHistoryTab();
setOnTabChangedListener(new TabHost.OnTabChangeListener() {
@Override
public void onTabChanged(String tabId) {
// Lazy load bookmarks and history lists. Only query the database
// if those lists requested by user.
if (tabId.equals(BOOKMARKS_TAB) && mBookmarksAdapter == null) {
new BookmarksQueryTask().execute();
} else if (tabId.equals(HISTORY_TAB) && mHistoryAdapter == null) {
new HistoryQueryTask().execute();
}
// Always dismiss SKB when changing tabs
View tabView = getCurrentTabView();
hideSoftInput(tabView);
}
});
// Initialize "App Pages" list with no filter
filter("");
}
private TabSpec addAwesomeTab(String id, int titleId, int contentId) {
TabSpec tab = newTabSpec(id);
LayoutInflater inflater =
(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View indicatorView = inflater.inflate(R.layout.awesomebar_tab_indicator, null);
Drawable background = indicatorView.getBackground();
background.setColorFilter(new LightingColorFilter(Color.WHITE, GeckoApp.mBrowserToolbar.getHighlightColor()));
TextView title = (TextView) indicatorView.findViewById(R.id.title);
title.setText(titleId);
tab.setIndicator(indicatorView);
tab.setContent(contentId);
addTab(tab);
return tab;
}
private void addAllPagesTab() {
Log.d(LOGTAG, "Creating All Pages tab");
addAwesomeTab(ALL_PAGES_TAB,
R.string.awesomebar_all_pages_title,
R.id.all_pages_list);
// Load the list using a custom adapter so we can create the bitmaps
mAllPagesAdapter = new SimpleCursorAdapter(
mContext,
R.layout.awesomebar_row,
null,
new String[] { AwesomeBar.TITLE_KEY,
AwesomeBar.URL_KEY,
Browser.BookmarkColumns.FAVICON },
new int[] { R.id.title, R.id.url, R.id.favicon }
);
mAllPagesAdapter.setViewBinder(new AwesomeCursorViewBinder());
mAllPagesAdapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
ContentResolver resolver = mContext.getContentResolver();
return resolver.query(Browser.BOOKMARKS_URI,
null,
// The length restriction on URL is for the same reason as in the general bookmark query
// (see comment earlier in this file).
"(" + Browser.BookmarkColumns.URL + " LIKE ? OR " + Browser.BookmarkColumns.TITLE + " LIKE ?)"
+ " AND LENGTH(" + Browser.BookmarkColumns.URL + ") > 0",
new String[] {"%" + constraint.toString() + "%", "%" + constraint.toString() + "%",},
// ORDER BY is number of visits times a multiplier from 1 - 120 of how recently the site
// was accessed with a site accessed today getting 120 and a site accessed 119 or more
// days ago getting 1
Browser.BookmarkColumns.VISITS + " * MAX(1, (" +
Browser.BookmarkColumns.DATE + " - " + new Date().getTime() + ") / 86400000 + 120) DESC LIMIT " + MAX_RESULTS);
}
});
final ListView allPagesList = (ListView) findViewById(R.id.all_pages_list);
allPagesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
handleItemClick(allPagesList, position);
}
});
allPagesList.setAdapter(mAllPagesAdapter);
allPagesList.setOnTouchListener(mListTouchListener);
}
private void addBookmarksTab() {
Log.d(LOGTAG, "Creating Bookmarks tab");
addAwesomeTab(BOOKMARKS_TAB,
R.string.awesomebar_bookmarks_title,
R.id.bookmarks_list);
ListView bookmarksList = (ListView) findViewById(R.id.bookmarks_list);
bookmarksList.setOnTouchListener(mListTouchListener);
// Only load bookmark list when tab is actually used.
// See OnTabChangeListener above.
}
private void addHistoryTab() {
Log.d(LOGTAG, "Creating History tab");
addAwesomeTab(HISTORY_TAB,
R.string.awesomebar_history_title,
R.id.history_list);
ListView historyList = (ListView) findViewById(R.id.history_list);
historyList.setOnTouchListener(mListTouchListener);
// Only load history list when tab is actually used.
// See OnTabChangeListener above.
}
private void hideSoftInput(View view) {
InputMethodManager imm =
(InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
private void handleHistoryItemClick(int groupPosition, int childPosition) {
@SuppressWarnings("unchecked")
Map<String,Object> historyItem =
(Map<String,Object>) mHistoryAdapter.getChild(groupPosition, childPosition);
String url = (String) historyItem.get(AwesomeBar.URL_KEY);
if (mUrlOpenListener != null)
mUrlOpenListener.onUrlOpen(this, url);
}
private void handleItemClick(ListView list, int position) {
Cursor cursor = (Cursor) list.getItemAtPosition(position);
String url = cursor.getString(cursor.getColumnIndexOrThrow(AwesomeBar.URL_KEY));
if (mUrlOpenListener != null)
mUrlOpenListener.onUrlOpen(this, url);
}
public void setOnUrlOpenListener(OnUrlOpenListener listener) {
mUrlOpenListener = listener;
}
public void destroy() {
Cursor allPagesCursor = mAllPagesAdapter.getCursor();
if (allPagesCursor != null)
allPagesCursor.close();
if (mBookmarksAdapter != null) {
Cursor bookmarksCursor = mBookmarksAdapter.getCursor();
if (bookmarksCursor != null)
bookmarksCursor.close();
}
}
public void filter(String searchTerm) {
// Don't let the tab's content steal focus on tab switch
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
// Ensure the 'All Pages' tab is selected
setCurrentTabByTag(ALL_PAGES_TAB);
// Restore normal focus behavior on tab host
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
// The tabs should only be visible if there's no on-going search
int tabsVisibility = (searchTerm.length() == 0 ? View.VISIBLE : View.GONE);
getTabWidget().setVisibility(tabsVisibility);
// Perform the actual search
mAllPagesAdapter.getFilter().filter(searchTerm);
}
}

Просмотреть файл

@ -0,0 +1,269 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009-2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Matt Brubeck <mbrubeck@mozilla.com>
* Vivien Nicolas <vnicolas@mozilla.com>
* Lucas Rocha <lucasr@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.Typeface;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.animation.TranslateAnimation;
import android.view.Gravity;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextSwitcher;
import android.widget.ViewSwitcher.ViewFactory;
public class BrowserToolbar extends LinearLayout {
final private Button mAwesomeBar;
final private ImageButton mTabs;
final public ImageButton mFavicon;
final public ImageButton mStop;
final public ImageButton mSiteSecurity;
final private AnimationDrawable mProgressSpinner;
final private TextSwitcher mTabsCount;
final private Context mContext;
final private Handler mHandler;
final private int mColor;
final private int mCounterColor;
final private int mDuration;
final private TranslateAnimation mSlideUpIn;
final private TranslateAnimation mSlideUpOut;
final private TranslateAnimation mSlideDownIn;
final private TranslateAnimation mSlideDownOut;
private int mCount;
public BrowserToolbar(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
// Get the device's highlight color
ContextThemeWrapper wrapper = new ContextThemeWrapper(mContext, android.R.style.TextAppearance);
TypedArray typedArray = wrapper.getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorHighlight });
mColor = typedArray.getColor(typedArray.getIndex(0), 0);
// Load layout into the custom view
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.browser_toolbar, this);
mAwesomeBar = (Button) findViewById(R.id.awesome_bar);
mAwesomeBar.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
onAwesomeBarSearch();
}
});
Resources resources = getResources();
int padding[] = { mAwesomeBar.getPaddingLeft(),
mAwesomeBar.getPaddingTop(),
mAwesomeBar.getPaddingRight(),
mAwesomeBar.getPaddingBottom() };
GeckoStateListDrawable states = new GeckoStateListDrawable();
states.initializeFilter(mColor);
states.addState(new int[] { android.R.attr.state_pressed }, resources.getDrawable(R.drawable.address_bar_url_pressed));
states.addState(new int[] { }, resources.getDrawable(R.drawable.address_bar_url_default));
mAwesomeBar.setBackgroundDrawable(states);
mAwesomeBar.setPadding(padding[0], padding[1], padding[2], padding[3]);
mTabs = (ImageButton) findViewById(R.id.tabs);
mTabs.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
if (Tabs.getInstance().getCount() > 1)
showTabs();
else
addTab();
}
});
mTabs.setImageLevel(1);
mCounterColor = 0x99ffffff;
mTabsCount = (TextSwitcher) findViewById(R.id.tabs_count);
mTabsCount.setFactory(new ViewFactory() {
public View makeView() {
TextView text = new TextView(mContext);
text.setGravity(Gravity.CENTER);
text.setTextSize(16);
text.setTextColor(mCounterColor);
text.setTypeface(text.getTypeface(), Typeface.BOLD);
return text;
}
});
mCount = 0;
mTabsCount.setText("0");
mFavicon = (ImageButton) findViewById(R.id.favicon);
mSiteSecurity = (ImageButton) findViewById(R.id.site_security);
mProgressSpinner = (AnimationDrawable) resources.getDrawable(R.drawable.progress_spinner);
mStop = (ImageButton) findViewById(R.id.stop);
mStop.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
doStop();
}
});
mHandler = new Handler();
mSlideUpIn = new TranslateAnimation(0, 0, 30, 0);
mSlideUpOut = new TranslateAnimation(0, 0, 0, -30);
mSlideDownIn = new TranslateAnimation(0, 0, -30, 0);
mSlideDownOut = new TranslateAnimation(0, 0, 0, 30);
mDuration = 750;
mSlideUpIn.setDuration(mDuration);
mSlideUpOut.setDuration(mDuration);
mSlideDownIn.setDuration(mDuration);
mSlideDownOut.setDuration(mDuration);
}
private void onAwesomeBarSearch() {
GeckoApp.mAppContext.onEditRequested();
}
private void addTab() {
GeckoApp.mAppContext.addTab();
}
private void showTabs() {
GeckoApp.mAppContext.showTabs();
}
private void doStop() {
GeckoApp.mAppContext.doStop();
}
public int getHighlightColor() {
return mColor;
}
public void updateTabs(int count) {
if (mCount > count) {
mTabsCount.setInAnimation(mSlideDownIn);
mTabsCount.setOutAnimation(mSlideDownOut);
} else if (mCount < count) {
mTabsCount.setInAnimation(mSlideUpIn);
mTabsCount.setOutAnimation(mSlideUpOut);
}
if (count > 1)
mTabs.setImageLevel(count);
else
mTabs.setImageLevel(0);
mTabsCount.setVisibility(View.VISIBLE);
mTabsCount.setText(String.valueOf(count));
mCount = count;
mHandler.postDelayed(new Runnable() {
public void run() {
((TextView) mTabsCount.getCurrentView()).setTextColor(mColor);
}
}, mDuration);
mHandler.postDelayed(new Runnable() {
public void run() {
if (Tabs.getInstance().getCount() == 1) {
mTabs.setImageLevel(1);
mTabsCount.setVisibility(View.GONE);
((TextView) mTabsCount.getCurrentView()).setTextColor(mCounterColor);
} else {
((TextView) mTabsCount.getCurrentView()).setTextColor(mCounterColor);
}
}
}, 2 * mDuration);
}
public void setProgressVisibility(boolean visible) {
if (visible) {
mFavicon.setImageDrawable(mProgressSpinner);
mProgressSpinner.start();
setStopVisibility(true);
} else {
mProgressSpinner.stop();
setStopVisibility(false);
setFavicon(Tabs.getInstance().getSelectedTab().getFavicon());
}
}
public void setStopVisibility(boolean visible) {
mStop.setVisibility(visible ? View.VISIBLE : View.GONE);
mSiteSecurity.setVisibility(visible ? View.GONE : View.VISIBLE);
}
public void setTitle(CharSequence title) {
mAwesomeBar.setText(title);
}
public void setFavicon(Drawable image) {
if (Tabs.getInstance().getSelectedTab().isLoading())
return;
if (image != null)
mFavicon.setImageDrawable(image);
else
mFavicon.setImageResource(R.drawable.favicon);
}
public void setSecurityMode(String mode) {
if (mode.equals("identified") || mode.equals("verified"))
mSiteSecurity.setImageLevel(1);
else
mSiteSecurity.setImageLevel(0);
}
}

Просмотреть файл

@ -0,0 +1,79 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009-2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brad Lassey <blassey@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import android.content.Context;
import android.preference.DialogPreference;
import android.provider.Browser;
import android.util.AttributeSet;
import android.util.Log;
class ConfirmPreference extends DialogPreference {
private static final String LOGTAG = "GeckoConfirmPreference";
private String mAction = null;
private Context mContext = null;
public ConfirmPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mAction = attrs.getAttributeValue(null, "action");
mContext = context;
}
public ConfirmPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mAction = attrs.getAttributeValue(null, "action");
mContext = context;
}
protected void onDialogClosed(boolean positiveResult) {
if (!positiveResult)
return;
if ("clear_history".equalsIgnoreCase(mAction)) {
GeckoAppShell.getHandler().post(new Runnable(){
public void run() {
Browser.clearHistory(mContext.getContentResolver());
}
});
} else if ("clear_private_data".equalsIgnoreCase(mAction)) {
GeckoAppShell.getHandler().post(new Runnable(){
public void run() {
GeckoAppShell.sendEventToGecko(new GeckoEvent("Sanitize:ClearAll", null));
}
});
}
Log.i(LOGTAG, "action: " + mAction);
}
}

Просмотреть файл

@ -0,0 +1,336 @@
/* -*- 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 <blassey@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#filter substitution
package @ANDROID_PACKAGE_NAME@;
import java.util.HashMap;
import java.util.Map;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import org.mozilla.gecko.R;
public class CrashReporter extends Activity
{
private static final String LOGTAG = "GeckoCrashReporter";
private static final String PASSED_MINI_DUMP_KEY = "minidumpPath";
private static final String MINI_DUMP_PATH_KEY = "upload_file_minidump";
private static final String PAGE_URL_KEY = "URL";
private static final String NOTES_KEY = "Notes";
private static final String SERVER_URL_KEY = "ServerURL";
private static final String CRASH_REPORT_DIR = "/data/data/@ANDROID_PACKAGE_NAME@/files/mozilla/Crash Reports/";
private static final String PENDING_DIR = CRASH_REPORT_DIR + "pending";
private static final String SUBMITTED_DIR = CRASH_REPORT_DIR + "submitted";
private Handler mHandler;
private ProgressDialog mProgressDialog;
private File mPendingMinidumpFile;
private File mPendingExtrasFile;
private HashMap<String, String> mExtrasStringMap;
private boolean moveFile(File inFile, File outFile) {
Log.i(LOGTAG, "moving " + inFile + " to " + outFile);
if (inFile.renameTo(outFile))
return true;
try {
outFile.createNewFile();
Log.i(LOGTAG, "couldn't rename minidump file");
// so copy it instead
FileChannel inChannel = new FileInputStream(inFile).getChannel();
FileChannel outChannel = new FileOutputStream(outFile).getChannel();
long transferred = inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
outChannel.close();
if (transferred > 0)
inFile.delete();
} catch (Exception e) {
Log.e(LOGTAG, "exception while copying minidump file: ", e);
return false;
}
return true;
}
private void doFinish() {
if (mHandler != null) {
mHandler.post(new Runnable() {
public void run() {
finish();
}
});
}
}
@Override
public void finish() {
if (mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
super.finish();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// mHandler is created here so runnables can be run on the main thread
mHandler = new Handler();
setContentView(R.layout.crash_reporter);
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage(getString(R.string.sending_crash_report));
final Button restartButton = (Button) findViewById(R.id.restart);
final Button closeButton = (Button) findViewById(R.id.close);
String passedMinidumpPath = getIntent().getStringExtra(PASSED_MINI_DUMP_KEY);
File passedMinidumpFile = new File(passedMinidumpPath);
File pendingDir = new File(PENDING_DIR);
pendingDir.mkdirs();
mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName());
moveFile(passedMinidumpFile, mPendingMinidumpFile);
File extrasFile = new File(passedMinidumpPath.replaceAll(".dmp", ".extra"));
mPendingExtrasFile = new File(pendingDir, extrasFile.getName());
moveFile(extrasFile, mPendingExtrasFile);
mExtrasStringMap = new HashMap<String, String>();
readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap);
}
private void backgroundSendReport() {
final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report);
if (!sendReportCheckbox.isChecked()) {
doFinish();
return;
}
mProgressDialog.show();
new Thread(new Runnable() {
public void run() {
sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile);
}
}).start();
}
public void onCloseClick(View v) { // bound via crash_reporter.xml
backgroundSendReport();
}
public void onRestartClick(View v) { // bound via crash_reporter.xml
doRestart();
backgroundSendReport();
}
private boolean readStringsFromFile(String filePath, Map<String, String> stringMap) {
try {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
return readStringsFromReader(reader, stringMap);
} catch (Exception e) {
Log.e(LOGTAG, "exception while reading strings: ", e);
return false;
}
}
private boolean readStringsFromReader(BufferedReader reader, Map<String, String> stringMap) throws IOException {
String line;
while ((line = reader.readLine()) != null) {
int equalsPos = -1;
if ((equalsPos = line.indexOf('=')) != -1) {
String key = line.substring(0, equalsPos);
String val = unescape(line.substring(equalsPos + 1));
stringMap.put(key, val);
}
}
reader.close();
return true;
}
private String generateBoundary() {
// Generate some random numbers to fill out the boundary
int r0 = (int)((double)Integer.MAX_VALUE * Math.random());
int r1 = (int)((double)Integer.MAX_VALUE * Math.random());
return String.format("---------------------------%08X%08X", r0, r1);
}
private void sendPart(OutputStream os, String boundary, String name, String data) {
try {
os.write(("--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"" + name + "\"\r\n" +
"\r\n" +
data + "\r\n"
).getBytes());
} catch (Exception ex) {
Log.e(LOGTAG, "Exception when sending \"" + name + "\"", ex);
}
}
private void sendFile(OutputStream os, String boundary, String name, File file) throws IOException {
os.write(("--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"" + name + "\"; " +
"filename=\"" + file.getName() + "\"\r\n" +
"Content-Type: application/octet-stream\r\n" +
"\r\n"
).getBytes());
FileChannel fc = new FileInputStream(file).getChannel();
fc.transferTo(0, fc.size(), Channels.newChannel(os));
fc.close();
}
private void sendReport(File minidumpFile, Map<String, String> extras, File extrasFile) {
Log.i(LOGTAG, "sendReport: " + minidumpFile.getPath());
final CheckBox includeURLCheckbox = (CheckBox) findViewById(R.id.include_url);
String spec = extras.get(SERVER_URL_KEY);
if (spec == null)
doFinish();
Log.i(LOGTAG, "server url: " + spec);
try {
URL url = new URL(spec);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
String boundary = generateBoundary();
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
OutputStream os = conn.getOutputStream();
for (String key : extras.keySet()) {
if (key.equals(PAGE_URL_KEY)) {
if (includeURLCheckbox.isChecked())
sendPart(os, boundary, key, extras.get(key));
} else if (!key.equals(SERVER_URL_KEY) && !key.equals(NOTES_KEY)) {
sendPart(os, boundary, key, extras.get(key));
}
}
// Add some extra information to notes so its displayed by
// crash-stats.mozilla.org. Remove this when bug 607942 is fixed.
StringBuffer sb = new StringBuffer();
sb.append(extras.containsKey(NOTES_KEY) ? extras.get(NOTES_KEY) + "\n" : "");
if (@MOZ_MIN_CPU_VERSION@ < 7)
sb.append("nothumb Build\n");
sb.append(Build.MANUFACTURER).append(' ')
.append(Build.MODEL).append('\n')
.append(Build.FINGERPRINT);
sendPart(os, boundary, NOTES_KEY, sb.toString());
sendPart(os, boundary, "Min_ARM_Version", "@MOZ_MIN_CPU_VERSION@");
sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER);
sendPart(os, boundary, "Android_Model", Build.MODEL);
sendPart(os, boundary, "Android_Board", Build.BOARD);
sendPart(os, boundary, "Android_Brand", Build.BRAND);
sendPart(os, boundary, "Android_Device", Build.DEVICE);
sendPart(os, boundary, "Android_Display", Build.DISPLAY);
sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT);
sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI);
if (Build.VERSION.SDK_INT >= 8) {
try {
sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2);
sendPart(os, boundary, "Android_Hardware", Build.HARDWARE);
} catch (Exception ex) {
Log.e(LOGTAG, "Exception while sending SDK version 8 keys", ex);
}
}
sendPart(os, boundary, "Android_Version", Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
sendFile(os, boundary, MINI_DUMP_PATH_KEY, minidumpFile);
os.write(("\r\n--" + boundary + "--\r\n").getBytes());
os.flush();
os.close();
BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
HashMap<String, String> responseMap = new HashMap<String, String>();
readStringsFromReader(br, responseMap);
if (conn.getResponseCode() == conn.HTTP_OK) {
File submittedDir = new File(SUBMITTED_DIR);
submittedDir.mkdirs();
minidumpFile.delete();
extrasFile.delete();
String crashid = responseMap.get("CrashID");
File file = new File(submittedDir, crashid + ".txt");
FileOutputStream fos = new FileOutputStream(file);
fos.write("Crash ID: ".getBytes());
fos.write(crashid.getBytes());
fos.close();
}
} catch (IOException e) {
Log.e(LOGTAG, "exception during send: ", e);
}
doFinish();
}
private void doRestart() {
try {
String action = "android.intent.action.MAIN";
Intent intent = new Intent(action);
intent.setClassName("@ANDROID_PACKAGE_NAME@",
"@ANDROID_PACKAGE_NAME@.App");
Log.i(LOGTAG, intent.toString());
startActivity(intent);
} catch (Exception e) {
Log.e(LOGTAG, "error while trying to restart", e);
}
}
private String unescape(String string) {
return string.replaceAll("\\\\", "\\").replaceAll("\\n", "\n").replaceAll("\\t", "\t");
}
}

Просмотреть файл

@ -0,0 +1,162 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
* Sriram Ramasubramanian <sriram@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.util.Date;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
import org.json.JSONObject;
import org.json.JSONException;
public class DoorHanger extends LinearLayout implements Button.OnClickListener {
private Context mContext;
private LinearLayout mChoicesLayout;
private TextView mTextView;
private Button mButton;
private LayoutParams mLayoutParams;
public Tab mTab;
// value used to identify the notification
private String mValue;
private int mPersistence = 0;
private long mTimeout = 0;
public DoorHanger(Context aContext, String aValue) {
super(aContext);
mContext = aContext;
mValue = aValue;
setOrientation(VERTICAL);
setBackgroundResource(R.drawable.doorhanger_shadow_bg);
// Load layout into the custom view
LayoutInflater inflater =
(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.doorhanger, this);
hide();
mTextView = (TextView) findViewById(R.id.doorhanger_title);
mChoicesLayout = (LinearLayout) findViewById(R.id.doorhanger_choices);
mLayoutParams = new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT,
1.0f);
}
public void addButton(String aText, int aCallback) {
Button mButton = new Button(mContext);
mButton.setText(aText);
mButton.setTag(Integer.toString(aCallback));
mButton.setOnClickListener(this);
mChoicesLayout.addView(mButton, mLayoutParams);
}
public void onClick(View v) {
GeckoEvent e = new GeckoEvent("Doorhanger:Reply", v.getTag().toString());
GeckoAppShell.sendEventToGecko(e);
mTab.removeDoorHanger(mValue);
// This will hide the doorhanger (and hide the popup if there are no
// more doorhangers to show)
GeckoApp.mDoorHangerPopup.updatePopup();
}
public void show() {
setVisibility(View.VISIBLE);
}
public void hide() {
setVisibility(View.GONE);
}
public boolean isVisible() {
return getVisibility() == View.VISIBLE;
}
public String getValue() {
return mValue;
}
public void setText(String aText) {
mTextView.setText(aText);
}
public Tab getTab() {
return mTab;
}
public void setTab(Tab tab) {
mTab = tab;
}
public void setOptions(JSONObject options) {
try {
mPersistence = options.getInt("persistence");
} catch (JSONException e) { }
try {
mTimeout = options.getLong("timeout");
} catch (JSONException e) { }
}
// This method checks with persistence and timeout options to see if
// it's okay to remove a doorhanger.
public boolean shouldRemove() {
// If persistence is set to -1, the doorhanger will never be
// automatically removed.
if (mPersistence != 0) {
mPersistence--;
return false;
}
if (new Date().getTime() <= mTimeout) {
return false;
}
return true;
}
}

Просмотреть файл

@ -0,0 +1,168 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
* Sriram Ramasubramanian <sriram@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.util.HashMap;
import java.util.Iterator;
import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.RelativeLayout;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;
public class DoorHangerPopup extends PopupWindow {
private static final String LOGTAG = "GeckoDoorHangerPopup";
private Context mContext;
private LinearLayout mContent;
public DoorHangerPopup(Context aContext) {
super(aContext);
mContext = aContext;
setBackgroundDrawable(new BitmapDrawable());
setOutsideTouchable(true);
setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.doorhangerpopup, null);
mContent = (LinearLayout) layout.findViewById(R.id.doorhanger_container);
setContentView(layout);
}
public void addDoorHanger(String message, String value, JSONArray buttons,
Tab tab, JSONObject options) {
Log.i(LOGTAG, "Adding a DoorHanger to Tab: " + tab.getId());
// Replace the doorhanger if it already exists
DoorHanger dh = tab.getDoorHanger(value);
if (dh != null) {
tab.removeDoorHanger(value);
}
dh = new DoorHanger(mContent.getContext(), value);
// Set the doorhanger text and buttons
dh.setText(message);
for (int i = 0; i < buttons.length(); i++) {
try {
JSONObject buttonObject = buttons.getJSONObject(i);
String label = buttonObject.getString("label");
int callBackId = buttonObject.getInt("callback");
dh.addButton(label, callBackId);
} catch (JSONException e) {
Log.i(LOGTAG, "JSON throws " + e);
}
}
dh.setOptions(options);
dh.setTab(tab);
tab.addDoorHanger(value, dh);
mContent.addView(dh);
updatePopup();
}
// Updates popup contents to show doorhangers for the selected tab
public void updatePopup() {
Tab tab = Tabs.getInstance().getSelectedTab();
if (tab == null) {
hidePopup();
return;
}
Log.i(LOGTAG, "Showing all doorhangers for tab: " + tab.getId());
HashMap<String, DoorHanger> doorHangers = tab.getDoorHangers();
// Hide the popup if there aren't any doorhangers to show
if (doorHangers == null || doorHangers.size() == 0) {
hidePopup();
return;
}
// Hide old doorhangers
for (int i = 0; i < mContent.getChildCount(); i++) {
DoorHanger dh = (DoorHanger) mContent.getChildAt(i);
dh.hide();
}
// Show the doorhangers for the tab
for (DoorHanger dh : doorHangers.values()) {
dh.show();
}
showPopup();
}
public void hidePopup() {
if (isShowing()) {
Log.i(LOGTAG, "Hiding the DoorHangerPopup");
dismiss();
}
}
public void showPopup() {
Log.i(LOGTAG, "Showing the DoorHangerPopup");
fixBackgroundForFirst();
if (isShowing())
update();
else
showAsDropDown(GeckoApp.mBrowserToolbar.mFavicon);
}
private void fixBackgroundForFirst() {
for (int i=0; i < mContent.getChildCount(); i++) {
DoorHanger dh = (DoorHanger) mContent.getChildAt(i);
if (dh.isVisible()) {
dh.setBackgroundResource(R.drawable.doorhanger_bg);
break;
}
}
}
}

Просмотреть файл

@ -0,0 +1,424 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Lucas Rocha <lucasr@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.provider.Browser;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Favicons {
private static final String LOGTAG = "GeckoFavicons";
public static final long NOT_LOADING = 0;
private Context mContext;
private DatabaseHelper mDbHelper;
private Map<Long,LoadFaviconTask> mLoadTasks;
private long mNextFaviconLoadId;
public interface OnFaviconLoadedListener {
public void onFaviconLoaded(String url, Drawable favicon);
}
private class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "favicon_urls.db";
private static final String TABLE_NAME = "favicon_urls";
private static final int DATABASE_VERSION = 1;
private static final String COLUMN_ID = "_id";
private static final String COLUMN_FAVICON_URL = "favicon_url";
private static final String COLUMN_PAGE_URL = "page_url";
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
Log.d(LOGTAG, "Creating DatabaseHelper");
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.d(LOGTAG, "Creating database for favicon URLs");
db.execSQL("CREATE TABLE " + TABLE_NAME + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY," +
COLUMN_FAVICON_URL + " TEXT NOT NULL," +
COLUMN_PAGE_URL + " TEXT UNIQUE NOT NULL" +
");");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(LOGTAG, "Upgrading favicon URLs database from version " +
oldVersion + " to " + newVersion + ", which will destroy all old data");
// Drop table completely
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
// Recreate database
onCreate(db);
}
public String getFaviconUrlForPageUrl(String pageUrl) {
Log.d(LOGTAG, "Calling getFaviconUrlForPageUrl() for " + pageUrl);
SQLiteDatabase db = mDbHelper.getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(TABLE_NAME);
Cursor c = qb.query(
db,
new String[] { COLUMN_FAVICON_URL },
COLUMN_PAGE_URL + " = ?",
new String[] { pageUrl },
null, null, null
);
if (!c.moveToFirst()) {
c.close();
return null;
}
String url = c.getString(c.getColumnIndexOrThrow(COLUMN_FAVICON_URL));
c.close();
return url;
}
public void setFaviconUrlForPageUrl(String pageUrl, String faviconUrl) {
Log.d(LOGTAG, "Calling setFaviconUrlForPageUrl() for " + pageUrl);
SQLiteDatabase db = mDbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_FAVICON_URL, faviconUrl);
values.put(COLUMN_PAGE_URL, pageUrl);
db.replace(TABLE_NAME, null, values);
}
}
public Favicons(Context context) {
Log.d(LOGTAG, "Creating Favicons instance");
mContext = context;
mDbHelper = new DatabaseHelper(context);
mLoadTasks = new HashMap<Long,LoadFaviconTask>();
mNextFaviconLoadId = 0;
}
public long loadFavicon(String pageUrl, String faviconUrl,
OnFaviconLoadedListener listener) {
// Handle the case where page url is empty
if (pageUrl == null || pageUrl.length() == 0) {
if (listener != null)
listener.onFaviconLoaded(null, null);
}
LoadFaviconTask task = new LoadFaviconTask(pageUrl, faviconUrl, listener);
long taskId = task.getId();
mLoadTasks.put(taskId, task);
task.execute();
Log.d(LOGTAG, "Calling loadFavicon() with URL = " + pageUrl +
" and favicon URL = " + faviconUrl +
" (" + taskId + ")");
return taskId;
}
public boolean cancelFaviconLoad(long taskId) {
Log.d(LOGTAG, "Requesting cancelation of favicon load (" + taskId + ")");
if (!mLoadTasks.containsKey(taskId))
return false;
Log.d(LOGTAG, "Cancelling favicon load (" + taskId + ")");
LoadFaviconTask task = mLoadTasks.get(taskId);
return task.cancel(false);
}
public void close() {
Log.d(LOGTAG, "Closing Favicons database");
mDbHelper.close();
// Cancel any pending tasks
Set<Long> taskIds = mLoadTasks.keySet();
Iterator iter = taskIds.iterator();
while (iter.hasNext()) {
long taskId = (Long) iter.next();
cancelFaviconLoad(taskId);
}
}
private class LoadFaviconTask extends AsyncTask<Void, Void, BitmapDrawable> {
private long mId;
private String mPageUrl;
private String mFaviconUrl;
private OnFaviconLoadedListener mListener;
public LoadFaviconTask(String pageUrl, String faviconUrl, OnFaviconLoadedListener listener) {
mId = ++mNextFaviconLoadId;
mPageUrl = pageUrl;
mFaviconUrl = faviconUrl;
mListener = listener;
Log.d(LOGTAG, "Creating LoadFaviconTask with URL = " + pageUrl +
" and favicon URL = " + faviconUrl);
}
// Runs in background thread
private BitmapDrawable loadFaviconFromDb() {
Log.d(LOGTAG, "Loading favicon from DB for URL = " + mPageUrl);
ContentResolver resolver = mContext.getContentResolver();
Cursor c = resolver.query(Browser.BOOKMARKS_URI,
new String[] { Browser.BookmarkColumns.FAVICON },
Browser.BookmarkColumns.URL + " = ?",
new String[] { mPageUrl },
null);
if (!c.moveToFirst()) {
c.close();
return null;
}
int faviconIndex = c.getColumnIndexOrThrow(Browser.BookmarkColumns.FAVICON);
byte[] b = c.getBlob(faviconIndex);
c.close();
if (b == null)
return null;
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
Log.d(LOGTAG, "Loaded favicon from DB successfully for URL = " + mPageUrl);
return new BitmapDrawable(bitmap);
}
// Runs in background thread
private void saveFaviconToDb(BitmapDrawable favicon) {
Bitmap bitmap = favicon.getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
ContentValues values = new ContentValues();
values.put(Browser.BookmarkColumns.FAVICON, stream.toByteArray());
values.put(Browser.BookmarkColumns.URL, mPageUrl);
ContentResolver resolver = mContext.getContentResolver();
Log.d(LOGTAG, "Saving favicon on browser database for URL = " + mPageUrl);
resolver.update(Browser.BOOKMARKS_URI,
values,
Browser.BookmarkColumns.URL + " = ?",
new String[] { mPageUrl });
Log.d(LOGTAG, "Saving favicon URL for URL = " + mPageUrl);
mDbHelper.setFaviconUrlForPageUrl(mPageUrl, mFaviconUrl);
}
// Runs in background thread
private BitmapDrawable downloadFavicon(URL faviconUrl) {
Log.d(LOGTAG, "Downloading favicon for URL = " + mPageUrl +
" with favicon URL = " + mFaviconUrl);
// due to android bug 6066, we must download the entire image before using it
// http://code.google.com/p/android/issues/detail?id=6066
HttpURLConnection urlConnection = null;
BufferedInputStream contentStream = null;
ByteArrayInputStream byteStream = null;
BitmapDrawable image = null;
try {
urlConnection = (HttpURLConnection) faviconUrl.openConnection();
int length = urlConnection.getContentLength();
contentStream = new BufferedInputStream(urlConnection.getInputStream(), length);
byte[] bytes = new byte[length];
int pos = 0;
int offset = 0;
while ((pos = contentStream.read(bytes, offset, length - offset)) > 0)
offset += pos;
if (length == offset) {
byteStream = new ByteArrayInputStream(bytes);
image = (BitmapDrawable) Drawable.createFromStream(byteStream, "src");
}
} catch (Exception e) {
Log.d(LOGTAG, "Error downloading favicon: " + e);
} finally {
if (urlConnection != null)
urlConnection.disconnect();
try {
if (contentStream != null)
contentStream.close();
if (byteStream != null)
byteStream.close();
} catch (IOException e) {
Log.d(LOGTAG, "error closing favicon stream");
}
}
if (image != null) {
Log.d(LOGTAG, "Downloaded favicon successfully for URL = " + mPageUrl);
saveFaviconToDb(image);
}
return image;
}
@Override
protected BitmapDrawable doInBackground(Void... unused) {
BitmapDrawable image = null;
URL pageUrl = null;
if (isCancelled())
return null;
// Handle the case of malformed URL
try {
pageUrl = new URL(mPageUrl);
} catch (MalformedURLException e) {
Log.d(LOGTAG, "The provided URL is not valid: " + e);
return null;
}
URL faviconUrl = null;
// Handle the case of malformed favicon URL
try {
// If favicon is empty, fallback to default favicon URI
if (mFaviconUrl == null || mFaviconUrl.length() == 0) {
faviconUrl = new URL(pageUrl.getProtocol(), pageUrl.getAuthority(), "/favicon.ico");
mFaviconUrl = faviconUrl.toString();
} else {
faviconUrl = new URL(mFaviconUrl);
}
} catch (MalformedURLException e) {
Log.d(LOGTAG, "The provided favicon URL is not valid: " + e);
return null;
}
Log.d(LOGTAG, "Favicon URL is now: " + mFaviconUrl);
if (isCancelled())
return null;
String storedFaviconUrl = mDbHelper.getFaviconUrlForPageUrl(mPageUrl);
if (storedFaviconUrl != null && storedFaviconUrl.equals(mFaviconUrl)) {
image = loadFaviconFromDb();
if (isCancelled())
return null;
// If favicon URL is defined but the favicon image is not
// stored in the database for some reason, we force download.
if (image == null) {
image = downloadFavicon(faviconUrl);
}
} else {
image = downloadFavicon(faviconUrl);
}
return image;
}
@Override
protected void onPostExecute(final BitmapDrawable image) {
Log.d(LOGTAG, "LoadFaviconTask finished for URL = " + mPageUrl +
" (" + mId + ")");
mLoadTasks.remove(mId);
if (mListener != null) {
// We want to always run the listener on UI thread
GeckoApp.mAppContext.runOnUiThread(new Runnable() {
public void run() {
mListener.onFaviconLoaded(mPageUrl, image);
}
});
}
}
@Override
protected void onCancelled() {
Log.d(LOGTAG, "LoadFaviconTask cancelled for URL = " + mPageUrl +
" (" + mId + ")");
mLoadTasks.remove(mId);
// Note that we don't call the listener callback if the
// favicon load is cancelled.
}
public long getId() {
return mId;
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Lord <chrislord.net@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.lang.Math;
public final class FloatUtils {
public static boolean fuzzyEquals(float a, float b) {
return (Math.abs(a - b) < 1e-6);
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,57 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brad Lassey <blassey@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
// AsyncTask runs onPostExecute on the thread it is constructed on
// We construct these off of the main thread, and we want that to run
// on the main UI thread, so this is a convenience class to do that
public abstract class GeckoAsyncTask<Params, Progress, Result> {
public void execute(final Params... params) {
GeckoAppShell.getHandler().post(new Runnable() {
public void run() {
final Result result = doInBackground(params);
GeckoApp.mAppContext.runOnUiThread(new Runnable() {
public void run() {
onPostExecute(result);
}});
}});
}
protected abstract Result doInBackground(Params... params);
protected abstract void onPostExecute(Result result);
}

Просмотреть файл

@ -51,6 +51,8 @@ import android.os.BatteryManager;
public class GeckoBatteryManager public class GeckoBatteryManager
extends BroadcastReceiver extends BroadcastReceiver
{ {
private static final String LOGTAG = "GeckoBatteryManager";
// Those constants should be keep in sync with the ones in: // Those constants should be keep in sync with the ones in:
// dom/battery/Constants.h // dom/battery/Constants.h
private final static double kDefaultLevel = 1.0; private final static double kDefaultLevel = 1.0;
@ -66,7 +68,7 @@ public class GeckoBatteryManager
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) { if (!intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
Log.e("GeckoBatteryManager", "Got an unexpected intent!"); Log.e(LOGTAG, "Got an unexpected intent!");
return; return;
} }
@ -77,7 +79,7 @@ public class GeckoBatteryManager
int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
if (plugged == -1) { if (plugged == -1) {
sCharging = kDefaultCharging; sCharging = kDefaultCharging;
Log.e("GeckoBatteryManager", "Failed to get the plugged status!"); Log.e(LOGTAG, "Failed to get the plugged status!");
} else { } else {
// Likely, if plugged > 0, it's likely plugged and charging but the doc // Likely, if plugged > 0, it's likely plugged and charging but the doc
// isn't clear about that. // isn't clear about that.
@ -95,7 +97,7 @@ public class GeckoBatteryManager
double current = (double)intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); double current = (double)intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
double max = (double)intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); double max = (double)intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
if (current == -1 || max == -1) { if (current == -1 || max == -1) {
Log.e("GeckoBatteryManager", "Failed to get battery level!"); Log.e(LOGTAG, "Failed to get battery level!");
sLevel = kDefaultLevel; sLevel = kDefaultLevel;
} else { } else {
sLevel = current / max; sLevel = current / max;
@ -112,14 +114,14 @@ public class GeckoBatteryManager
if (sCharging) { if (sCharging) {
if (dLevel < 0) { if (dLevel < 0) {
Log.w("GeckoBatteryManager", "When charging, level should increase!"); Log.w(LOGTAG, "When charging, level should increase!");
sRemainingTime = kUnknownRemainingTime; sRemainingTime = kUnknownRemainingTime;
} else { } else {
sRemainingTime = Math.round(dt / dLevel * (1.0 - sLevel)); sRemainingTime = Math.round(dt / dLevel * (1.0 - sLevel));
} }
} else { } else {
if (dLevel > 0) { if (dLevel > 0) {
Log.w("GeckoBatteryManager", "When discharging, level should decrease!"); Log.w(LOGTAG, "When discharging, level should decrease!");
sRemainingTime = kUnknownRemainingTime; sRemainingTime = kUnknownRemainingTime;
} else { } else {
sRemainingTime = Math.round(dt / -dLevel * sLevel); sRemainingTime = Math.round(dt / -dLevel * sLevel);

Просмотреть файл

@ -37,12 +37,23 @@
package org.mozilla.gecko; package org.mozilla.gecko;
import android.content.*; import android.content.BroadcastReceiver;
import android.net.*; import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public class GeckoConnectivityReceiver public class GeckoConnectivityReceiver
extends BroadcastReceiver extends BroadcastReceiver
{ {
/*
* Keep the below constants in sync with
* http://mxr.mozilla.org/mozilla-central/source/netwerk/base/public/nsINetworkLinkService.idl
*/
private static final String LINK_DATA_UP = "up";
private static final String LINK_DATA_DOWN = "down";
private static final String LINK_DATA_UNKNOWN = "unknown";
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String status; String status;
@ -50,11 +61,11 @@ public class GeckoConnectivityReceiver
context.getSystemService(Context.CONNECTIVITY_SERVICE); context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo(); NetworkInfo info = cm.getActiveNetworkInfo();
if (info == null) if (info == null)
status = "unknown"; status = LINK_DATA_UNKNOWN;
else if (!info.isConnected()) else if (!info.isConnected())
status = "down"; status = LINK_DATA_DOWN;
else else
status = "up"; status = LINK_DATA_UP;
if (GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning)) if (GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning))
GeckoAppShell.onChangeNetworkLinkStatus(status); GeckoAppShell.onChangeNetworkLinkStatus(status);

Просмотреть файл

@ -55,6 +55,8 @@ import android.util.Log;
*/ */
public class GeckoEvent { public class GeckoEvent {
private static final String LOGTAG = "GeckoEvent";
public static final int INVALID = -1; public static final int INVALID = -1;
public static final int NATIVE_POKE = 0; public static final int NATIVE_POKE = 0;
public static final int KEY_EVENT = 1; public static final int KEY_EVENT = 1;
@ -157,7 +159,7 @@ public class GeckoEvent {
mAlpha = -s.values[0]; mAlpha = -s.values[0];
mBeta = -s.values[1]; mBeta = -s.values[1];
mGamma = -s.values[2]; mGamma = -s.values[2];
Log.i("GeckoEvent", "SensorEvent type = " + s.sensor.getType() + " " + s.sensor.getName() + " " + mAlpha + " " + mBeta + " " + mGamma ); Log.i(LOGTAG, "SensorEvent type = " + s.sensor.getType() + " " + s.sensor.getName() + " " + mAlpha + " " + mBeta + " " + mGamma );
} }
} }
@ -203,14 +205,14 @@ public class GeckoEvent {
rangeForeColor, rangeBackColor); rangeForeColor, rangeBackColor);
} }
public GeckoEvent(int etype, Rect dirty) { public GeckoEvent(int etype, Rect rect) {
if (etype != DRAW) { if (etype != DRAW) {
mType = INVALID; mType = INVALID;
return; return;
} }
mType = etype; mType = etype;
mRect = dirty; mRect = rect;
} }
public GeckoEvent(int etype, int w, int h, int screenw, int screenh) { public GeckoEvent(int etype, int w, int h, int screenw, int screenh) {
@ -235,4 +237,5 @@ public class GeckoEvent {
mType = LOAD_URI; mType = LOAD_URI;
mCharacters = uri; mCharacters = uri;
} }
} }

Просмотреть файл

@ -0,0 +1,44 @@
/* -*- 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):
* Sriram Ramasubramanian <sriram@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import org.json.JSONObject;
public interface GeckoEventListener {
public void handleMessage(String event, JSONObject message);
}

Просмотреть файл

@ -42,6 +42,10 @@ import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
import org.mozilla.gecko.gfx.InputConnectionHandler;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.os.*; import android.os.*;
import android.app.*; import android.app.*;
import android.text.*; import android.text.*;
@ -51,12 +55,18 @@ import android.view.inputmethod.*;
import android.content.*; import android.content.*;
import android.R; import android.R;
import android.text.method.TextKeyListener;
import android.text.method.KeyListener;
import android.util.*; import android.util.*;
public class GeckoInputConnection public class GeckoInputConnection
extends BaseInputConnection extends BaseInputConnection
implements TextWatcher implements TextWatcher, InputConnectionHandler
{ {
private static final String LOGTAG = "GeckoInputConnection";
private class ChangeNotification { private class ChangeNotification {
public String mText; public String mText;
public int mStart; public int mStart;
@ -81,25 +91,31 @@ public class GeckoInputConnection
public GeckoInputConnection (View targetView) { public GeckoInputConnection (View targetView) {
super(targetView, true); super(targetView, true);
mQueryResult = new SynchronousQueue<String>(); mQueryResult = new SynchronousQueue<String>();
mEditableFactory = Editable.Factory.getInstance();
initEditable("");
mIMEState = IME_STATE_DISABLED;
mIMETypeHint = "";
mIMEActionHint = "";
} }
@Override @Override
public boolean beginBatchEdit() { public boolean beginBatchEdit() {
//Log.d("GeckoAppJava", "IME: beginBatchEdit"); Log.d(LOGTAG, "IME: beginBatchEdit");
mBatchMode = true; mBatchMode = true;
return true; return true;
} }
@Override @Override
public boolean commitCompletion(CompletionInfo text) { public boolean commitCompletion(CompletionInfo text) {
//Log.d("GeckoAppJava", "IME: commitCompletion"); Log.d(LOGTAG, "IME: commitCompletion");
return commitText(text.getText(), 1); return commitText(text.getText(), 1);
} }
@Override @Override
public boolean commitText(CharSequence text, int newCursorPosition) { public boolean commitText(CharSequence text, int newCursorPosition) {
//Log.d("GeckoAppJava", "IME: commitText"); Log.d(LOGTAG, "IME: commitText");
setComposingText(text, newCursorPosition); setComposingText(text, newCursorPosition);
finishComposingText(); finishComposingText();
@ -109,7 +125,7 @@ public class GeckoInputConnection
@Override @Override
public boolean deleteSurroundingText(int leftLength, int rightLength) { public boolean deleteSurroundingText(int leftLength, int rightLength) {
//Log.d("GeckoAppJava", "IME: deleteSurroundingText"); Log.d(LOGTAG, "IME: deleteSurroundingText");
if (leftLength == 0 && rightLength == 0) if (leftLength == 0 && rightLength == 0)
return true; return true;
@ -132,7 +148,7 @@ public class GeckoInputConnection
try { try {
mQueryResult.take(); mQueryResult.take();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e("GeckoAppJava", "IME: deleteSurroundingText interrupted", e); Log.e(LOGTAG, "IME: deleteSurroundingText interrupted", e);
return false; return false;
} }
delStart = mSelectionStart > leftLength ? delStart = mSelectionStart > leftLength ?
@ -157,18 +173,24 @@ public class GeckoInputConnection
GeckoAppShell.sendEventToGecko( GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0)); new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0));
} }
// Temporarily disable text change notifications which confuse some IMEs (SlideIT, for example)
// in the middle of text update.
// They will be re-enabled on the next setComposingText
disableChangeNotifications();
return true; return true;
} }
@Override @Override
public boolean endBatchEdit() { public boolean endBatchEdit() {
//Log.d("GeckoAppJava", "IME: endBatchEdit"); Log.d(LOGTAG, "IME: endBatchEdit");
mBatchMode = false; mBatchMode = false;
if (!mBatchChanges.isEmpty()) { if (!mBatchChanges.isEmpty()) {
InputMethodManager imm = (InputMethodManager) InputMethodManager imm = (InputMethodManager)
GeckoApp.surfaceView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); GeckoApp.mAppContext.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) { if (imm != null) {
for (ChangeNotification n : mBatchChanges) { for (ChangeNotification n : mBatchChanges) {
if (n.mText != null) if (n.mText != null)
@ -184,7 +206,7 @@ public class GeckoInputConnection
@Override @Override
public boolean finishComposingText() { public boolean finishComposingText() {
//Log.d("GeckoAppJava", "IME: finishComposingText"); Log.d(LOGTAG, "IME: finishComposingText");
if (mComposing) { if (mComposing) {
// Set style to none // Set style to none
@ -209,14 +231,14 @@ public class GeckoInputConnection
@Override @Override
public int getCursorCapsMode(int reqModes) { public int getCursorCapsMode(int reqModes) {
//Log.d("GeckoAppJava", "IME: getCursorCapsMode"); Log.d(LOGTAG, "IME: getCursorCapsMode");
return 0; return 0;
} }
@Override @Override
public Editable getEditable() { public Editable getEditable() {
Log.w("GeckoAppJava", "IME: getEditable called from " + Log.w(LOGTAG, "IME: getEditable called from " +
Thread.currentThread().getStackTrace()[0].toString()); Thread.currentThread().getStackTrace()[0].toString());
return null; return null;
@ -224,7 +246,7 @@ public class GeckoInputConnection
@Override @Override
public boolean performContextMenuAction(int id) { public boolean performContextMenuAction(int id) {
//Log.d("GeckoAppJava", "IME: performContextMenuAction"); Log.d(LOGTAG, "IME: performContextMenuAction");
// First we need to ask Gecko to tell us the full contents of the // First we need to ask Gecko to tell us the full contents of the
// text field we're about to operate on. // text field we're about to operate on.
@ -234,7 +256,7 @@ public class GeckoInputConnection
try { try {
text = mQueryResult.take(); text = mQueryResult.take();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e("GeckoAppJava", "IME: performContextMenuAction interrupted", e); Log.e(LOGTAG, "IME: performContextMenuAction interrupted", e);
return false; return false;
} }
@ -264,7 +286,7 @@ public class GeckoInputConnection
try { try {
text = mQueryResult.take(); text = mQueryResult.take();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e("GeckoAppJava", "IME: performContextMenuAction interrupted", e); Log.e(LOGTAG, "IME: performContextMenuAction interrupted", e);
return false; return false;
} }
} }
@ -284,7 +306,7 @@ public class GeckoInputConnection
if (!GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning)) if (!GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning))
return null; return null;
//Log.d("GeckoAppJava", "IME: getExtractedText"); Log.d(LOGTAG, "IME: getExtractedText");
ExtractedText extract = new ExtractedText(); ExtractedText extract = new ExtractedText();
extract.flags = 0; extract.flags = 0;
@ -296,7 +318,7 @@ public class GeckoInputConnection
try { try {
mQueryResult.take(); mQueryResult.take();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e("GeckoAppJava", "IME: getExtractedText interrupted", e); Log.e(LOGTAG, "IME: getExtractedText interrupted", e);
return null; return null;
} }
extract.selectionStart = mSelectionStart; extract.selectionStart = mSelectionStart;
@ -329,21 +351,21 @@ public class GeckoInputConnection
return extract; return extract;
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e("GeckoAppJava", "IME: getExtractedText interrupted", e); Log.e(LOGTAG, "IME: getExtractedText interrupted", e);
return null; return null;
} }
} }
@Override @Override
public CharSequence getTextAfterCursor(int length, int flags) { public CharSequence getTextAfterCursor(int length, int flags) {
//Log.d("GeckoAppJava", "IME: getTextAfterCursor"); Log.d(LOGTAG, "IME: getTextAfterCursor");
GeckoAppShell.sendEventToGecko( GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0)); new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
try { try {
mQueryResult.take(); mQueryResult.take();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e("GeckoAppJava", "IME: getTextBefore/AfterCursor interrupted", e); Log.e(LOGTAG, "IME: getTextBefore/AfterCursor interrupted", e);
return null; return null;
} }
@ -366,27 +388,43 @@ public class GeckoInputConnection
try { try {
return mQueryResult.take(); return mQueryResult.take();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e("GeckoAppJava", "IME: getTextBefore/AfterCursor: Interrupted!", e); Log.e(LOGTAG, "IME: getTextBefore/AfterCursor: Interrupted!", e);
return null; return null;
} }
} }
@Override @Override
public CharSequence getTextBeforeCursor(int length, int flags) { public CharSequence getTextBeforeCursor(int length, int flags) {
//Log.d("GeckoAppJava", "IME: getTextBeforeCursor"); Log.d(LOGTAG, "IME: getTextBeforeCursor");
return getTextAfterCursor(-length, flags); return getTextAfterCursor(-length, flags);
} }
@Override @Override
public boolean setComposingText(CharSequence text, int newCursorPosition) { public boolean setComposingText(CharSequence text, int newCursorPosition) {
//Log.d("GeckoAppJava", "IME: setComposingText"); Log.d(LOGTAG, "IME: setComposingText");
enableChangeNotifications();
// Set new composing text // Set new composing text
mComposingText = text != null ? text.toString() : ""; mComposingText = text != null ? text.toString() : "";
if (!mComposing) { if (!mComposing) {
// Get current selection
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
try {
mQueryResult.take();
} catch (InterruptedException e) {
Log.e(LOGTAG, "IME: setComposingText interrupted", e);
return false;
}
if (mComposingText.length() == 0) { if (mComposingText.length() == 0) {
// Empty composing text is usually sent by IME to delete the selection (for example, ezKeyboard)
if (mSelectionLength > 0)
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.IME_DELETE_TEXT, 0, 0));
// Some IMEs such as iWnn sometimes call with empty composing // Some IMEs such as iWnn sometimes call with empty composing
// text. (See bug 664364) // text. (See bug 664364)
// If composing text is empty, ignore this and don't start // If composing text is empty, ignore this and don't start
@ -394,15 +432,6 @@ public class GeckoInputConnection
return true; return true;
} }
// Get current selection
GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_GET_SELECTION, 0, 0));
try {
mQueryResult.take();
} catch (InterruptedException e) {
Log.e("GeckoAppJava", "IME: setComposingText interrupted", e);
return false;
}
// Make sure we are in a composition // Make sure we are in a composition
GeckoAppShell.sendEventToGecko( GeckoAppShell.sendEventToGecko(
new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0)); new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0));
@ -507,7 +536,7 @@ public class GeckoInputConnection
@Override @Override
public boolean setComposingRegion(int start, int end) { public boolean setComposingRegion(int start, int end) {
//Log.d("GeckoAppJava", "IME: setComposingRegion(start=" + start + ", end=" + end + ")"); Log.d(LOGTAG, "IME: setComposingRegion(start=" + start + ", end=" + end + ")");
if (start < 0 || end < start) if (start < 0 || end < start)
return true; return true;
@ -525,7 +554,7 @@ public class GeckoInputConnection
try { try {
text = mQueryResult.take(); text = mQueryResult.take();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e("GeckoAppJava", "IME: setComposingRegion interrupted", e); Log.e(LOGTAG, "IME: setComposingRegion interrupted", e);
return false; return false;
} }
} }
@ -541,7 +570,7 @@ public class GeckoInputConnection
@Override @Override
public boolean setSelection(int start, int end) { public boolean setSelection(int start, int end) {
//Log.d("GeckoAppJava", "IME: setSelection"); Log.d(LOGTAG, "IME: setSelection");
if (mComposing) { if (mComposing) {
/* Translate to fake selection positions */ /* Translate to fake selection positions */
@ -589,8 +618,10 @@ public class GeckoInputConnection
public void notifyTextChange(InputMethodManager imm, String text, public void notifyTextChange(InputMethodManager imm, String text,
int start, int oldEnd, int newEnd) { int start, int oldEnd, int newEnd) {
// Log.d("GeckoAppShell", String.format("IME: notifyTextChange: text=%s s=%d ne=%d oe=%d", Log.d(LOGTAG, String.format("IME: notifyTextChange: text=%s s=%d ne=%d oe=%d",
// text, start, newEnd, oldEnd)); text, start, newEnd, oldEnd));
if (!mChangeNotificationsEnabled)
return;
if (mBatchMode) { if (mBatchMode) {
mBatchChanges.add(new ChangeNotification(text, start, oldEnd, newEnd)); mBatchChanges.add(new ChangeNotification(text, start, oldEnd, newEnd));
@ -601,8 +632,10 @@ public class GeckoInputConnection
// If there are pending changes, that means this text is not the most up-to-date version // If there are pending changes, that means this text is not the most up-to-date version
// and we'll step on ourselves if we change the editable right now. // and we'll step on ourselves if we change the editable right now.
if (mNumPendingChanges == 0 && !text.contentEquals(GeckoApp.surfaceView.mEditable)) View v = GeckoApp.mAppContext.getLayerController().getView();
GeckoApp.surfaceView.setEditable(text);
if (mNumPendingChanges == 0 && !text.contentEquals(mEditable))
setEditable(text);
if (mUpdateRequest == null) if (mUpdateRequest == null)
return; return;
@ -621,34 +654,38 @@ public class GeckoInputConnection
mUpdateExtract.text = text.substring(0, newEnd); mUpdateExtract.text = text.substring(0, newEnd);
mUpdateExtract.startOffset = 0; mUpdateExtract.startOffset = 0;
imm.updateExtractedText(GeckoApp.surfaceView, imm.updateExtractedText(v, mUpdateRequest.token, mUpdateExtract);
mUpdateRequest.token, mUpdateExtract);
} }
public void notifySelectionChange(InputMethodManager imm, public void notifySelectionChange(InputMethodManager imm,
int start, int end) { int start, int end) {
// Log.d("GeckoAppJava", String.format("IME: notifySelectionChange: s=%d e=%d", start, end)); Log.d(LOGTAG, String.format("IME: notifySelectionChange: s=%d e=%d", start, end));
if (!mChangeNotificationsEnabled)
return;
if (mBatchMode) { if (mBatchMode) {
mBatchChanges.add(new ChangeNotification(start, end)); mBatchChanges.add(new ChangeNotification(start, end));
return; return;
} }
View v = GeckoApp.mAppContext.getLayerController().getView();
if (mComposing) if (mComposing)
imm.updateSelection(GeckoApp.surfaceView, imm.updateSelection(v,
mCompositionStart + mCompositionSelStart, mCompositionStart + mCompositionSelStart,
mCompositionStart + mCompositionSelStart + mCompositionSelLen, mCompositionStart + mCompositionSelStart + mCompositionSelLen,
mCompositionStart, mCompositionStart,
mCompositionStart + mComposingText.length()); mCompositionStart + mComposingText.length());
else else
imm.updateSelection(GeckoApp.surfaceView, start, end, -1, -1); imm.updateSelection(v, start, end, -1, -1);
// We only change the selection if we are relatively sure that the text we have is // We only change the selection if we are relatively sure that the text we have is
// up-to-date. Bail out if we are stil expecting changes. // up-to-date. Bail out if we are stil expecting changes.
if (mNumPendingChanges > 0) if (mNumPendingChanges > 0)
return; return;
int maxLen = GeckoApp.surfaceView.mEditable.length(); int maxLen = mEditable.length();
Selection.setSelection(GeckoApp.surfaceView.mEditable, Selection.setSelection(mEditable,
Math.min(start, maxLen), Math.min(start, maxLen),
Math.min(end, maxLen)); Math.min(end, maxLen));
} }
@ -665,8 +702,8 @@ public class GeckoInputConnection
// TextWatcher // TextWatcher
public void onTextChanged(CharSequence s, int start, int before, int count) public void onTextChanged(CharSequence s, int start, int before, int count)
{ {
// Log.d("GeckoAppShell", String.format("IME: onTextChanged: t=%s s=%d b=%d l=%d", Log.d(LOGTAG, String.format("IME: onTextChanged: t=%s s=%d b=%d l=%d",
// s, start, before, count)); s, start, before, count));
mNumPendingChanges++; mNumPendingChanges++;
GeckoAppShell.sendEventToGecko( GeckoAppShell.sendEventToGecko(
@ -705,6 +742,340 @@ public class GeckoInputConnection
{ {
} }
private void disableChangeNotifications() {
mChangeNotificationsEnabled = false;
}
private void enableChangeNotifications() {
mChangeNotificationsEnabled = true;
}
public InputConnection onCreateInputConnection(EditorInfo outAttrs)
{
Log.d(LOGTAG, "IME: handleCreateInputConnection called");
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;
reset();
return this;
}
public boolean onKeyPreIme(int keyCode, KeyEvent 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 false;
}
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_MENU:
case KeyEvent.KEYCODE_BACK:
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 (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;
View v = GeckoApp.mAppContext.getLayerController().getView();
// 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(v, mEditable, keyCode, event))
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
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:
case KeyEvent.KEYCODE_SEARCH:
case KeyEvent.KEYCODE_MENU:
return false;
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;
View v = GeckoApp.mAppContext.getLayerController().getView();
if (mIMEState == IME_STATE_DISABLED ||
keyCode == KeyEvent.KEYCODE_ENTER ||
keyCode == KeyEvent.KEYCODE_DEL ||
(event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 ||
!mKeyListener.onKeyUp(v, mEditable, keyCode, event))
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
View v = GeckoApp.mAppContext.getLayerController().getView();
switch (keyCode) {
case KeyEvent.KEYCODE_MENU:
InputMethodManager imm = (InputMethodManager)
v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInputFromWindow(v.getWindowToken(),
imm.SHOW_FORCED, 0);
return true;
default:
break;
}
return false;
}
public void notifyIME(int type, int state) {
View v = GeckoApp.mAppContext.getLayerController().getView();
Log.d(LOGTAG, "notifyIME");
if (v == null)
return;
Log.d(LOGTAG, "notifyIME v!= null");
switch (type) {
case NOTIFY_IME_RESETINPUTSTATE:
Log.d(LOGTAG, "notifyIME = reset");
// Composition event is already fired from widget.
// So reset IME flags.
reset();
// Don't use IMEStateUpdater for reset.
// Because IME may not work showSoftInput()
// after calling restartInput() immediately.
// So we have to call showSoftInput() delay.
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
// no way to reset IME status directly
IMEStateUpdater.resetIME();
} else {
imm.restartInput(v);
}
// keep current enabled state
IMEStateUpdater.enableIME();
break;
case NOTIFY_IME_CANCELCOMPOSITION:
Log.d(LOGTAG, "notifyIME = cancel");
IMEStateUpdater.resetIME();
break;
case NOTIFY_IME_FOCUSCHANGE:
Log.d(LOGTAG, "notifyIME = focus");
IMEStateUpdater.resetIME();
break;
}
}
public void notifyIMEEnabled(int state, String typeHint,
String actionHint, boolean landscapeFS)
{
View v = GeckoApp.mAppContext.getLayerController().getView();
if (v == null)
return;
/* When IME is 'disabled', IME processing is disabled.
In addition, the IME UI is hidden */
mIMEState = state;
mIMETypeHint = typeHint;
mIMEActionHint = actionHint;
mIMELandscapeFS = landscapeFS;
IMEStateUpdater.enableIME();
}
public void notifyIMEChange(String text, int start, int end, int newEnd) {
View v = GeckoApp.mAppContext.getLayerController().getView();
if (v == null)
return;
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null)
return;
Log.d(LOGTAG, String.format("IME: notifyIMEChange: t=%s s=%d ne=%d oe=%d",
text, start, newEnd, end));
if (newEnd < 0)
notifySelectionChange(imm, start, end);
else
notifyTextChange(imm, text, start, end, newEnd);
}
public void returnIMEQueryResult(String result, int selectionStart, int selectionLength) {
mSelectionStart = selectionStart;
mSelectionLength = selectionLength;
try {
mQueryResult.put(result);
} catch (InterruptedException e) {}
}
static private final Timer mIMETimer = new Timer();
static private final int NOTIFY_IME_RESETINPUTSTATE = 0;
static private final int NOTIFY_IME_SETOPENSTATE = 1;
static private final int NOTIFY_IME_CANCELCOMPOSITION = 2;
static private final int NOTIFY_IME_FOCUSCHANGE = 3;
/* Delay updating IME states (see bug 573800) */
private static final class IMEStateUpdater extends TimerTask
{
static private IMEStateUpdater instance;
private boolean mEnable, mReset;
static private IMEStateUpdater getInstance() {
if (instance == null) {
instance = new IMEStateUpdater();
mIMETimer.schedule(instance, 200);
}
return instance;
}
static public synchronized void enableIME() {
getInstance().mEnable = true;
}
static public synchronized void resetIME() {
getInstance().mReset = true;
}
public void run() {
Log.d(LOGTAG, "IME: run()");
synchronized(IMEStateUpdater.class) {
instance = null;
}
View v = GeckoApp.mAppContext.getLayerController().getView();
Log.d(LOGTAG, "IME: v="+v);
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null)
return;
if (mReset)
imm.restartInput(v);
if (!mEnable)
return;
if (mIMEState != IME_STATE_DISABLED &&
mIMEState != IME_STATE_PLUGIN)
imm.showSoftInput(v, 0);
else
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
public void setEditable(String contents)
{
mEditable.removeSpan(this);
mEditable.replace(0, mEditable.length(), contents);
mEditable.setSpan(this, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
Selection.setSelection(mEditable, contents.length());
}
public void initEditable(String contents)
{
mEditable = mEditableFactory.newEditable(contents);
mEditable.setSpan(this, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
Selection.setSelection(mEditable, contents.length());
}
// Is a composition active? // Is a composition active?
boolean mComposing; boolean mComposing;
// Composition text when a composition is active // Composition text when a composition is active
@ -720,7 +1091,23 @@ public class GeckoInputConnection
// Number of in flight changes // Number of in flight changes
int mNumPendingChanges; int mNumPendingChanges;
boolean mBatchMode; // 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;
KeyListener mKeyListener;
Editable mEditable;
Editable.Factory mEditableFactory;
static int mIMEState;
static String mIMETypeHint;
static String mIMEActionHint;
static boolean mIMELandscapeFS;
private boolean mBatchMode;
private boolean mChangeNotificationsEnabled = true;
private CopyOnWriteArrayList<ChangeNotification> mBatchChanges = private CopyOnWriteArrayList<ChangeNotification> mBatchChanges =
new CopyOnWriteArrayList<ChangeNotification>(); new CopyOnWriteArrayList<ChangeNotification>();

Просмотреть файл

@ -0,0 +1,212 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alex Pakhotin <alexp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.util.ArrayList;
import android.os.Build;
import android.os.Bundle;
import android.content.res.Resources;
import android.content.Context;
import android.preference.*;
import android.preference.Preference.*;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import org.json.*;
public class GeckoPreferences
extends PreferenceActivity
implements OnPreferenceChangeListener
{
private static final String LOGTAG = "GeckoPreferences";
private static Context sContext;
private static JSONArray sJSONPrefs = null;
private ArrayList<String> mPreferencesList = new ArrayList<String>();
private PreferenceScreen mPreferenceScreen;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sContext = this;
if (Build.VERSION.SDK_INT >= 11)
getActionBar().setDisplayHomeAsUpEnabled(true);
addPreferencesFromResource(R.xml.preferences);
mPreferenceScreen = getPreferenceScreen();
initGroups(mPreferenceScreen);
// setData() must have been called already
if (sJSONPrefs != null)
refresh();
}
private void initGroups(PreferenceGroup preferences) {
final int count = preferences.getPreferenceCount();
for (int i = 0; i < count; i++) {
Preference pref = preferences.getPreference(i);
if (pref instanceof PreferenceGroup)
initGroups((PreferenceGroup)pref);
else {
pref.setOnPreferenceChangeListener(this);
mPreferencesList.add(pref.getKey());
}
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String prefName = preference.getKey();
setPreference(prefName, newValue);
if (preference instanceof ListPreference)
((ListPreference)preference).setSummary((String)newValue);
return true;
}
public static void setData(JSONArray jsonPrefs) {
sJSONPrefs = jsonPrefs;
}
public static boolean isLoaded() {
return sJSONPrefs != null;
}
// Update the preferences UI with our in-memory JSON preferences object
private void refresh() {
try {
// set the current page URL for the "Home page" preference
final String[] homepageValues = sContext.getResources().getStringArray(R.array.pref_homepage_values);
final Preference homepagePref = mPreferenceScreen.findPreference("browser.startup.homepage");
GeckoAppShell.getMainHandler().post(new Runnable() {
public void run() {
Tab tab = Tabs.getInstance().getSelectedTab();
homepageValues[2] = tab.getURL();
((ListPreference)homepagePref).setEntryValues(homepageValues);
}
});
final int length = sJSONPrefs.length();
for (int i = 0; i < length; i++) {
JSONObject jPref = sJSONPrefs.getJSONObject(i);
final String prefName = jPref.getString("name");
final String prefType = jPref.getString("type");
final Preference pref = mPreferenceScreen.findPreference(prefName);
if (prefName.equals("browser.startup.homepage")) {
final String value = jPref.getString("value");
GeckoAppShell.getMainHandler().post(new Runnable() {
public void run() {
pref.setSummary(value);
}
});
}
if (pref instanceof CheckBoxPreference && "bool".equals(prefType)) {
final boolean value = jPref.getBoolean("value");
GeckoAppShell.getMainHandler().post(new Runnable() {
public void run() {
if (((CheckBoxPreference)pref).isChecked() != value)
((CheckBoxPreference)pref).setChecked(value);
}
});
} else if (pref instanceof EditTextPreference && "string".equals(prefType)) {
final String value = jPref.getString("value");
GeckoAppShell.getMainHandler().post(new Runnable() {
public void run() {
((EditTextPreference)pref).setText(value);
}
});
} else if (pref instanceof ListPreference && "string".equals(prefType)) {
final String value = jPref.getString("value");
GeckoAppShell.getMainHandler().post(new Runnable() {
public void run() {
((ListPreference)pref).setValue(value);
}
});
}
}
} catch (JSONException e) {
Log.e(LOGTAG, "Problem parsing preferences response: ", e);
}
}
public static void setPreference(String pref, Object value) {
// update the in-memory preferences cache
JSONObject jsonPref = null;
try {
for (int i = 0; i < sJSONPrefs.length(); i++) {
if (sJSONPrefs.getJSONObject(i).getString("name").equals(pref)) {
jsonPref = sJSONPrefs.getJSONObject(i);
if (value instanceof Boolean)
jsonPref.put("value", ((Boolean)value).booleanValue());
else if (value instanceof Integer)
jsonPref.put("value", ((Integer)value).intValue());
else
jsonPref.put("value", String.valueOf(value));
break;
}
}
} catch (JSONException e) {
Log.e(LOGTAG, "JSON exception: ", e);
return;
}
if (jsonPref == null) {
Log.e(LOGTAG, "invalid preference given to setPreference()");
return;
}
// send the Preferences:Set message to Gecko
GeckoEvent event = new GeckoEvent("Preferences:Set", jsonPref.toString());
GeckoAppShell.sendEventToGecko(event);
}
}

Просмотреть файл

@ -0,0 +1,64 @@
/* -*- 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):
* Sriram Ramasubramanian <sriram@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import android.graphics.Color;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.StateListDrawable;
import android.graphics.LightingColorFilter;
public class GeckoStateListDrawable extends StateListDrawable {
private LightingColorFilter mFilter;
public void initializeFilter(int color) {
mFilter = new LightingColorFilter(Color.WHITE, color);
}
@Override
protected boolean onStateChange(int[] stateSet) {
for (int state: stateSet) {
if (state == android.R.attr.state_pressed || state == android.R.attr.state_focused) {
super.onStateChange(stateSet);
((LayerDrawable) getCurrent()).getDrawable(0).setColorFilter(mFilter);
return true;
}
}
return super.onStateChange(stateSet);
}
}

Просмотреть файл

@ -0,0 +1,127 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brad Lassey <blassey@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.content.res.Configuration;
import android.util.Log;
import android.widget.AbsoluteLayout;
import java.io.File;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.Locale;
public class GeckoThread extends Thread {
private static final String LOGTAG = "GeckoThread";
Intent mIntent;
GeckoThread (Intent intent) {
mIntent = intent;
}
public void run() {
final GeckoApp app = GeckoApp.mAppContext;
Intent intent = mIntent;
File cacheFile = GeckoAppShell.getCacheDir();
File libxulFile = new File(cacheFile, "libxul.so");
if ((!libxulFile.exists() ||
new File(app.getApplication().getPackageResourcePath()).lastModified() >= libxulFile.lastModified())) {
File[] libs = cacheFile.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".so");
}
});
if (libs != null) {
for (int i = 0; i < libs.length; i++) {
libs[i].delete();
}
}
}
// At some point while loading the gecko libs our default locale gets set
// so just save it to locale here and reset it as default after the join
Locale locale = Locale.getDefault();
GeckoAppShell.loadGeckoLibs(
app.getApplication().getPackageResourcePath());
Locale.setDefault(locale);
Resources res = app.getBaseContext().getResources();
Configuration config = res.getConfiguration();
config.locale = locale;
res.updateConfiguration(config, res.getDisplayMetrics());
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - runGecko");
// and then fire us up
try {
String uri = intent.getDataString();
String title = uri;
if (!app.mUserDefinedProfile &&
(uri == null || uri.length() == 0)) {
SharedPreferences prefs = app.getSharedPreferences("GeckoApp", app.MODE_PRIVATE);
uri = prefs.getString("last-uri", "");
title = prefs.getString("last-title", uri);
}
final String awesomeTitle = title;
app.mMainHandler.post(new Runnable() {
public void run() {
app.mBrowserToolbar.setTitle(awesomeTitle);
}
});
Log.w(LOGTAG, "RunGecko - URI = " + uri);
GeckoAppShell.runGecko(app.getApplication().getPackageResourcePath(),
intent.getStringExtra("args"),
uri);
} catch (Exception e) {
Log.e(LOGTAG, "top level exception", e);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
GeckoAppShell.reportJavaCrash(sw.toString());
}
}
}

Просмотреть файл

@ -0,0 +1,149 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kartikaya Gupta <kgupta@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.lang.ref.SoftReference;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Handler;
import android.provider.Browser;
import android.util.Log;
class GlobalHistory {
private static final String LOGTAG = "GeckoGlobalHistory";
private static GlobalHistory sInstance = new GlobalHistory();
static GlobalHistory getInstance() {
return sInstance;
}
// this is the delay between receiving a URI check request and processing it.
// this allows batching together multiple requests and processing them together,
// which is more efficient.
private static final long BATCHING_DELAY_MS = 100;
private final Handler mHandler; // a background thread on which we can process requests
private final Queue<String> mPendingUris; // URIs that need to be checked
private SoftReference<Set<String>> mVisitedCache; // cache of the visited URI list
private final Runnable mNotifierRunnable; // off-thread runnable used to check URIs
private boolean mProcessing; // = false // whether or not the runnable is queued/working
private GlobalHistory() {
mHandler = GeckoAppShell.getHandler();
mPendingUris = new LinkedList<String>();
mVisitedCache = new SoftReference<Set<String>>(null);
mNotifierRunnable = new Runnable() {
public void run() {
Set<String> visitedSet = mVisitedCache.get();
if (visitedSet == null) {
// the cache was wiped away, repopulate it
Log.w(LOGTAG, "Rebuilding visited link set...");
visitedSet = new HashSet<String>();
Cursor c = GeckoApp.mAppContext.getContentResolver().query(Browser.BOOKMARKS_URI,
new String[] { Browser.BookmarkColumns.URL },
Browser.BookmarkColumns.BOOKMARK + "=0 AND " +
Browser.BookmarkColumns.VISITS + ">0",
null,
null);
if (c.moveToFirst()) {
do {
visitedSet.add(c.getString(0));
} while (c.moveToNext());
}
mVisitedCache = new SoftReference<Set<String>>(visitedSet);
c.close();
}
// this runs on the same handler thread as the checkUriVisited code,
// so no synchronization needed
while (true) {
String uri = mPendingUris.poll();
if (uri == null) {
break;
}
if (visitedSet.contains(uri)) {
GeckoAppShell.notifyUriVisited(uri);
}
}
mProcessing = false;
}
};
}
public void add(String uri) {
Browser.updateVisitedHistory(GeckoApp.mAppContext.getContentResolver(), uri, true);
Set<String> visitedSet = mVisitedCache.get();
if (visitedSet != null) {
visitedSet.add(uri);
}
GeckoAppShell.notifyUriVisited(uri);
}
public void update(String uri, String title) {
ContentValues values = new ContentValues();
values.put(Browser.BookmarkColumns.TITLE, title);
GeckoApp.mAppContext.getContentResolver().update(
Browser.BOOKMARKS_URI,
values,
Browser.BookmarkColumns.URL + " = ?",
new String[] { uri });
}
public void checkUriVisited(final String uri) {
mHandler.post(new Runnable() {
public void run() {
// this runs on the same handler thread as the processing loop,
// so synchronization needed
mPendingUris.add(uri);
if (mProcessing) {
// there's already a runnable queued up or working away, so
// no need to post another
return;
}
mProcessing = true;
mHandler.postDelayed(mNotifierRunnable, BATCHING_DELAY_MS);
}
});
}
}

Просмотреть файл

@ -195,7 +195,7 @@ public class LauncherShortcuts extends Activity {
try { try {
JSONObject webApps = (JSONObject) new JSONTokener(webappsJson).nextValue(); JSONObject webApps = (JSONObject) new JSONTokener(webappsJson).nextValue();
Iterator<Object> appKeys = webApps.keys(); Iterator appKeys = webApps.keys();
HashMap<String, String> map; HashMap<String, String> map;
while (appKeys.hasNext()) { while (appKeys.hasNext()) {
@ -235,7 +235,6 @@ public class LauncherShortcuts extends Activity {
new String[] { "favicon", "title" }, new String[] { "favicon", "title" },
new int[] { R.id.favicon, R.id.title } new int[] { R.id.favicon, R.id.title }
), new DialogInterface.OnClickListener() { ), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
dialog.dismiss(); dialog.dismiss();
onListItemClick(id); onListItemClick(id);
@ -244,7 +243,6 @@ public class LauncherShortcuts extends Activity {
}); });
builder.setOnCancelListener(new DialogInterface.OnCancelListener() { builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
dialog.dismiss(); dialog.dismiss();
finish(); finish();

Просмотреть файл

@ -0,0 +1,502 @@
# ***** 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 <vladimir@pobox.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/ipc/app/defs.mk
DIRS = locales
DIST_FILES = package-name.txt
JAVAFILES = \
AlertNotification.java \
AwesomeBar.java \
AwesomeBarTabs.java \
BrowserToolbar.java \
ConfirmPreference.java \
DoorHanger.java \
DoorHangerPopup.java \
Favicons.java \
FloatUtils.java \
GeckoApp.java \
GeckoAppShell.java \
GeckoConnectivityReceiver.java \
GeckoEvent.java \
GeckoEventListener.java \
GeckoInputConnection.java \
GeckoPreferences.java \
GeckoStateListDrawable.java \
GlobalHistory.java \
PromptService.java \
SurfaceLockInfo.java \
Tab.java \
Tabs.java \
TabsTray.java \
GeckoBatteryManager.java \
GeckoThread.java \
GeckoAsyncTask.java \
gfx/BufferedCairoImage.java \
gfx/CairoGLInfo.java \
gfx/CairoImage.java \
gfx/CairoUtils.java \
gfx/FloatSize.java \
gfx/GeckoSoftwareLayerClient.java \
gfx/InputConnectionHandler.java \
gfx/IntSize.java \
gfx/Layer.java \
gfx/LayerClient.java \
gfx/LayerController.java \
gfx/LayerRenderer.java \
gfx/LayerView.java \
gfx/NinePatchTileLayer.java \
gfx/PlaceholderLayerClient.java \
gfx/PointUtils.java \
gfx/RectUtils.java \
gfx/ScrollbarLayer.java \
gfx/SingleTileLayer.java \
gfx/TextureReaper.java \
gfx/TextLayer.java \
gfx/TileLayer.java \
gfx/ViewportMetrics.java \
ui/PanZoomController.java \
$(NULL)
PROCESSEDJAVAFILES = \
App.java \
LauncherShortcuts.java \
NotificationHandler.java \
Restarter.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/awesomebar_header_row.xml \
res/layout/awesomebar_row.xml \
res/layout/awesomebar_search.xml \
res/layout/awesomebar_tab_indicator.xml \
res/layout/awesomebar_tabs.xml \
res/layout/browser_toolbar.xml \
res/layout/doorhangerpopup.xml \
res/layout/doorhanger.xml \
res/layout/gecko_app.xml \
res/layout/gecko_menu.xml \
res/layout/launch_app_list.xml \
res/layout/launch_app_listitem.xml \
res/layout/notification_icon_text.xml \
res/layout/notification_progress.xml \
res/layout/notification_progress_text.xml \
res/layout/tabs_row.xml \
res/layout/tabs_tray.xml \
res/layout/list_item_header.xml \
res/layout/select_dialog_list.xml \
$(NULL)
RES_LAYOUT_V11 = \
res/layout-v11/awesomebar_search.xml \
res/layout-v11/gecko_app.xml \
res/layout-v11/gecko_app_actionbar.xml \
$(NULL)
RES_VALUES = \
res/values/arrays.xml \
res/values/colors.xml \
res/values/styles.xml \
res/values/themes.xml \
$(NULL)
RES_VALUES_V11 = \
res/values-v11/styles.xml \
res/values-v11/themes.xml \
$(NULL)
RES_XML = res/xml/preferences.xml
RES_ANIM = \
res/anim/grow_fade_in.xml \
res/anim/shrink_fade_out.xml \
$(NULL)
RES_DRAWABLE_MDPI_V8 = \
res/drawable-mdpi-v8/ic_awesomebar_go.png \
res/drawable-mdpi-v8/ic_awesomebar_search.png \
res/drawable-mdpi-v8/ic_menu_bookmark_add.png \
res/drawable-mdpi-v8/ic_menu_bookmark_remove.png \
res/drawable-mdpi-v8/ic_menu_find_in_page.png \
res/drawable-mdpi-v8/ic_menu_reload.png \
res/drawable-mdpi-v8/ic_menu_save_as_pdf.png \
res/drawable-mdpi-v8/ic_menu_share.png \
res/drawable-mdpi-v8/tabs_normal.png \
res/drawable-mdpi-v8/tabs_pressed.png \
res/drawable-mdpi-v8/tabs_more.png \
res/drawable-mdpi-v8/tabs_plus.png \
res/drawable-mdpi-v8/address_bar_url_bg.9.png \
res/drawable-mdpi-v8/doorhanger_arrow.png \
res/drawable-mdpi-v8/doorhanger_bg.9.png \
res/drawable-mdpi-v8/doorhanger_shadow_bg.9.png \
res/drawable-mdpi-v8/doorhanger_popup_bg.9.png \
res/drawable-mdpi-v8/site_security_lock.png \
res/drawable-mdpi-v8/urlbar_stop.png \
$(NULL)
RES_DRAWABLE_HDPI_V8 = \
res/drawable-hdpi-v8/ic_awesomebar_go.png \
res/drawable-hdpi-v8/ic_awesomebar_search.png \
res/drawable-hdpi-v8/ic_menu_bookmark_add.png \
res/drawable-hdpi-v8/ic_menu_bookmark_remove.png \
res/drawable-hdpi-v8/ic_menu_find_in_page.png \
res/drawable-hdpi-v8/ic_menu_reload.png \
res/drawable-hdpi-v8/ic_menu_save_as_pdf.png \
res/drawable-hdpi-v8/ic_menu_share.png \
res/drawable-hdpi-v8/tabs_normal.png \
res/drawable-hdpi-v8/tabs_pressed.png \
res/drawable-hdpi-v8/tabs_more.png \
res/drawable-hdpi-v8/tabs_plus.png \
res/drawable-hdpi-v8/address_bar_url_bg.9.png \
res/drawable-hdpi-v8/doorhanger_arrow.png \
res/drawable-hdpi-v8/doorhanger_bg.9.png \
res/drawable-hdpi-v8/doorhanger_shadow_bg.9.png \
res/drawable-hdpi-v8/doorhanger_popup_bg.9.png \
res/drawable-hdpi-v8/site_security_lock.png \
res/drawable-hdpi-v8/urlbar_stop.png \
$(NULL)
RES_DRAWABLE_MDPI_V9 = \
res/drawable-mdpi-v9/ic_menu_bookmark_add.png \
res/drawable-mdpi-v9/ic_menu_bookmark_remove.png \
res/drawable-mdpi-v9/ic_menu_find_in_page.png \
res/drawable-mdpi-v9/ic_menu_reload.png \
res/drawable-mdpi-v9/ic_menu_save_as_pdf.png \
res/drawable-mdpi-v9/ic_menu_share.png \
$(NULL)
RES_DRAWABLE_HDPI_V9 = \
res/drawable-hdpi-v9/ic_menu_bookmark_add.png \
res/drawable-hdpi-v9/ic_menu_bookmark_remove.png \
res/drawable-hdpi-v9/ic_menu_find_in_page.png \
res/drawable-hdpi-v9/ic_menu_reload.png \
res/drawable-hdpi-v9/ic_menu_save_as_pdf.png \
res/drawable-hdpi-v9/ic_menu_share.png \
$(NULL)
RES_DRAWABLE_MDPI_V11 = \
res/drawable-mdpi-v11/ic_awesomebar_go.png \
res/drawable-mdpi-v11/ic_awesomebar_search.png \
res/drawable-mdpi-v11/ic_menu_bookmark_add.png \
res/drawable-mdpi-v11/ic_menu_bookmark_remove.png \
res/drawable-mdpi-v11/ic_menu_find_in_page.png \
res/drawable-mdpi-v11/ic_menu_reload.png \
res/drawable-mdpi-v11/ic_menu_save_as_pdf.png \
res/drawable-mdpi-v11/ic_menu_share.png \
res/drawable-mdpi-v11/tabs_normal.png \
res/drawable-mdpi-v11/tabs_pressed.png \
res/drawable-mdpi-v11/tabs_more.png \
res/drawable-mdpi-v11/tabs_plus.png \
res/drawable-mdpi-v11/address_bar_url_bg.9.png \
$(NULL)
RES_DRAWABLE_HDPI_V11 = \
res/drawable-hdpi-v11/ic_awesomebar_go.png \
res/drawable-hdpi-v11/ic_awesomebar_search.png \
res/drawable-hdpi-v11/ic_menu_bookmark_add.png \
res/drawable-hdpi-v11/ic_menu_bookmark_remove.png \
res/drawable-hdpi-v11/ic_menu_find_in_page.png \
res/drawable-hdpi-v11/ic_menu_reload.png \
res/drawable-hdpi-v11/ic_menu_save_as_pdf.png \
res/drawable-hdpi-v11/ic_menu_share.png \
res/drawable-hdpi-v11/tabs_normal.png \
res/drawable-hdpi-v11/tabs_pressed.png \
res/drawable-hdpi-v11/tabs_more.png \
res/drawable-hdpi-v11/tabs_plus.png \
res/drawable-hdpi-v11/address_bar_url_bg.9.png \
$(NULL)
RES_DRAWABLE_XHDPI_V11 = \
res/drawable-xhdpi-v11/ic_awesomebar_go.png \
res/drawable-xhdpi-v11/ic_awesomebar_search.png \
res/drawable-xhdpi-v11/ic_menu_bookmark_add.png \
res/drawable-xhdpi-v11/ic_menu_bookmark_remove.png \
res/drawable-xhdpi-v11/ic_menu_find_in_page.png \
res/drawable-xhdpi-v11/ic_menu_reload.png \
res/drawable-xhdpi-v11/ic_menu_save_as_pdf.png \
res/drawable-xhdpi-v11/ic_menu_share.png \
res/drawable-xhdpi-v11/tabs_normal.png \
res/drawable-xhdpi-v11/tabs_pressed.png \
res/drawable-xhdpi-v11/tabs_more.png \
res/drawable-xhdpi-v11/tabs_plus.png \
res/drawable-xhdpi-v11/address_bar_url_bg.9.png \
$(NULL)
RES_COLOR = \
res/color/awesomebar_tab_text.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 += mobile/android/base/resources/drawable/crash_reporter.png
RES_LAYOUT += res/layout/crash_reporter.xml
endif
MOZ_ANDROID_DRAWABLES += mobile/android/base/resources/drawable/address_bar_bg.xml \
mobile/android/base/resources/drawable/address_bar_url_default.xml \
mobile/android/base/resources/drawable/address_bar_url_pressed.xml \
mobile/android/base/resources/drawable/awesomebar_tab_focus.xml \
mobile/android/base/resources/drawable/awesomebar_tab_focus_selected.xml \
mobile/android/base/resources/drawable/awesomebar_tab_indicator.xml \
mobile/android/base/resources/drawable/awesomebar_tab_press.xml \
mobile/android/base/resources/drawable/awesomebar_tab_press_selected.xml \
mobile/android/base/resources/drawable/awesomebar_tab_selected.xml \
mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml \
mobile/android/base/resources/drawable/desktop_notification.png \
mobile/android/base/resources/drawable/favicon.png \
mobile/android/base/resources/drawable/progress_spinner.xml \
mobile/android/base/resources/drawable/progress_spinner_1.png \
mobile/android/base/resources/drawable/progress_spinner_2.png \
mobile/android/base/resources/drawable/progress_spinner_3.png \
mobile/android/base/resources/drawable/progress_spinner_4.png \
mobile/android/base/resources/drawable/progress_spinner_5.png \
mobile/android/base/resources/drawable/progress_spinner_6.png \
mobile/android/base/resources/drawable/progress_spinner_7.png \
mobile/android/base/resources/drawable/progress_spinner_8.png \
mobile/android/base/resources/drawable/progress_spinner_9.png \
mobile/android/base/resources/drawable/progress_spinner_10.png \
mobile/android/base/resources/drawable/progress_spinner_11.png \
mobile/android/base/resources/drawable/progress_spinner_12.png \
mobile/android/base/resources/drawable/progress_spinner_13.png \
mobile/android/base/resources/drawable/progress_spinner_14.png \
mobile/android/base/resources/drawable/progress_spinner_15.png \
mobile/android/base/resources/drawable/progress_spinner_16.png \
mobile/android/base/resources/drawable/progress_spinner_17.png \
mobile/android/base/resources/drawable/progress_spinner_18.png \
mobile/android/base/resources/drawable/start.png \
mobile/android/base/resources/drawable/site_security_level.xml \
mobile/android/base/resources/drawable/tab_new.png \
mobile/android/base/resources/drawable/tab_close.png \
mobile/android/base/resources/drawable/tabs_button.xml \
mobile/android/base/resources/drawable/tabs_level.xml \
mobile/android/base/resources/drawable/tabs_tray_bg.9.png \
mobile/android/base/resources/drawable/checkerboard.png \
mobile/android/base/resources/drawable/shadow.png \
$(NULL)
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) -Xlint:unchecked -Xlint:deprecation -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(PROCESSEDJAVAFILES) R.java
$(DX) --dex --output=$@ classes
AndroidManifest.xml $(PROCESSEDJAVAFILES) package-name.txt: % : %.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) $^ res/layout
$(RES_LAYOUT_V11): $(subst res/,$(srcdir)/resources/,$(RES_LAYOUT_V11))
$(NSINSTALL) -D res/layout-v11
$(NSINSTALL) $(srcdir)/resources/layout-v11/* res/layout-v11/
$(RES_VALUES): $(subst res/,$(srcdir)/resources/,$(RES_VALUES))
$(NSINSTALL) -D res/values
$(NSINSTALL) $^ res/values
$(RES_VALUES_V11): $(subst res/,$(srcdir)/resources/,$(RES_VALUES_V11))
$(NSINSTALL) -D res/values-v11
$(NSINSTALL) $(srcdir)/resources/values-v11/* res/values-v11
$(RES_XML): $(subst res/,$(srcdir)/resources/,$(RES_XML))
$(NSINSTALL) -D res/xml
$(NSINSTALL) $(srcdir)/resources/xml/* res/xml/
$(RES_ANIM): $(subst res/,$(srcdir)/resources/,$(RES_ANIM))
$(NSINSTALL) -D res/anim
$(NSINSTALL) $(srcdir)/resources/anim/* res/anim/
$(RES_DRAWABLE_MDPI_V8): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_MDPI_V8))
$(NSINSTALL) -D res/drawable-mdpi-v8
$(NSINSTALL) $(srcdir)/resources/drawable-mdpi-v8/* res/drawable-mdpi-v8/
$(RES_DRAWABLE_HDPI_V8): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_HDPI_V8))
$(NSINSTALL) -D res/drawable-hdpi-v8
$(NSINSTALL) $(srcdir)/resources/drawable-hdpi-v8/* res/drawable-hdpi-v8/
$(RES_DRAWABLE_MDPI_V9): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_MDPI_V9))
$(NSINSTALL) -D res/drawable-mdpi-v9
$(NSINSTALL) $(srcdir)/resources/drawable-mdpi-v9/* res/drawable-mdpi-v9/
$(RES_DRAWABLE_HDPI_V9): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_HDPI_V9))
$(NSINSTALL) -D res/drawable-hdpi-v9
$(NSINSTALL) $(srcdir)/resources/drawable-hdpi-v9/* res/drawable-hdpi-v9/
$(RES_DRAWABLE_MDPI_V11): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_MDPI_V11))
$(NSINSTALL) -D res/drawable-mdpi-v11
$(NSINSTALL) $(srcdir)/resources/drawable-mdpi-v11/* res/drawable-mdpi-v11/
$(RES_DRAWABLE_HDPI_V11): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_HDPI_V11))
$(NSINSTALL) -D res/drawable-hdpi-v11
$(NSINSTALL) $(srcdir)/resources/drawable-hdpi-v11/* res/drawable-hdpi-v11/
$(RES_DRAWABLE_XHDPI_V11): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_XHDPI_V11))
$(NSINSTALL) -D res/drawable-xhdpi-v11
$(NSINSTALL) $(srcdir)/resources/drawable-xhdpi-v11/* res/drawable-xhdpi-v11/
$(RES_COLOR): $(subst res/,$(srcdir)/resources/,$(RES_COLOR))
$(NSINSTALL) -D res/color
$(NSINSTALL) $^ res/color
R.java: $(MOZ_APP_ICON) $(RES_LAYOUT) $(RES_LAYOUT_V11) $(RES_DRAWABLE) $(RES_VALUES) $(RES_VALUES_V11) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_MDPI_V8) $(RES_DRAWABLE_HDPI_V8) $(RES_DRAWABLE_MDPI_V9) $(RES_DRAWABLE_HDPI_V9) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_COLOR) 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_LAYOUT_V11) $(RES_DRAWABLE) $(RES_VALUES) $(RES_VALUES_V11) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_MDPI_V8) $(RES_DRAWABLE_HDPI_V8) $(RES_DRAWABLE_MDPI_V9) $(RES_DRAWABLE_HDPI_V9) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_COLOR) 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) $(srcdir)/strings.xml.in
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) $(srcdir)/strings.xml.in
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 package-name.txt
$(INSTALL) classes.dex $(FINAL_TARGET)
$(INSTALL) package-name.txt $(FINAL_TARGET)

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше