Bug 1004734 - Create system notification on browser update. r=liuche,mfinkle
MozReview-Commit-ID: DsVhO2kagZB
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -249,16 +249,25 @@
<service android:name="org.mozilla.gecko.Restarter"
android:exported="false"
android:process="@MANGLED_ANDROID_PACKAGE_NAME@.Restarter">
</service>
<receiver android:name="org.mozilla.gecko.AlarmReceiver" >
</receiver>
+ <receiver
+ android:name="org.mozilla.gecko.notifications.WhatsNewReceiver"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_REPLACED" />
+ <data android:scheme="package" android:path="org.mozilla.gecko" />
+ </intent-filter>
+ </receiver>
+
#include ../services/manifests/FxAccountAndroidManifest_activities.xml.in
#ifdef MOZ_ANDROID_SEARCH_ACTIVITY
#include ../search/manifests/SearchAndroidManifest_activities.xml.in
#endif
#if MOZ_CRASHREPORTER
<activity android:name="org.mozilla.gecko.CrashReporter"
android:process="@ANDROID_PACKAGE_NAME@.CrashReporter"
--- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java
@@ -16,33 +16,32 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.annotation.JNITarget;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.favicons.Favicons;
import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent;
-import org.mozilla.gecko.preferences.GeckoPreferences;
+import org.mozilla.gecko.notifications.WhatsNewReceiver;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.OnAccountsUpdateListener;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.sqlite.SQLiteException;
import android.graphics.Color;
import android.net.Uri;
import android.os.Handler;
import android.provider.Browser;
import android.util.Log;
-import android.content.SharedPreferences;
public class Tabs implements GeckoEventListener {
private static final String LOGTAG = "GeckoTabs";
// mOrder and mTabs are always of the same cardinality, and contain the same values.
private final CopyOnWriteArrayList<Tab> mOrder = new CopyOnWriteArrayList<Tab>();
// All writes to mSelectedTab must be synchronized on the Tabs instance.
@@ -814,16 +813,23 @@ public class Tabs implements GeckoEventL
*
* @return the Tab if a new one was created; null otherwise
*/
public Tab loadUrl(String url, int flags) {
return loadUrl(url, null, -1, null, flags);
}
public Tab loadUrlWithIntentExtras(final String url, final SafeIntent intent, final int flags) {
+ // We can't directly create a listener to tell when the user taps on the "What's new"
+ // notification, so we use this intent handling as a signal that they tapped the notification.
+ if (intent.getBooleanExtra(WhatsNewReceiver.EXTRA_WHATSNEW_NOTIFICATION, false)) {
+ Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.NOTIFICATION,
+ WhatsNewReceiver.EXTRA_WHATSNEW_NOTIFICATION);
+ }
+
// Note: we don't get the URL from the intent so the calling
// method has the opportunity to change the URL if applicable.
return loadUrl(url, null, -1, intent, flags);
}
public Tab loadUrl(final String url, final String searchEngine, final int parentId, final int flags) {
return loadUrl(url, searchEngine, parentId, null, flags);
}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/notifications/WhatsNewReceiver.java
@@ -0,0 +1,87 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.notifications;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.v4.app.NotificationCompat;
+import android.text.TextUtils;
+import android.util.Log;
+import com.keepsafe.switchboard.SwitchBoard;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.Locales;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
+import org.mozilla.gecko.util.Experiments;
+
+import java.util.Locale;
+
+public class WhatsNewReceiver extends BroadcastReceiver {
+
+ public static final String EXTRA_WHATSNEW_NOTIFICATION = "whatsnew_notification";
+ private static final String ACTION_NOTIFICATION_CANCELLED = "notification_cancelled";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_NOTIFICATION_CANCELLED.equals(intent.getAction())) {
+ Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL, TelemetryContract.Method.NOTIFICATION, EXTRA_WHATSNEW_NOTIFICATION);
+ return;
+ }
+
+ final String dataString = intent.getDataString();
+ if (TextUtils.isEmpty(dataString) || !dataString.contains(AppConstants.ANDROID_PACKAGE_NAME)){
+ return;
+ }
+
+ if (SwitchBoard.isInExperiment(context, Experiments.WHATSNEW_NOTIFICATION)) {
+ showWhatsNewNotification(context);
+ }
+ }
+
+ private void showWhatsNewNotification(Context context) {
+ final Notification notification = new NotificationCompat.Builder(context)
+ .setContentTitle(context.getString(R.string.whatsnew_notification_title))
+ .setContentText(context.getString(R.string.whatsnew_notification_summary))
+ .setSmallIcon(R.drawable.ic_status_logo)
+ .setAutoCancel(true)
+ .setContentIntent(getContentIntent(context))
+ .setDeleteIntent(getDeleteIntent(context))
+ .build();
+
+ final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ final int notificationID = EXTRA_WHATSNEW_NOTIFICATION.hashCode();
+ notificationManager.notify(notificationID, notification);
+
+ Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.NOTIFICATION, EXTRA_WHATSNEW_NOTIFICATION);
+ }
+
+ private PendingIntent getContentIntent(Context context) {
+ final String link = context.getString(R.string.whatsnew_notification_url,
+ AppConstants.MOZ_APP_VERSION,
+ AppConstants.OS_TARGET,
+ Locales.getLanguageTag(Locale.getDefault()));
+
+ final Intent i = new Intent(Intent.ACTION_VIEW);
+ i.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
+ i.setData(Uri.parse(link));
+ i.putExtra(EXTRA_WHATSNEW_NOTIFICATION, true);
+
+ return PendingIntent.getActivity(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ private PendingIntent getDeleteIntent(Context context) {
+ final Intent i = new Intent(context, WhatsNewReceiver.class);
+ i.setAction(ACTION_NOTIFICATION_CANCELLED);
+
+ return PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+}
--- a/mobile/android/base/java/org/mozilla/gecko/util/Experiments.java
+++ b/mobile/android/base/java/org/mozilla/gecko/util/Experiments.java
@@ -20,26 +20,30 @@ import java.util.List;
* https://github.com/mozilla-services/switchboard-experiments
*/
public class Experiments {
private static final String LOGTAG = "GeckoExperiments";
// Display History and Bookmarks in 3-dot menu.
public static final String BOOKMARKS_HISTORY_MENU = "bookmark-history-menu";
- // Onboarding: "Features and Story"
+ // Show search mode (instead of home panels) when tapping on urlbar if there is a search term in the urlbar.
+ public static final String SEARCH_TERM = "search-term";
+
+ // Show a system notification linking to a "What's New" page on app update.
+ public static final String WHATSNEW_NOTIFICATION = "whatsnew-notification";
+
+ // Onboarding: "Features and Story". These experiments are determined
+ // on the client, they are not part of the server config.
public static final String ONBOARDING2_A = "onboarding2-a"; // Control: Single (blue) welcome screen
public static final String ONBOARDING2_B = "onboarding2-b"; // 4 static Feature slides
public static final String ONBOARDING2_C = "onboarding2-c"; // 4 static + 1 clickable (Data saving) Feature slides
public static final String PREF_ONBOARDING_VERSION = "onboarding_version";
- // Show search mode (instead of home panels) when tapping on urlbar if there is a search term in the urlbar.
- public static final String SEARCH_TERM = "search-term";
-
private static volatile Boolean disabled = null;
/**
* Determines whether Switchboard is disabled by the MOZ_DISABLE_SWITCHBOARD
* environment variable. We need to read this value from the intent string
* extra because environment variables from our test harness aren't set
* until Gecko is loaded, and we need to know this before then.
*
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -773,8 +773,13 @@ just addresses the organization to follo
<!-- LOCALIZATION NOTE (unsupported_sdk_version): The user installed a build of this app that does not support
the Android version of this device. the formatS1 is replaced by the CPU ABI (e.g., ARMv7); the formatS2 is
replaced by the Android OS version (e.g., 14)-->
<!ENTITY unsupported_sdk_version "Sorry! This &brandShortName; won\'t work on this device (&formatS1;, &formatS2;). Please download the correct version.">
<!ENTITY eol_notification_title "&brandShortName; no longer supports Android 3">
<!ENTITY eol_notification_summary "Tap to learn more">
+
+<!-- LOCALIZATION NOTE (whatsnew_notification_title, whatsnew_notification_summary): These strings
+ are used for a system notification that's shown to users after the app updates. -->
+<!ENTITY whatsnew_notification_title "&brandShortName; is up to date">
+<!ENTITY whatsnew_notification_summary "Find out what\'s new in this version">
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -436,16 +436,17 @@ gbjar.sources += ['java/org/mozilla/geck
'menu/MenuItemSwitcherLayout.java',
'menu/MenuPanel.java',
'menu/MenuPopup.java',
'menu/QuickShareBarActionView.java',
'MotionEventInterceptor.java',
'NotificationClient.java',
'NotificationHandler.java',
'NotificationHelper.java',
+ 'notifications/WhatsNewReceiver.java',
'NotificationService.java',
'NSSBridge.java',
'OrderedBroadcastHelper.java',
'overlays/OverlayConstants.java',
'overlays/service/OverlayActionService.java',
'overlays/service/ShareData.java',
'overlays/service/sharemethods/AddBookmark.java',
'overlays/service/sharemethods/AddToReadingList.java',
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -606,9 +606,14 @@
<string name="devtools_auth_scan_header">&devtools_auth_scan_header;</string>
<string name="unsupported_sdk_version">&unsupported_sdk_version;</string>
<string name="eol_notification_title">&eol_notification_title;</string>
<string name="eol_notification_summary">&eol_notification_summary;</string>
<!-- https://support.mozilla.org/1/mobile/%VERSION%/%OS%/%LOCALE%/honeycomb -->
<string name="eol_notification_url">https://support.mozilla.org/1/mobile/&formatS1;/&formatS2;/&formatS3;/honeycomb</string>
+
+ <string name="whatsnew_notification_title">&whatsnew_notification_title;</string>
+ <string name="whatsnew_notification_summary">&whatsnew_notification_summary;</string>
+ <!-- https://support.mozilla.org/1/mobile/%VERSION%/%OS%/%LOCALE%/new-android -->
+ <string name="whatsnew_notification_url">https://support.mozilla.org/1/mobile/&formatS1;/&formatS2;/&formatS3;/new-android</string>
</resources>