Bug 569402 - Show notifications in the Status Bar on Android r=blassey a=blocking-fennec

This commit is contained in:
Alex Pakhotin
2010-06-14 19:17:37 -07:00
parent 552011a988
commit d787c063c9
14 changed files with 388 additions and 23 deletions

View File

@@ -61,10 +61,20 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<receiver android:enabled="true" android:name="Restarter">
<intent-filter> <activity android:name="NotificationHandler"
android:label="@MOZ_APP_DISPLAYNAME@ Notification"
android:theme="@android:style/Theme.NoTitleBar">
<intent-filter>
<action android:name="org.mozilla.gecko.ACTION_ALERT_CLICK" />
<action android:name="org.mozilla.gecko.ACTION_ALERT_CLEAR" />
</intent-filter>
</activity>
<receiver android:enabled="true" android:name="Restarter">
<intent-filter>
<action android:name="org.mozilla.gecko.restart@MOZ_APP_NAME@" /> <action android:name="org.mozilla.gecko.restart@MOZ_APP_NAME@" />
</intent-filter> </intent-filter>
</receiver> </receiver>
</application> </application>
</manifest> </manifest>

View File

@@ -57,6 +57,9 @@ import android.util.*;
abstract public class GeckoApp abstract public class GeckoApp
extends Activity extends Activity
{ {
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 FrameLayout mainLayout; public static FrameLayout mainLayout;
public static GeckoSurfaceView surfaceView; public static GeckoSurfaceView surfaceView;
public static GeckoApp mAppContext; public static GeckoApp mAppContext;
@@ -431,4 +434,8 @@ abstract public class GeckoApp
} }
System.exit(0); System.exit(0);
} }
public void handleNotification(String action, String alertName, String alertCookie) {
GeckoAppShell.handleNotification(action, alertName, alertCookie);
}
} }

View File

@@ -91,6 +91,8 @@ class GeckoAppShell
public static native void setSurfaceView(GeckoSurfaceView sv); public static native void setSurfaceView(GeckoSurfaceView sv);
public static native void putenv(String map); public static native void putenv(String map);
public static native void onResume(); public static native void onResume();
public static native void callObserver(String observerKey, String topic, String data);
public static native void removeObserver(String observerKey);
// java-side stuff // java-side stuff
public static void loadGeckoLibs() { public static void loadGeckoLibs() {
@@ -439,4 +441,69 @@ class GeckoAppShell
context.getSystemService(Context.CLIPBOARD_SERVICE); context.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setText(text); cm.setText(text);
} }
static void showAlertNotification(String imageUrl, String alertTitle, String alertText,
String alertCookie, String alertName) {
Log.i("GeckoAppJava", "GeckoAppShell.showAlertNotification\n" +
"- image = '" + imageUrl + "'\n" +
"- title = '" + alertTitle + "'\n" +
"- text = '" + alertText +"'\n" +
"- cookie = '" + alertCookie +"'\n" +
"- name = '" + alertName + "'");
int icon = R.drawable.icon; // Just use the app icon by default
Uri imageUri = Uri.parse(imageUrl);
String scheme = imageUri.getScheme();
if ("drawable".equals(scheme)) {
String resource = imageUri.getSchemeSpecificPart();
if ("//alertdownloads".equals(resource))
icon = R.drawable.alertdownloads;
else if ("//alertaddons".equals(resource))
icon = R.drawable.alertaddons;
}
int notificationID = alertName.hashCode();
Notification notification = new Notification(icon, alertTitle, System.currentTimeMillis());
// The intent to launch when the user clicks the expanded notification
Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CLICK);
notificationIntent.setClassName(GeckoApp.mAppContext,
"org.mozilla." + GeckoApp.mAppContext.getAppName() + ".NotificationHandler");
// Put the strings into the intent as an URI "alert:<name>#<cookie>"
Uri dataUri = Uri.fromParts("alert", alertName, alertCookie);
notificationIntent.setData(dataUri);
PendingIntent contentIntent = PendingIntent.getActivity(GeckoApp.mAppContext, 0, notificationIntent, 0);
notification.setLatestEventInfo(GeckoApp.mAppContext, alertTitle, alertText, contentIntent);
// The intent to execute when the status entry is deleted by the user with the "Clear All Notifications" button
Intent clearNotificationIntent = new Intent(GeckoApp.ACTION_ALERT_CLEAR);
clearNotificationIntent.setClassName(GeckoApp.mAppContext,
"org.mozilla." + GeckoApp.mAppContext.getAppName() + ".NotificationHandler");
clearNotificationIntent.setData(dataUri);
PendingIntent pendingClearIntent = PendingIntent.getActivity(GeckoApp.mAppContext, 0, clearNotificationIntent, 0);
notification.deleteIntent = pendingClearIntent;
// Show the notification
NotificationManager notificationManager = (NotificationManager)
GeckoApp.mAppContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationID, notification);
Log.i("GeckoAppJava", "Created notification ID " + notificationID);
}
public static void handleNotification(String action, String alertName, String alertCookie) {
if (GeckoApp.ACTION_ALERT_CLICK.equals(action)) {
Log.i("GeckoAppJava", "GeckoAppShell.handleNotification: callObserver(alertclickcallback)");
callObserver(alertName, "alertclickcallback", alertCookie);
}
Log.i("GeckoAppJava", "GeckoAppShell.handleNotification: callObserver(alertfinished)");
callObserver(alertName, "alertfinished", alertCookie);
removeObserver(alertName);
}
} }

View File

@@ -51,6 +51,12 @@ JAVAFILES = \
GeckoInputConnection.java \ GeckoInputConnection.java \
$(NULL) $(NULL)
PROCESSEDJAVAFILES = \
App.java \
Restarter.java \
NotificationHandler.java \
$(NULL)
DEFINES += \ DEFINES += \
-DMOZ_APP_DISPLAYNAME=$(MOZ_APP_DISPLAYNAME) \ -DMOZ_APP_DISPLAYNAME=$(MOZ_APP_DISPLAYNAME) \
-DMOZ_APP_NAME=$(MOZ_APP_NAME) \ -DMOZ_APP_NAME=$(MOZ_APP_NAME) \
@@ -60,8 +66,7 @@ GARBAGE += \
AndroidManifest.xml \ AndroidManifest.xml \
classes.dex \ classes.dex \
$(MOZ_APP_NAME).apk \ $(MOZ_APP_NAME).apk \
App.java \ $(PROCESSEDJAVAFILES) \
Restarter.java \
gecko.ap_ \ gecko.ap_ \
gecko-unaligned.apk \ gecko-unaligned.apk \
gecko-unsigned-unaligned.apk \ gecko-unsigned-unaligned.apk \
@@ -74,12 +79,22 @@ DIRS = utils
# Bug 567884 - Need a way to find appropriate icons during packaging # Bug 567884 - Need a way to find appropriate icons during packaging
ifeq ($(MOZ_APP_NAME),fennec) ifeq ($(MOZ_APP_NAME),fennec)
ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_48x48.png ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_48x48.png
ICON_PATH_HI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png
else else
ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon48.png ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon48.png
ICON_PATH_HI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon64.png ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon64.png
endif endif
RES_DRAWABLE = \
res/drawable/alertaddons.png \
res/drawable/alertdownloads.png \
$(NULL)
RES_DRAWABLE_HDPI = \
res/drawable-hdpi/alertaddons.png \
res/drawable-hdpi/alertdownloads.png \
$(NULL)
NATIVE_LIBS = $(shell cat $(DIST)/bin/dependentlibs.list) libxpcom.so libnssckbi.so libfreebl3.so libmozutils.so NATIVE_LIBS = $(shell cat $(DIST)/bin/dependentlibs.list) libxpcom.so libnssckbi.so libfreebl3.so libmozutils.so
FULL_LIBS = $(addprefix libs/armeabi/,$(NATIVE_LIBS)) FULL_LIBS = $(addprefix libs/armeabi/,$(NATIVE_LIBS))
@@ -120,12 +135,12 @@ tools:: $(MOZ_APP_NAME).apk
# Note that we're going to set up a dependency directly between embed_android.dex and the java files # 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 # Instead of on the .class files, since more than one .class file might be produced per .java file
classes.dex: $(JAVAFILES) App.java Restarter.java classes.dex: $(JAVAFILES) $(PROCESSEDJAVAFILES) R.java
$(NSINSTALL) -D classes $(NSINSTALL) -D classes
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) App.java Restarter.java $(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(PROCESSEDJAVAFILES) R.java
$(DX) --dex --output=$@ classes $(DX) --dex --output=$@ classes
AndroidManifest.xml App.java Restarter.java : % : %.in AndroidManifest.xml $(PROCESSEDJAVAFILES): % : %.in
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \ $(PYTHON) $(topsrcdir)/config/Preprocessor.py \
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@ $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@
@@ -135,9 +150,20 @@ res/drawable/icon.png: $(MOZ_APP_ICON)
res/drawable-hdpi/icon.png: $(MOZ_APP_ICON) res/drawable-hdpi/icon.png: $(MOZ_APP_ICON)
$(NSINSTALL) -D res/drawable-hdpi $(NSINSTALL) -D res/drawable-hdpi
cp $(ICON_PATH_HI) $@ cp $(ICON_PATH_HDPI) $@
gecko.ap_: AndroidManifest.xml res/drawable/icon.png res/drawable-hdpi/icon.png $(RES_DRAWABLE):
$(NSINSTALL) -D res/drawable
cp $(topsrcdir)/mobile/app/android/drawable/* res/drawable/
$(RES_DRAWABLE_HDPI):
$(NSINSTALL) -D res/drawable-hdpi
cp $(topsrcdir)/mobile/app/android/drawable-hdpi/* res/drawable-hdpi/
R.java: $(MOZ_APP_ICON) $(RES_DRAWABLE) $(RES_DRAWABLE_HDPI)
$(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_DRAWABLE) $(RES_DRAWABLE_HDPI)
$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@ $(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
libs/armeabi/%: $(DIST)/lib/% libs/armeabi/%: $(DIST)/lib/%

View File

@@ -0,0 +1,104 @@
/* -*- 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 Corporation.
* Portions created by the Initial Developer are Copyright (C) 2010
* 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 ***** */
#filter substitution
package org.mozilla.@MOZ_APP_NAME@;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.Intent;
import android.content.ActivityNotFoundException;
import android.os.Bundle;
import android.util.Log;
import android.net.Uri;
public class NotificationHandler
extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("GeckoAppJava", "NotificationHandler.onCreate");
Intent intent = getIntent();
if (intent != null)
handleIntent(intent);
finish();
}
protected void handleIntent(Intent notificationIntent) {
String action = notificationIntent.getAction();
String alertName = "";
String alertCookie = "";
Uri data = notificationIntent.getData();
if (data != null) {
alertName = data.getSchemeSpecificPart();
alertCookie = data.getFragment();
if (alertCookie == null)
alertCookie = "";
}
Log.i("GeckoAppJava", "NotificationHandler.handleIntent\n" +
"- action = '" + action + "'\n" +
"- alertName = '" + alertName + "'\n" +
"- alertCookie = '" + alertCookie + "'");
int notificationID = alertName.hashCode();
Log.i("GeckoAppJava", "Handle notification ID " + notificationID);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.cancel(notificationID);
if (App.mAppContext != null) {
// This should call the observer, if any
App.mAppContext.handleNotification(action, alertName, alertCookie);
}
if (App.ACTION_ALERT_CLICK.equals(action)) {
// Start or bring to front the main activity
Intent appIntent = new Intent(Intent.ACTION_MAIN);
appIntent.setClassName(this, "org.mozilla.@MOZ_APP_NAME@.App");
try {
startActivity(appIntent);
} catch (ActivityNotFoundException e) {
Log.e("GeckoAppJava", "NotificationHandler Exception: " + e.getMessage());
}
}
}
}

View File

@@ -56,9 +56,11 @@ interface nsIAlertsService : nsISupports
* consumer during the alert listener callbacks. * consumer during the alert listener callbacks.
* @param alertListener Used for callbacks. May be null if the caller * @param alertListener Used for callbacks. May be null if the caller
* doesn't care about callbacks. * doesn't care about callbacks.
* @param name The name of the notification. This is currently * @param name The name of the notification. This is currently
* only used on OS X with Growl. On OS X with Growl, * only used on OS X with Growl and Android.
* users can disable notifications with a given name. * On OS X with Growl, users can disable notifications
* with a given name. On Android the name is hashed
* and used as a notification ID.
* *
* @throws NS_ERROR_NOT_AVAILABLE If the notification cannot be displayed. * @throws NS_ERROR_NOT_AVAILABLE If the notification cannot be displayed.
* *

View File

@@ -22,6 +22,7 @@
* Contributor(s): * Contributor(s):
* Scott MacGregor <mscott@netscape.com> * Scott MacGregor <mscott@netscape.com>
* Jens Bannmann <jens.b@web.de> * Jens Bannmann <jens.b@web.de>
* Alex Pakhotin <alexp@mozilla.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -38,6 +39,11 @@
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "nsAlertsService.h" #include "nsAlertsService.h"
#ifdef ANDROID
#include "AndroidBridge.h"
#else
#include "nsISupportsArray.h" #include "nsISupportsArray.h"
#include "nsXPCOM.h" #include "nsXPCOM.h"
#include "nsISupportsPrimitives.h" #include "nsISupportsPrimitives.h"
@@ -53,6 +59,8 @@ static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
#define ALERT_CHROME_URL "chrome://global/content/alerts/alert.xul" #define ALERT_CHROME_URL "chrome://global/content/alerts/alert.xul"
#endif // !ANDROID
NS_IMPL_THREADSAFE_ADDREF(nsAlertsService) NS_IMPL_THREADSAFE_ADDREF(nsAlertsService)
NS_IMPL_THREADSAFE_RELEASE(nsAlertsService) NS_IMPL_THREADSAFE_RELEASE(nsAlertsService)
@@ -74,6 +82,11 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
nsIObserver * aAlertListener, nsIObserver * aAlertListener,
const nsAString & aAlertName) const nsAString & aAlertName)
{ {
#ifdef ANDROID
mozilla::AndroidBridge::Bridge()->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertCookie,
aAlertListener, aAlertName);
return NS_OK;
#else
// Check if there is an optional service that handles system-level notifications // Check if there is an optional service that handles system-level notifications
nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID)); nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID));
nsresult rv; nsresult rv;
@@ -156,4 +169,5 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
"chrome,dialog=yes,titlebar=no,popup=yes", argsArray, "chrome,dialog=yes,titlebar=no,popup=yes", argsArray,
getter_AddRefs(newWindow)); getter_AddRefs(newWindow));
return rv; return rv;
#endif // !ANDROID
} }

View File

@@ -46,6 +46,7 @@
#include "nsXPCOMStrings.h" #include "nsXPCOMStrings.h"
#include "AndroidBridge.h" #include "AndroidBridge.h"
#include "nsAppShell.h"
using namespace mozilla; using namespace mozilla;
@@ -110,6 +111,7 @@ AndroidBridge::Init(JNIEnv *jEnv,
jMoveTaskToBack = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "moveTaskToBack", "()V"); jMoveTaskToBack = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "moveTaskToBack", "()V");
jGetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getClipboardText", "()Ljava/lang/String;"); jGetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getClipboardText", "()Ljava/lang/String;");
jSetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setClipboardText", "(Ljava/lang/String;)V"); jSetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setClipboardText", "(Ljava/lang/String;)V");
jShowAlertNotification = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext")); jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
@@ -403,6 +405,30 @@ AndroidBridge::EmptyClipboard()
mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, jSetClipboardText, nsnull); mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, jSetClipboardText, nsnull);
} }
void
AndroidBridge::ShowAlertNotification(const nsAString& aImageUrl,
const nsAString& aAlertTitle,
const nsAString& aAlertText,
const nsAString& aAlertCookie,
nsIObserver *aAlertListener,
const nsAString& aAlertName)
{
ALOG("ShowAlertNotification");
AutoLocalJNIFrame jniFrame;
if (nsAppShell::gAppShell && aAlertListener)
nsAppShell::gAppShell->AddObserver(aAlertName, aAlertListener);
jvalue args[5];
args[0].l = mJNIEnv->NewString(nsPromiseFlatString(aImageUrl).get(), aImageUrl.Length());
args[1].l = mJNIEnv->NewString(nsPromiseFlatString(aAlertTitle).get(), aAlertTitle.Length());
args[2].l = mJNIEnv->NewString(nsPromiseFlatString(aAlertText).get(), aAlertText.Length());
args[3].l = mJNIEnv->NewString(nsPromiseFlatString(aAlertCookie).get(), aAlertCookie.Length());
args[4].l = mJNIEnv->NewString(nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
mJNIEnv->CallStaticVoidMethodA(mGeckoAppShellClass, jShowAlertNotification, args);
}
void void
AndroidBridge::SetSurfaceView(jobject obj) AndroidBridge::SetSurfaceView(jobject obj)
{ {

View File

@@ -43,6 +43,7 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIRunnable.h" #include "nsIRunnable.h"
#include "nsIObserver.h"
#include "AndroidJavaWrappers.h" #include "AndroidJavaWrappers.h"
@@ -134,6 +135,13 @@ public:
bool ClipboardHasText(); bool ClipboardHasText();
void ShowAlertNotification(const nsAString& aImageUrl,
const nsAString& aAlertTitle,
const nsAString& aAlertText,
const nsAString& aAlertData,
nsIObserver *aAlertListener,
const nsAString& aAlertName);
struct AutoLocalJNIFrame { struct AutoLocalJNIFrame {
AutoLocalJNIFrame(int nEntries = 128) : mEntries(nEntries) { AutoLocalJNIFrame(int nEntries = 128) : mEntries(nEntries) {
AndroidBridge::Bridge()->JNI()->PushLocalFrame(mEntries); AndroidBridge::Bridge()->JNI()->PushLocalFrame(mEntries);
@@ -191,6 +199,7 @@ protected:
jmethodID jMoveTaskToBack; jmethodID jMoveTaskToBack;
jmethodID jGetClipboardText; jmethodID jGetClipboardText;
jmethodID jSetClipboardText; jmethodID jSetClipboardText;
jmethodID jShowAlertNotification;
// stuff we need for CallEglCreateWindowSurface // stuff we need for CallEglCreateWindowSurface
jclass jEGLSurfaceImplClass; jclass jEGLSurfaceImplClass;

View File

@@ -36,6 +36,7 @@
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "nsILocalFile.h" #include "nsILocalFile.h"
#include "nsString.h"
#include "AndroidBridge.h" #include "AndroidBridge.h"
@@ -57,6 +58,8 @@ extern "C" {
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setSurfaceView(JNIEnv *jenv, jclass, jobject sv); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setSurfaceView(JNIEnv *jenv, jclass, jobject sv);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setInitialSize(JNIEnv *jenv, jclass, int width, int height); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setInitialSize(JNIEnv *jenv, jclass, int width, int height);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *, jclass); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *, jclass);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_callObserver(JNIEnv *, jclass, jstring observerKey, jstring topic, jstring data);
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_removeObserver(JNIEnv *jenv, jclass, jstring jObserverKey);
} }
@@ -98,3 +101,30 @@ Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *jenv, jclass jc)
if (nsAppShell::gAppShell) if (nsAppShell::gAppShell)
nsAppShell::gAppShell->OnResume(); nsAppShell::gAppShell->OnResume();
} }
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_callObserver(JNIEnv *jenv, jclass, jstring jObserverKey, jstring jTopic, jstring jData)
{
if (!nsAppShell::gAppShell)
return;
nsJNIString sObserverKey(jObserverKey, jenv);
nsJNIString sTopic(jTopic, jenv);
nsJNIString sData(jData, jenv);
nsAppShell::gAppShell->CallObserver(sObserverKey, sTopic, sData);
}
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_removeObserver(JNIEnv *jenv, jclass, jstring jObserverKey)
{
if (!nsAppShell::gAppShell)
return;
const jchar *observerKey = jenv->GetStringChars(jObserverKey, NULL);
nsString sObserverKey(observerKey);
sObserverKey.SetLength(jenv->GetStringLength(jObserverKey));
jenv->ReleaseStringChars(jObserverKey, observerKey);
nsAppShell::gAppShell->RemoveObserver(sObserverKey);
}

View File

@@ -441,16 +441,17 @@ AndroidRect::Init(JNIEnv *jenv, jobject jobj)
} }
} }
nsJNIString::nsJNIString(jstring jstr) nsJNIString::nsJNIString(jstring jstr, JNIEnv *jenv)
{ {
if (!jstr) { if (!jstr) {
SetIsVoid(PR_TRUE); SetIsVoid(PR_TRUE);
return; return;
} }
const jchar* jCharPtr = JNI()->GetStringChars(jstr, false); JNIEnv *jni = jenv;
int len = JNI()->GetStringLength(jstr); if (!jni)
nsresult rv; jni = JNI();
const jchar* jCharPtr = jni->GetStringChars(jstr, false);
int len = jni->GetStringLength(jstr);
Assign(jCharPtr, len); Assign(jCharPtr, len);
JNI()->ReleaseStringChars(jstr, jCharPtr); jni->ReleaseStringChars(jstr, jCharPtr);
} }

View File

@@ -468,7 +468,7 @@ public:
class nsJNIString : public nsString class nsJNIString : public nsString
{ {
public: public:
nsJNIString(jstring jstr); nsJNIString(jstring jstr, JNIEnv *jenv = NULL);
}; };
} }

View File

@@ -118,6 +118,8 @@ nsAppShell::Init()
mQueueCond = PR_NewCondVar(mCondLock); mQueueCond = PR_NewCondVar(mCondLock);
mPaused = PR_NewCondVar(mPausedLock); mPaused = PR_NewCondVar(mPausedLock);
mObserversHash.Init();
return nsBaseAppShell::Init(); return nsBaseAppShell::Init();
} }
@@ -367,6 +369,67 @@ nsAppShell::OnResume()
} }
nsresult
nsAppShell::AddObserver(const nsAString &aObserverKey, nsIObserver *aObserver)
{
NS_ASSERTION(aObserver != nsnull, "nsAppShell::AddObserver: aObserver is null!");
return mObserversHash.Put(aObserverKey, aObserver) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
/**
* The XPCOM event that will call the observer on the main thread.
*/
class ObserverCaller : public nsRunnable {
public:
ObserverCaller(nsIObserver *aObserver, const char *aTopic, const PRUnichar *aData) :
mObserver(aObserver), mTopic(aTopic), mData(aData) {
NS_ASSERTION(aObserver != nsnull, "ObserverCaller: aObserver is null!");
}
NS_IMETHOD Run() {
ALOG("ObserverCaller::Run: observer = %p, topic = '%s')",
(nsIObserver*)mObserver, mTopic.get());
mObserver->Observe(nsnull, mTopic.get(), mData.get());
return NS_OK;
}
private:
nsCOMPtr<nsIObserver> mObserver;
nsCString mTopic;
nsString mData;
};
void
nsAppShell::CallObserver(const nsAString &aObserverKey, const nsAString &aTopic, const nsAString &aData)
{
nsCOMPtr<nsIObserver> observer;
mObserversHash.Get(aObserverKey, getter_AddRefs(observer));
if (!observer) {
ALOG("nsAppShell::CallObserver: Observer was not found!");
return;
}
const NS_ConvertUTF16toUTF8 sTopic(aTopic);
const nsPromiseFlatString& sData = PromiseFlatString(aData);
if (NS_IsMainThread()) {
// This branch will unlikely be hit, have it just in case
observer->Observe(nsnull, sTopic.get(), sData.get());
} else {
// Java is not running on main thread, so we have to use NS_DispatchToMainThread
nsCOMPtr<nsIRunnable> observerCaller = new ObserverCaller(observer, sTopic.get(), sData.get());
nsresult rv = NS_DispatchToMainThread(observerCaller);
ALOG("NS_DispatchToMainThread result: %d", rv);
}
}
void
nsAppShell::RemoveObserver(const nsAString &aObserverKey)
{
mObserversHash.Remove(aObserverKey);
}
// Used by IPC code // Used by IPC code
namespace mozilla { namespace mozilla {

View File

@@ -42,6 +42,7 @@
#include "nsBaseAppShell.h" #include "nsBaseAppShell.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "nsInterfaceHashtable.h"
#include "prcvar.h" #include "prcvar.h"
@@ -70,6 +71,10 @@ public:
void RemoveNextEvent(); void RemoveNextEvent();
void OnResume(); void OnResume();
nsresult AddObserver(const nsAString &aObserverKey, nsIObserver *aObserver);
void CallObserver(const nsAString &aObserverKey, const nsAString &aTopic, const nsAString &aData);
void RemoveObserver(const nsAString &aObserverKey);
protected: protected:
virtual void ScheduleNativeEventCallback(); virtual void ScheduleNativeEventCallback();
virtual ~nsAppShell(); virtual ~nsAppShell();
@@ -81,6 +86,7 @@ protected:
PRCondVar *mQueueCond; PRCondVar *mQueueCond;
PRCondVar *mPaused; PRCondVar *mPaused;
nsTArray<mozilla::AndroidGeckoEvent *> mEventQueue; nsTArray<mozilla::AndroidGeckoEvent *> mEventQueue;
nsInterfaceHashtable<nsStringHashKey, nsIObserver> mObserversHash;
mozilla::AndroidGeckoEvent *GetNextEvent(); mozilla::AndroidGeckoEvent *GetNextEvent();
mozilla::AndroidGeckoEvent *PeekNextEvent(); mozilla::AndroidGeckoEvent *PeekNextEvent();