Bug 569402 - Show notifications in the Status Bar on Android r=blassey a=blocking-fennec
This commit is contained in:
@@ -61,10 +61,20 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</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@" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -57,6 +57,9 @@ import android.util.*;
|
||||
abstract public class GeckoApp
|
||||
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 GeckoSurfaceView surfaceView;
|
||||
public static GeckoApp mAppContext;
|
||||
@@ -431,4 +434,8 @@ abstract public class GeckoApp
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public void handleNotification(String action, String alertName, String alertCookie) {
|
||||
GeckoAppShell.handleNotification(action, alertName, alertCookie);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ class GeckoAppShell
|
||||
public static native void setSurfaceView(GeckoSurfaceView sv);
|
||||
public static native void putenv(String map);
|
||||
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
|
||||
public static void loadGeckoLibs() {
|
||||
@@ -439,4 +441,69 @@ class GeckoAppShell
|
||||
context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,12 @@ JAVAFILES = \
|
||||
GeckoInputConnection.java \
|
||||
$(NULL)
|
||||
|
||||
PROCESSEDJAVAFILES = \
|
||||
App.java \
|
||||
Restarter.java \
|
||||
NotificationHandler.java \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += \
|
||||
-DMOZ_APP_DISPLAYNAME=$(MOZ_APP_DISPLAYNAME) \
|
||||
-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
|
||||
@@ -60,8 +66,7 @@ GARBAGE += \
|
||||
AndroidManifest.xml \
|
||||
classes.dex \
|
||||
$(MOZ_APP_NAME).apk \
|
||||
App.java \
|
||||
Restarter.java \
|
||||
$(PROCESSEDJAVAFILES) \
|
||||
gecko.ap_ \
|
||||
gecko-unaligned.apk \
|
||||
gecko-unsigned-unaligned.apk \
|
||||
@@ -74,12 +79,22 @@ DIRS = utils
|
||||
# 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_HI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png
|
||||
ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png
|
||||
else
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
# 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
|
||||
$(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
|
||||
|
||||
AndroidManifest.xml App.java Restarter.java : % : %.in
|
||||
AndroidManifest.xml $(PROCESSEDJAVAFILES): % : %.in
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
|
||||
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@
|
||||
|
||||
@@ -135,9 +150,20 @@ res/drawable/icon.png: $(MOZ_APP_ICON)
|
||||
|
||||
res/drawable-hdpi/icon.png: $(MOZ_APP_ICON)
|
||||
$(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 $@
|
||||
|
||||
libs/armeabi/%: $(DIST)/lib/%
|
||||
|
||||
104
embedding/android/NotificationHandler.java.in
Normal file
104
embedding/android/NotificationHandler.java.in
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,9 +56,11 @@ interface nsIAlertsService : nsISupports
|
||||
* consumer during the alert listener callbacks.
|
||||
* @param alertListener Used for callbacks. May be null if the caller
|
||||
* doesn't care about callbacks.
|
||||
* @param name The name of the notification. This is currently
|
||||
* only used on OS X with Growl. On OS X with Growl,
|
||||
* users can disable notifications with a given name.
|
||||
* @param name The name of the notification. This is currently
|
||||
* only used on OS X with Growl and Android.
|
||||
* 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.
|
||||
*
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* Contributor(s):
|
||||
* Scott MacGregor <mscott@netscape.com>
|
||||
* Jens Bannmann <jens.b@web.de>
|
||||
* 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
|
||||
@@ -38,6 +39,11 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsAlertsService.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "AndroidBridge.h"
|
||||
#else
|
||||
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsXPCOM.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"
|
||||
|
||||
#endif // !ANDROID
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsAlertsService)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsAlertsService)
|
||||
|
||||
@@ -74,6 +82,11 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
|
||||
nsIObserver * aAlertListener,
|
||||
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
|
||||
nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID));
|
||||
nsresult rv;
|
||||
@@ -156,4 +169,5 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
|
||||
"chrome,dialog=yes,titlebar=no,popup=yes", argsArray,
|
||||
getter_AddRefs(newWindow));
|
||||
return rv;
|
||||
#endif // !ANDROID
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "nsXPCOMStrings.h"
|
||||
|
||||
#include "AndroidBridge.h"
|
||||
#include "nsAppShell.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@@ -110,6 +111,7 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
||||
jMoveTaskToBack = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "moveTaskToBack", "()V");
|
||||
jGetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getClipboardText", "()Ljava/lang/String;");
|
||||
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"));
|
||||
@@ -403,6 +405,30 @@ AndroidBridge::EmptyClipboard()
|
||||
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
|
||||
AndroidBridge::SetSurfaceView(jobject obj)
|
||||
{
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
#include "AndroidJavaWrappers.h"
|
||||
|
||||
@@ -134,6 +135,13 @@ public:
|
||||
|
||||
bool ClipboardHasText();
|
||||
|
||||
void ShowAlertNotification(const nsAString& aImageUrl,
|
||||
const nsAString& aAlertTitle,
|
||||
const nsAString& aAlertText,
|
||||
const nsAString& aAlertData,
|
||||
nsIObserver *aAlertListener,
|
||||
const nsAString& aAlertName);
|
||||
|
||||
struct AutoLocalJNIFrame {
|
||||
AutoLocalJNIFrame(int nEntries = 128) : mEntries(nEntries) {
|
||||
AndroidBridge::Bridge()->JNI()->PushLocalFrame(mEntries);
|
||||
@@ -191,6 +199,7 @@ protected:
|
||||
jmethodID jMoveTaskToBack;
|
||||
jmethodID jGetClipboardText;
|
||||
jmethodID jSetClipboardText;
|
||||
jmethodID jShowAlertNotification;
|
||||
|
||||
// stuff we need for CallEglCreateWindowSurface
|
||||
jclass jEGLSurfaceImplClass;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsString.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_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_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)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -441,16 +441,17 @@ AndroidRect::Init(JNIEnv *jenv, jobject jobj)
|
||||
}
|
||||
}
|
||||
|
||||
nsJNIString::nsJNIString(jstring jstr)
|
||||
nsJNIString::nsJNIString(jstring jstr, JNIEnv *jenv)
|
||||
{
|
||||
if (!jstr) {
|
||||
SetIsVoid(PR_TRUE);
|
||||
return;
|
||||
}
|
||||
const jchar* jCharPtr = JNI()->GetStringChars(jstr, false);
|
||||
int len = JNI()->GetStringLength(jstr);
|
||||
nsresult rv;
|
||||
JNIEnv *jni = jenv;
|
||||
if (!jni)
|
||||
jni = JNI();
|
||||
const jchar* jCharPtr = jni->GetStringChars(jstr, false);
|
||||
int len = jni->GetStringLength(jstr);
|
||||
Assign(jCharPtr, len);
|
||||
JNI()->ReleaseStringChars(jstr, jCharPtr);
|
||||
|
||||
jni->ReleaseStringChars(jstr, jCharPtr);
|
||||
}
|
||||
|
||||
@@ -468,7 +468,7 @@ public:
|
||||
class nsJNIString : public nsString
|
||||
{
|
||||
public:
|
||||
nsJNIString(jstring jstr);
|
||||
nsJNIString(jstring jstr, JNIEnv *jenv = NULL);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -118,6 +118,8 @@ nsAppShell::Init()
|
||||
mQueueCond = PR_NewCondVar(mCondLock);
|
||||
mPaused = PR_NewCondVar(mPausedLock);
|
||||
|
||||
mObserversHash.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
|
||||
namespace mozilla {
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "nsBaseAppShell.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
|
||||
#include "prcvar.h"
|
||||
|
||||
@@ -70,6 +71,10 @@ public:
|
||||
void RemoveNextEvent();
|
||||
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:
|
||||
virtual void ScheduleNativeEventCallback();
|
||||
virtual ~nsAppShell();
|
||||
@@ -81,6 +86,7 @@ protected:
|
||||
PRCondVar *mQueueCond;
|
||||
PRCondVar *mPaused;
|
||||
nsTArray<mozilla::AndroidGeckoEvent *> mEventQueue;
|
||||
nsInterfaceHashtable<nsStringHashKey, nsIObserver> mObserversHash;
|
||||
|
||||
mozilla::AndroidGeckoEvent *GetNextEvent();
|
||||
mozilla::AndroidGeckoEvent *PeekNextEvent();
|
||||
|
||||
Reference in New Issue
Block a user