Merge mozilla-central to birch.
|
@ -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();
|
|
||||||
|
|
||||||
jmethodID getClass = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass,
|
|
||||||
"getSurfaceInfoClass",
|
|
||||||
"()Ljava/lang/Class;");
|
|
||||||
|
|
||||||
gSurfaceJavaGlue.surfaceInfoCls = (jclass) env->NewGlobalRef(env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, getClass));
|
void* (* regionConstructor)(void*);
|
||||||
|
void (* setRegion)(void*, ARect const&);
|
||||||
|
} gSurfaceFunctions;
|
||||||
|
|
||||||
gSurfaceJavaGlue.jFormat = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "format", "I");
|
|
||||||
gSurfaceJavaGlue.jWidth = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "width", "I");
|
|
||||||
gSurfaceJavaGlue.jHeight = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "height", "I");
|
|
||||||
|
|
||||||
gSurfaceJavaGlue.getSurfaceInfo = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "getSurfaceInfo", "(Landroid/view/SurfaceView;)Lorg/mozilla/gecko/SurfaceInfo;");
|
static inline void* getSurface(JNIEnv* env, jobject view) {
|
||||||
gSurfaceJavaGlue.initialized = true;
|
if (!env || !view) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gSurfaceJavaGlue.initialized) {
|
||||||
|
|
||||||
|
jclass surfaceViewClass = env->FindClass("android/view/SurfaceView");
|
||||||
|
gSurfaceJavaGlue.getSurfaceHolder = env->GetMethodID(surfaceViewClass, "getHolder", "()Landroid/view/SurfaceHolder;");
|
||||||
|
|
||||||
|
jclass surfaceHolderClass = env->FindClass("android/view/SurfaceHolder");
|
||||||
|
gSurfaceJavaGlue.getSurface = env->GetMethodID(surfaceHolderClass, "getSurface", "()Landroid/view/Surface;");
|
||||||
|
|
||||||
|
jclass surfaceClass = env->FindClass("android/view/Surface");
|
||||||
|
gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
|
||||||
|
"mSurfacePointer", "I");
|
||||||
|
|
||||||
|
if (!gSurfaceJavaGlue.surfacePointer) {
|
||||||
|
CLEAR_EXCEPTION(env);
|
||||||
|
|
||||||
|
// It was something else in 2.2.
|
||||||
|
gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
|
||||||
|
"mSurface", "I");
|
||||||
|
|
||||||
|
if (!gSurfaceJavaGlue.surfacePointer) {
|
||||||
|
CLEAR_EXCEPTION(env);
|
||||||
|
|
||||||
|
// And something else in 2.3+
|
||||||
|
gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
|
||||||
|
"mNativeSurface", "I");
|
||||||
|
|
||||||
|
CLEAR_EXCEPTION(env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gSurfaceJavaGlue.surfacePointer) {
|
||||||
|
LOG("Failed to acquire surface pointer");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->DeleteLocalRef(surfaceClass);
|
||||||
|
env->DeleteLocalRef(surfaceViewClass);
|
||||||
|
env->DeleteLocalRef(surfaceHolderClass);
|
||||||
|
|
||||||
|
gSurfaceJavaGlue.initialized = (gSurfaceJavaGlue.surfacePointer != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder);
|
||||||
|
jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface);
|
||||||
|
jint surfacePointer = env->GetIntField(surface, gSurfaceJavaGlue.surfacePointer);
|
||||||
|
|
||||||
|
env->DeleteLocalRef(holder);
|
||||||
|
env->DeleteLocalRef(surface);
|
||||||
|
|
||||||
|
return (void*)surfacePointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) {
|
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;
|
|
||||||
} else {
|
|
||||||
// No dirty rect, use the whole bitmap
|
|
||||||
lockRect.top = lockRect.left = 0;
|
|
||||||
lockRect.right = bitmap->width;
|
|
||||||
lockRect.bottom = bitmap->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfxImageSurface* target = pinst->LockTargetSurface(bitmap->width, bitmap->height, targetFormat, &lockRect);
|
|
||||||
bitmap->baseAddr = target->Data();
|
|
||||||
|
|
||||||
env->DeleteLocalRef(info);
|
ARect rect;
|
||||||
|
rect.left = dirtyRect->left;
|
||||||
|
rect.top = dirtyRect->top;
|
||||||
|
rect.right = dirtyRect->right;
|
||||||
|
rect.bottom = dirtyRect->bottom;
|
||||||
|
|
||||||
|
gSurfaceFunctions.setRegion(region, rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
SurfaceInfo info;
|
||||||
|
int err = gSurfaceFunctions.lock(surface, &info, region);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG("Failed to lock surface");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the surface may have expanded the dirty region so we must to pass that
|
||||||
|
// information back to the plugin.
|
||||||
|
if (dirtyRect) {
|
||||||
|
ARect* dirtyBounds = (ARect*)region; // The bounds are the first member, so this should work!
|
||||||
|
|
||||||
|
dirtyRect->left = dirtyBounds->left;
|
||||||
|
dirtyRect->right = dirtyBounds->right;
|
||||||
|
dirtyRect->top = dirtyBounds->top;
|
||||||
|
dirtyRect->bottom = dirtyBounds->bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region)
|
||||||
|
free(region);
|
||||||
|
|
||||||
|
int bpr = info.s * bytesPerPixel(info.format);
|
||||||
|
|
||||||
|
bitmap->format = convertPixelFormat(info.format);
|
||||||
|
bitmap->width = info.w;
|
||||||
|
bitmap->height = info.h;
|
||||||
|
bitmap->rowBytes = bpr;
|
||||||
|
|
||||||
|
if (info.w > 0 && info.h > 0) {
|
||||||
|
bitmap->baseAddr = info.bits;
|
||||||
|
} else {
|
||||||
|
bitmap->baseAddr = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
|
||||||
|
@ -1820,12 +1847,13 @@ nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt)
|
||||||
for (PRUint32 i = 0; i < mListeners.Length(); i++) {
|
for (PRUint32 i = 0; i < mListeners.Length(); i++) {
|
||||||
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);
|
||||||
|
|
|
@ -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
|
После Ширина: | Высота: | Размер: 1.6 KiB |
После Ширина: | Высота: | Размер: 1.6 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 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%";
|
После Ширина: | Высота: | Размер: 1.9 KiB |
После Ширина: | Высота: | Размер: 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%¤tAppVersion=%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>
|
Двоичные данные
mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/skin/beta-hdpi.png
Normal file
После Ширина: | Высота: | Размер: 2.6 KiB |
Двоичные данные
mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/skin/dino-32.png
Normal file
После Ширина: | Высота: | Размер: 1.5 KiB |
Двоичные данные
mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/skin/happy-32.png
Normal file
После Ширина: | Высота: | Размер: 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");
|
||||||
|
}
|
Двоичные данные
mobile/android/app/profile/extensions/feedback@mobile.mozilla.org/skin/sad-32.png
Normal file
После Ширина: | Высота: | Размер: 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)
|