author | Jim Chen <nchen@mozilla.com> |
Thu, 22 Sep 2016 16:38:19 -0400 | |
changeset 314941 | 4cffc34944279275900d4489a50011268586cee9 |
parent 314940 | 10ce1c1de6b777af5aeabb31698cc91ba3e44ec2 |
child 314942 | d676a611d3ac68dfb398527fae4026629f1b0775 |
push id | 82024 |
push user | nchen@mozilla.com |
push date | Thu, 22 Sep 2016 20:38:38 +0000 |
treeherder | mozilla-inbound@4ead4233329b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | nalexander |
bugs | 1304145 |
milestone | 52.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java @@ -1136,21 +1136,20 @@ public abstract class GeckoApp // GeckoAppShell is tightly coupled to us, rather than // the app context, because various parts of Fennec (e.g., // GeckoScreenOrientation) use GAS to access the Activity in // the guise of fetching a Context. // When that's fixed, `this` can change to // `(GeckoApplication) getApplication()` here. GeckoAppShell.setContextGetter(this); - GeckoAppShell.setApplicationContext(getApplicationContext()); GeckoAppShell.setGeckoInterface(this); // We need to set the notification client before launching Gecko, since Gecko could start // sending notifications immediately after startup, which we don't want to lose/crash on. - GeckoAppShell.setNotificationClient(makeNotificationClient()); + GeckoAppShell.setNotificationListener(makeNotificationClient()); // Tell Stumbler to register a local broadcast listener to listen for preference intents. // We do this via intents since we can't easily access Stumbler directly, // as it might be compiled outside of Fennec. getApplicationContext().sendBroadcast( new Intent(INTENT_REGISTER_STUMBLER_LISTENER) ); @@ -2389,17 +2388,18 @@ public abstract class GeckoApp }); } public void handleNotification(String action, String alertName, String alertCookie) { // If Gecko isn't running yet, we ignore the notification. Note that // even if Gecko is running but it was restarted since the notification // was created, the notification won't be handled (bug 849653). if (GeckoThread.isRunning()) { - GeckoAppShell.handleNotification(action, alertName, alertCookie); + ((NotificationClient) GeckoAppShell.getNotificationListener()).onNotificationClick( + alertName); } } private void checkMigrateProfile() { final File profileDir = getProfile().getDir(); if (profileDir != null) { ThreadUtils.postToBackgroundThread(new Runnable() {
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java @@ -153,16 +153,17 @@ public class GeckoApplication extends Ap @Override public void onCreate() { Log.i(LOG_TAG, "zerdatime " + SystemClock.uptimeMillis() + " - Fennec application start"); mRefWatcher = LeakCanary.install(this); final Context context = getApplicationContext(); + GeckoAppShell.setApplicationContext(context); HardwareUtils.init(context); Clipboard.init(context); FilePicker.init(context); DownloadsIntegration.init(); HomePanelsManager.getInstance().init(context); // This getInstance call will force initialization of the NotificationHelper, but does nothing with the result NotificationHelper.getInstance(context).init();
--- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -264,16 +264,17 @@ gvjar.sources += [geckoview_source_dir + 'gfx/RenderTask.java', 'gfx/SimpleScaleGestureDetector.java', 'gfx/StackScroller.java', 'gfx/SubdocumentScrollHelper.java', 'gfx/SurfaceTextureListener.java', 'gfx/ViewTransform.java', 'InputConnectionListener.java', 'InputMethods.java', + 'NotificationListener.java', 'notifications/AppNotificationClient.java', 'notifications/NotificationClient.java', 'notifications/NotificationHandler.java', 'notifications/NotificationHelper.java', 'notifications/NotificationReceiver.java', 'notifications/NotificationService.java', 'notifications/ServiceNotificationClient.java', 'NSSBridge.java',
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -28,17 +28,16 @@ import java.util.concurrent.ConcurrentHa import android.annotation.SuppressLint; import org.mozilla.gecko.annotation.JNITarget; import org.mozilla.gecko.annotation.RobocopTarget; import org.mozilla.gecko.annotation.WrapForJNI; import org.mozilla.gecko.AppConstants.Versions; import org.mozilla.gecko.gfx.BitmapUtils; import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.gfx.PanZoomController; -import org.mozilla.gecko.notifications.NotificationClient; import org.mozilla.gecko.permissions.Permissions; import org.mozilla.gecko.util.EventCallback; import org.mozilla.gecko.util.GeckoRequest; import org.mozilla.gecko.util.HardwareCodecCapabilityUtils; import org.mozilla.gecko.util.HardwareUtils; import org.mozilla.gecko.util.NativeEventListener; import org.mozilla.gecko.util.NativeJSContainer; import org.mozilla.gecko.util.NativeJSObject; @@ -177,23 +176,16 @@ public class GeckoAppShell public static CrashHandler ensureCrashHandling() { // Crash handling is automatically enabled when GeckoAppShell is loaded. return CRASH_HANDLER; } private static volatile boolean locationHighAccuracyEnabled; - // Accessed by NotificationHelper. This should be encapsulated. - /* package */ static NotificationClient notificationClient; - - public static NotificationClient getNotificationClient() { - return notificationClient; - } - // See also HardwareUtils.LOW_MEMORY_THRESHOLD_MB. private static final int HIGH_MEMORY_DEVICE_THRESHOLD_MB = 768; static private int sDensityDpi; static private int sScreenDepth; /* Is the value in sVibrationEndTime valid? */ private static boolean sVibrationMaybePlaying; @@ -462,17 +454,18 @@ public class GeckoAppShell /* package */ static native void onSensorChanged(int hal_type, float x, float y, float z, float w, int accuracy, long time); @WrapForJNI(calledFrom = "ui", dispatchTo = "gecko") /* package */ static native void onLocationChanged(double latitude, double longitude, double altitude, float accuracy, float bearing, float speed, long time); - private static class DefaultListeners implements SensorEventListener, LocationListener { + private static class DefaultListeners + implements SensorEventListener, LocationListener, NotificationListener { @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } private static int HalSensorAccuracyFor(int androidAccuracy) { switch (androidAccuracy) { case SensorManager.SENSOR_STATUS_UNRELIABLE: return GeckoHalDefines.SENSOR_ACCURACY_UNRELIABLE; @@ -572,36 +565,65 @@ public class GeckoAppShell public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } + + @Override // NotificationListener + public void showNotification(String name, String cookie, String host, + String title, String text, String imageUrl) { + // Default is to not show the notification, and immediate send close message. + GeckoAppShell.onNotificationClose(name); + } + + @Override // NotificationListener + public void showPersistentNotification(String name, String cookie, String host, + String title, String text, String imageUrl, + String data) { + // Default is to not show the notification, and immediate send close message. + GeckoAppShell.onNotificationClose(name); + } + + @Override // NotificationListener + public void closeNotification(String name) { + // Do nothing. + } } private static final DefaultListeners DEFAULT_LISTENERS = new DefaultListeners(); private static SensorEventListener sSensorListener = DEFAULT_LISTENERS; private static LocationListener sLocationListener = DEFAULT_LISTENERS; + private static NotificationListener sNotificationListener = DEFAULT_LISTENERS; public static SensorEventListener getSensorListener() { return sSensorListener; } public static void setSensorListener(final SensorEventListener listener) { - sSensorListener = listener; + sSensorListener = (listener != null) ? listener : DEFAULT_LISTENERS; } public static LocationListener getLocationListener() { return sLocationListener; } public static void setLocationListener(final LocationListener listener) { - sLocationListener = listener; + sLocationListener = (listener != null) ? listener : DEFAULT_LISTENERS; + } + + public static NotificationListener getNotificationListener() { + return sNotificationListener; + } + + public static void setNotificationListener(final NotificationListener listener) { + sNotificationListener = (listener != null) ? listener : DEFAULT_LISTENERS; } @WrapForJNI(calledFrom = "gecko") private static void enableSensor(int aSensortype) { GeckoInterface gi = getGeckoInterface(); if (gi == null) { return; } @@ -916,107 +938,65 @@ public class GeckoAppShell String title) { final GeckoInterface geckoInterface = getGeckoInterface(); if (geckoInterface == null) { return false; } return geckoInterface.openUriExternal(targetURI, mimeType, packageName, className, action, title); } - /** - * Only called from GeckoApp. - */ - public static void setNotificationClient(NotificationClient client) { - if (notificationClient == null) { - notificationClient = client; - } else { - Log.d(LOGTAG, "Notification client already set"); - } - } - - private static PendingIntent makePersistentNotificationIntent(int notificationID, String type, - String persistentData) { - final Uri.Builder b = new Uri.Builder(); - final Uri u = b.scheme("notification-event") - .path(Integer.toString(notificationID)) - .appendQueryParameter("type", type) - .build(); - final Intent intent = GeckoService.getIntentToCreateServices( - getApplicationContext(), type, persistentData); - intent.setData(u); - - return PendingIntent.getService(getApplicationContext(), 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT); - } - @WrapForJNI(dispatchTo = "gecko") private static native void notifyAlertListener(String name, String topic); - @WrapForJNI(calledFrom = "gecko") - private static void showAlertNotification(String imageUrl, String alertTitle, String alertText, - String alertCookie, String alertName, String host, - String persistentData) { - final int notificationID = alertName.hashCode(); - final PendingIntent clickIntent, closeIntent; - - if (persistentData != null) { - clickIntent = makePersistentNotificationIntent( - notificationID, "persistent-notification-click", persistentData); - closeIntent = makePersistentNotificationIntent( - notificationID, "persistent-notification-close", persistentData); - - } else { - notifyAlertListener(alertName, "alertshow"); + /** + * Called by the NotificationListener to notify Gecko that a notification has been + * shown. + */ + public static void onNotificationShow(final String name) { + if (GeckoThread.isRunning()) { + notifyAlertListener(name, "alertshow"); + } + } - // The intent to launch when the user clicks the expanded notification - final Intent notificationIntent = new Intent(ACTION_ALERT_CALLBACK); - notificationIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, - AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS); - notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + /** + * Called by the NotificationListener to notify Gecko that a previously shown + * notification has been closed. + */ + public static void onNotificationClose(final String name) { + if (GeckoThread.isRunning()) { + notifyAlertListener(name, "alertfinished"); + } + } - // Put the strings into the intent as an URI - // "alert:?name=<alertName>&app=<appName>&cookie=<cookie>" - final Uri.Builder b = new Uri.Builder(); - final Uri dataUri = b.scheme("alert") - .path(Integer.toString(notificationID)) - .appendQueryParameter("name", alertName) - .appendQueryParameter("cookie", alertCookie) - .build(); - notificationIntent.setData(dataUri); - - clickIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, - PendingIntent.FLAG_UPDATE_CURRENT); - closeIntent = null; + /** + * Called by the NotificationListener to notify Gecko that a previously shown + * notification has been clicked on. + */ + public static void onNotificationClick(final String name) { + if (GeckoThread.isRunning()) { + notifyAlertListener(name, "alertclickcallback"); } - - notificationClient.add(notificationID, imageUrl, host, alertTitle, - alertText, clickIntent, closeIntent); } @WrapForJNI(calledFrom = "gecko") - private static void closeNotification(String alertName) { - notifyAlertListener(alertName, "alertfinished"); + private static void showNotification(String name, String cookie, String title, + String text, String host, String imageUrl, + String persistentData) { + if (persistentData == null) { + getNotificationListener().showNotification(name, cookie, title, text, host, imageUrl); + return; + } - final int notificationID = alertName.hashCode(); - notificationClient.remove(notificationID); + getNotificationListener().showPersistentNotification( + name, cookie, title, text, host, imageUrl, persistentData); } - public static void handleNotification(String action, String alertName, String alertCookie) { - final int notificationID = alertName.hashCode(); - - if (ACTION_ALERT_CALLBACK.equals(action)) { - notifyAlertListener(alertName, "alertclickcallback"); - - if (notificationClient.isOngoing(notificationID)) { - // When clicked, keep the notification if it displays progress - return; - } - } - - closeNotification(alertName); + @WrapForJNI(calledFrom = "gecko") + private static void closeNotification(String name) { + getNotificationListener().closeNotification(name); } @WrapForJNI(calledFrom = "gecko") public static int getDpi() { if (sDensityDpi == 0) { sDensityDpi = getApplicationContext().getResources().getDisplayMetrics().densityDpi; }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoService.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoService.java @@ -82,18 +82,17 @@ public class GeckoService extends Servic } EventDispatcher.getInstance().unregisterGeckoThreadListener(EVENT_LISTENER, "Gecko:ScheduleRun"); } @Override // Service public void onCreate() { GeckoAppShell.ensureCrashHandling(); - GeckoAppShell.setApplicationContext(getApplicationContext()); - GeckoAppShell.setNotificationClient(new ServiceNotificationClient(getApplicationContext())); + GeckoAppShell.setNotificationListener(new ServiceNotificationClient(getApplicationContext())); GeckoThread.onResume(); super.onCreate(); if (DEBUG) { Log.d(LOGTAG, "Created"); } }
new file mode 100644 --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/NotificationListener.java @@ -0,0 +1,17 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +public interface NotificationListener +{ + void showNotification(String name, String cookie, String title, String text, + String host, String imageUrl); + + void showPersistentNotification(String name, String cookie, String title, String text, + String host, String imageUrl, String data); + + void closeNotification(String name); +}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/notifications/NotificationHelper.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/notifications/NotificationHelper.java @@ -298,17 +298,17 @@ public final class NotificationHelper im } } PendingIntent pi = buildNotificationPendingIntent(message, CLICK_EVENT); builder.setContentIntent(pi); PendingIntent deletePendingIntent = buildNotificationPendingIntent(message, CLEARED_EVENT); builder.setDeleteIntent(deletePendingIntent); - GeckoAppShell.getNotificationClient().add(id.hashCode(), builder.build()); + ((NotificationClient) GeckoAppShell.getNotificationListener()).add(id.hashCode(), builder.build()); boolean persistent = message.optBoolean(PERSISTENT_ATTR); // We add only not persistent notifications to the list since we want to purge only // them when geckoapp is destroyed. if (!persistent && !mClearableNotifications.containsKey(id)) { mClearableNotifications.put(id, message.toString()); } } @@ -339,17 +339,17 @@ public final class NotificationHelper im Log.i(LOGTAG, "Send " + args.toString()); GeckoAppShell.notifyObservers("Notification:Event", args.toString()); } catch (JSONException ex) { Log.e(LOGTAG, "sendNotificationWasClosed: error building JSON notification arguments.", ex); } } private void closeNotification(String id, String handlerKey, String cookie) { - GeckoAppShell.getNotificationClient().remove(id.hashCode()); + ((NotificationClient) GeckoAppShell.getNotificationListener()).remove(id.hashCode()); sendNotificationWasClosed(id, handlerKey, cookie); } public void hideNotification(String id, String handlerKey, String cookie) { mClearableNotifications.remove(id); closeNotification(id, handlerKey, cookie); }
--- a/widget/android/AndroidAlerts.cpp +++ b/widget/android/AndroidAlerts.cpp @@ -79,18 +79,18 @@ AndroidAlerts::ShowPersistentNotificatio if (aPersistentData.IsEmpty() && aAlertListener) { if (!sAlertInfoMap) { sAlertInfoMap = new AlertInfoMap(); } // This will remove any observers already registered for this name. sAlertInfoMap->Put(name, new AlertInfo{aAlertListener, cookie}); } - java::GeckoAppShell::ShowAlertNotification( - imageUrl, title, text, cookie, name, host, + java::GeckoAppShell::ShowNotification( + name, cookie, title, text, host, imageUrl, !aPersistentData.IsEmpty() ? jni::StringParam(aPersistentData) : jni::StringParam(nullptr)); return NS_OK; } NS_IMETHODIMP AndroidAlerts::CloseAlert(const nsAString& aAlertName, nsIPrincipal* aPrincipal)