Bug 1474961 - Change StumblerService to a foreground service when targeting Android Oreo. r?sdaswani draft
authorVlad Baicu <vlad.baicu@softvision.ro>
Wed, 11 Jul 2018 20:02:24 +0300
changeset 816943 b7408548bf2f8518e5f4654c8230754e959f4011
parent 816856 aff060ad3204234adae2d59b3776207c6687ebfc
push id115894
push uservbaicu@mozilla.com
push dateWed, 11 Jul 2018 17:02:59 +0000
reviewerssdaswani
bugs1474961
milestone63.0a1
Bug 1474961 - Change StumblerService to a foreground service when targeting Android Oreo. r?sdaswani Also made broadcasts involving Stumbler explicit. MozReview-Commit-ID: 7CK2Cr2JqX0
mobile/android/app/src/main/res/values/ids.xml
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/strings.xml.in
mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/LocalPreferenceReceiver.java
mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SystemReceiver.java
mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java
--- a/mobile/android/app/src/main/res/values/ids.xml
+++ b/mobile/android/app/src/main/res/values/ids.xml
@@ -13,13 +13,14 @@
     <item type="id" name="menu_margin"/>
     <item type="id" name="recycler_view_click_support" />
     <item type="id" name="range_list"/>
     <item type="id" name="pref_header_general"/>
     <item type="id" name="pref_header_privacy"/>
     <item type="id" name="pref_header_search"/>
     <item type="id" name="updateServicePermissionNotification" />
     <item type="id" name="foregroundNotification" />
+    <item type="id" name="stumblerNotification" />
     <item type="id" name="actionbar"/>
     <item type="id" name="action_button"/>
     <item type="id" name="page_progress"/>
     <item type="id" name="mediaControlNotification"/>
 </resources>
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -85,16 +85,17 @@ import android.widget.ListView;
 import android.widget.RelativeLayout;
 import android.widget.SimpleAdapter;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.mozilla.mozstumbler.service.mainthread.SafeReceiver;
 
 import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
@@ -980,19 +981,19 @@ public abstract class GeckoApp extends G
             Class.forName("android.os.AsyncTask");
         } catch (ClassNotFoundException e) { }
 
         GeckoAppShell.setScreenOrientationDelegate(this);
 
         // 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)
-        );
+        final Intent stumblerIntent = new Intent(getApplicationContext(), SafeReceiver.class);
+        stumblerIntent.setAction(INTENT_REGISTER_STUMBLER_LISTENER);
+        getApplicationContext().sendBroadcast(stumblerIntent);
 
         // Did the OS locale change while we were backgrounded? If so,
         // we need to die so that Gecko will re-init add-ons that touch
         // the UI.
         // This is using a sledgehammer to crack a nut, but it'll do for
         // now.
         // Our OS locale pref will be detected as invalid after the
         // restart, and will be propagated to Gecko accordingly, so there's
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -434,16 +434,21 @@
 <!ENTITY datareporting_telemetry_title "Telemetry">
 <!ENTITY datareporting_telemetry_summary "Shares performance, usage, hardware and customization data about your browser with &vendorShortName; to help us make &brandShortName; better">
 <!ENTITY datareporting_crashreporter_summary "&brandShortName; submits crash reports to help &vendorShortName; make your browser more stable and secure">
 <!-- Localization note (datareporting_crashreporter_title_short) : This string matches
      (crashReporterSection.label) in en-US/chrome/browser/preferences/advanced.dtd.-->
 <!ENTITY datareporting_crashreporter_title_short "Crash Reporter">
 <!ENTITY datareporting_wifi_title2 "&vendorShortName; Location Service">
 <!ENTITY datareporting_wifi_geolocation_summary4 "Help &vendorShortName; map the world! Share the approximate Wi-Fi and cellular location of your device to improve our geolocation service.">
+<!-- Localization note (datareporting_notification_title ) : This will be the title
+     of the notification shown whenever the user has enabled data reporting and the stumbler
+     service is running. -->
+<!ENTITY datareporting_stumbler_notification_title "&vendorShortName; Location Service running">
+
 <!-- Localization note (pref_update_autodownload2) : This should mention downloading
      specifically, since the pref only prevents automatic downloads and not the
      actual notification that an update is available. -->
 <!ENTITY pref_update_autodownload3 "Automatic updates">
 <!ENTITY pref_update_autodownload_wifi "Only over Wi-Fi">
 <!ENTITY pref_update_autodownload_never "Never">
 <!ENTITY pref_update_autodownload_always "Always">
 
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -337,16 +337,17 @@
   <string name="datareporting_telemetry_title">&datareporting_telemetry_title;</string>
   <string name="datareporting_telemetry_summary">&datareporting_telemetry_summary;</string>
   <string name="datareporting_fhr_title">&datareporting_fhr_title;</string>
   <string name="datareporting_fhr_summary2">&datareporting_fhr_summary2;</string>
   <string name="datareporting_crashreporter_title_short">&datareporting_crashreporter_title_short;</string>
   <string name="datareporting_crashreporter_summary">&datareporting_crashreporter_summary;</string>
   <string name="datareporting_wifi_title">&datareporting_wifi_title2;</string>
   <string name="datareporting_wifi_geolocation_summary">&datareporting_wifi_geolocation_summary4;</string>
+  <string name="datareporting_stumbler_notification_title">&datareporting_stumbler_notification_title;</string>
 
   <string name="search">&search;</string>
   <string name="reload">&reload;</string>
   <string name="forward">&forward;</string>
   <string name="menu">&menu;</string>
   <string name="back">&back;</string>
   <string name="stop">&stop;</string>
   <string name="site_security">&site_security;</string>
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/LocalPreferenceReceiver.java
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/LocalPreferenceReceiver.java
@@ -1,35 +1,37 @@
 /* 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.mozstumbler.service.mainthread;
-
+import android.annotation.SuppressLint;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.util.Log;
 
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.mozstumbler.service.AppGlobals;
 import org.mozilla.mozstumbler.service.stumblerthread.StumblerService;
 
 /**
  * Starts the StumblerService, an Intent service, which by definition runs on its own thread.
  * Registered as a local broadcast receiver in SafeReceiver.
  * Starts the StumblerService in passive listening mode.
  *
  * The received intent contains enabled state, upload API key and user agent,
  * and is used to initialize the StumblerService.
  */
 public class LocalPreferenceReceiver extends BroadcastReceiver {
     // This allows global debugging logs to be enabled by doing
     // |adb shell setprop log.tag.PassiveStumbler DEBUG|
     static final String LOG_TAG = "PassiveStumbler";
 
+    @SuppressLint("NewApi")
     @Override
     public void onReceive(Context context, Intent intent) {
         if (intent == null) {
             return;
         }
 
         // This value is cached, so if |setprop| is performed (as described on the LOG_TAG above),
         // then the start/stop intent must be resent by toggling the setting or stopping/starting Fennec.
@@ -59,12 +61,17 @@ public class LocalPreferenceReceiver ext
                 StumblerService.ACTION_EXTRA_MOZ_API_KEY,
                 intent.getStringExtra("moz_mozilla_api_key")
         );
         startServiceIntent.putExtra(
                 StumblerService.ACTION_EXTRA_USER_AGENT,
                 intent.getStringExtra("user_agent")
         );
 
-        context.startService(startServiceIntent);
+        intent.setClass(context, StumblerService.class);
+        if (AppConstants.Versions.preO) {
+            context.startService(intent);
+        } else {
+            context.startForegroundService(intent);
+        }
     }
 }
 
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SystemReceiver.java
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/mainthread/SystemReceiver.java
@@ -1,41 +1,48 @@
 /* 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.mozstumbler.service.mainthread;
 
+import android.annotation.SuppressLint;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.text.TextUtils;
 import android.util.Log;
 
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.mozstumbler.service.stumblerthread.StumblerService;
 
 /**
  * Responsible for starting StumblerService in response to
  * BOOT_COMPLETE and EXTERNAL_APPLICATIONS_AVAILABLE system intents.
  */
 public class SystemReceiver extends BroadcastReceiver {
     static final String LOG_TAG = "StumblerSystemReceiver";
 
+    @SuppressLint("NewApi")
     @Override
     public void onReceive(Context context, Intent intent) {
         if (intent == null) {
             return;
         }
 
         final String action = intent.getAction();
 
         if (!TextUtils.equals(action, Intent.ACTION_BOOT_COMPLETED) && !TextUtils.equals(action, Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE)) {
             // This is not the broadcast you are looking for.
             return;
         }
 
         final Intent startServiceIntent = new Intent(context, StumblerService.class);
         startServiceIntent.putExtra(StumblerService.ACTION_NOT_FROM_HOST_APP, true);
-        context.startService(startServiceIntent);
+        if (AppConstants.Versions.preO) {
+            context.startService(startServiceIntent);
+        } else {
+            context.startForegroundService(startServiceIntent);
+        }
 
         Log.d(LOG_TAG, "Responded to a system intent");
     }
 }
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/StumblerService.java
@@ -1,25 +1,31 @@
 /* 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.mozstumbler.service.stumblerthread;
 
 import android.Manifest;
+import android.annotation.SuppressLint;
+import android.app.Notification;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.location.Location;
 import android.os.AsyncTask;
+import android.support.v4.app.NotificationCompat;
 import android.support.v4.content.ContextCompat;
 import android.util.Log;
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.GeckoApplication;
+import org.mozilla.gecko.R;
 import org.mozilla.mozstumbler.service.AppGlobals;
 import org.mozilla.mozstumbler.service.Prefs;
 import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface;
 import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
 import org.mozilla.mozstumbler.service.stumblerthread.scanners.ScanManager;
 import org.mozilla.mozstumbler.service.uploadthread.UploadAlarmReceiver;
 import org.mozilla.mozstumbler.service.utils.PersistentIntentService;
 
@@ -127,16 +133,33 @@ public class StumblerService extends Per
 
     // Called from the main thread.
     @Override
     public void onCreate() {
         super.onCreate();
         setIntentRedelivery(true);
     }
 
+    @Override
+    @SuppressLint("NewApi")
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (!AppConstants.Versions.preO) {
+            final Notification notification = new NotificationCompat.Builder(this, GeckoApplication.getDefaultNotificationChannel().getId())
+                    .setSmallIcon(R.drawable.ic_status_logo)
+                    .setContentTitle(getString(R.string.datareporting_stumbler_notification_title))
+                    .setOngoing(true)
+                    .setShowWhen(false)
+                    .setWhen(0)
+                    .build();
+
+            startForeground(R.id.stumblerNotification, notification);
+        }
+        return START_STICKY;
+    }
+
     // Called from the main thread
     @Override
     public void onDestroy() {
         super.onDestroy();
 
         if (!mScanManager.isScanning()) {
             return;
         }