question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[android][expo-location][bare] How to change the foreground service icon ?

See original GitHub issue

Hi, I use expo-location in a bare React Native app :

 "expo-constants": "9.0.0",
 "expo-location": "8.1.0",
 "expo-task-manager": "8.1.0",
 "react": "16.11.0",
 "react-native": "0.62.0",

When I start a foregroundTask via startLocationUpdatesAsync a default notification icon is displayed.

Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
            accuracy: Location.Accuracy.BestForNavigation,
            distanceInterval: 20, //meters
            //ios
            showsBackgroundLocationIndicator: true,
            activityType: Location.ActivityType.AutomotiveNavigation,
            pausesUpdatesAutomatically: true,
            //android
            timeInterval: 1000, //milliseconds
            foregroundService: {
              notificationTitle: 'Title',
              notificationBody: 'body,
              notificationColor: '#FF00FF',
            },
          });

I would like to know how I can change the foreground icon ? As I can see in the LocationTaskService.java file, the icon comes from “getApplicationInfo().icon”.
How can I override this icon ?
I try to update my app.json file but with no success

{
  "name": "MyApp",
  "displayName": "My App",
  "icon": "./src/assets/images/Icon-1024x1024.png",
  "expo": {
    "icon": "./src/assets/images/Icon-1024x1024.png",
    "notification": {
      "icon": "./src/assets/images/Icon-1024x1024.png"
    }
  }
}

97248610_2510378145729649_4703329904580624384_n

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:19 (6 by maintainers)

github_iconTop GitHub Comments

3reactions
araboldcommented, Aug 16, 2021

@andkom 's answer helped me a lot and now the app uses the same icon for location as it does for notifications. I created a patch file that can be applied using patch-package

To apply the patch in your build, follow these steps:

  1. Install patch-package

    npm install patch-package --save-dev
    
  2. Create a new file patches/expo-location+12.1.2.patch and copy-paste the following code.

    diff --git a/node_modules/expo-location/android/src/main/java/expo/modules/location/services/LocationTaskService.java b/node_modules/expo-location/android/src/main/java/expo/modules/location/services/LocationTaskService.java
    index 444eb33..6ab4098 100644
    --- a/node_modules/expo-location/android/src/main/java/expo/modules/location/services/LocationTaskService.java
    +++ b/node_modules/expo-location/android/src/main/java/expo/modules/location/services/LocationTaskService.java
    @@ -9,9 +9,15 @@ import android.app.PendingIntent;
     import android.app.Service;
     import android.content.Context;
     import android.content.Intent;
    +import android.content.pm.ApplicationInfo;
    +import android.content.pm.PackageManager;
    +import android.content.res.Resources;
    +import android.graphics.Bitmap;
    +import android.graphics.BitmapFactory;
     import android.graphics.Color;
     import android.net.Uri;
     import android.os.Binder;
    +import android.os.Build;
     import android.os.Bundle;
     import android.os.IBinder;
     import androidx.annotation.Nullable;
    @@ -26,6 +32,11 @@ public class LocationTaskService extends Service {
       private int mServiceId = sServiceId++;
       private final IBinder mBinder = new ServiceBinder();
     
    +  // Code based on https://github.com/expo/expo/issues/8260#issuecomment-673363086
    +  public static final String META_DATA_DEFAULT_ICON_KEY = "expo.modules.notifications.default_notification_icon";
    +  public static final String META_DATA_LARGE_ICON_KEY = "expo.modules.notifications.large_notification_icon";
    +  public static final String META_DATA_DEFAULT_COLOR_KEY = "expo.modules.notifications.default_notification_color";
    +
       public class ServiceBinder extends Binder {
         public LocationTaskService getService() {
           return LocationTaskService.this;
    @@ -75,6 +86,58 @@ public class LocationTaskService extends Service {
     
       //region private
     
    +  protected int getIcon() {
    +    try {
    +      ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
    +      if (ai.metaData.containsKey(META_DATA_DEFAULT_ICON_KEY)) {
    +        return ai.metaData.getInt(META_DATA_DEFAULT_ICON_KEY);
    +      }
    +    } catch (PackageManager.NameNotFoundException | ClassCastException e) {
    +      Log.e("expo-location", "Could not have fetched default notification icon.");
    +    }
    +    return getApplicationInfo().icon;
    +  }
    +
    +
    +  @Nullable
    +  protected Bitmap getLargeIcon() {
    +    try {
    +      ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
    +      if (ai.metaData.containsKey(META_DATA_LARGE_ICON_KEY)) {
    +        int resourceId = ai.metaData.getInt(META_DATA_LARGE_ICON_KEY);
    +        return BitmapFactory.decodeResource(getResources(), resourceId);
    +      }
    +    } catch (PackageManager.NameNotFoundException | ClassCastException e) {
    +      Log.e("expo-location", "Could not have fetched large notification icon.");
    +    }
    +    return null;
    +  }
    +
    +  @Nullable
    +  protected Integer getColor(Bundle serviceOptions) {
    +    Integer color = colorStringToInteger(serviceOptions.getString("notificationColor"));
    +
    +    if (color != null) {
    +      return color;
    +    }
    +
    +    try {
    +      ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
    +      if (ai.metaData.containsKey(META_DATA_DEFAULT_COLOR_KEY)) {
    +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    +          return getResources().getColor(ai.metaData.getInt(META_DATA_DEFAULT_COLOR_KEY), null);
    +        } else {
    +          return getResources().getColor(ai.metaData.getInt(META_DATA_DEFAULT_COLOR_KEY));
    +        }
    +      }
    +    } catch (PackageManager.NameNotFoundException | Resources.NotFoundException | ClassCastException e) {
    +      Log.e("expo-location", "Could not have fetched default notification color.");
    +    }
    +
    +    // No custom color
    +    return null;
    +  }
    +
       @TargetApi(26)
       private Notification buildServiceNotification(Bundle serviceOptions) {
         prepareChannel(mChannelId);
    @@ -83,7 +146,7 @@ public class LocationTaskService extends Service {
     
         String title = serviceOptions.getString("notificationTitle");
         String body = serviceOptions.getString("notificationBody");
    -    Integer color = colorStringToInteger(serviceOptions.getString("notificationColor"));
    +    Integer color = getColor(serviceOptions);
     
         if (title != null) {
           builder.setContentTitle(title);
    @@ -106,7 +169,8 @@ public class LocationTaskService extends Service {
         }
     
         return builder.setCategory(Notification.CATEGORY_SERVICE)
    -        .setSmallIcon(getApplicationInfo().icon)
    +        .setSmallIcon(getIcon())
    +        .setLargeIcon(getLargeIcon())
             .build();
       }
     
    
    
  3. Update your package.json to run patch-package after each install:

    "scripts": {
      "postinstall": "patch-package",
      ...
    }
    
  4. Run npm install followed by npm run android. The icon should be updated.

I’m not sure if the team is already working on a different way of setting the default icon, but I can provide a pull request if that is desired.

2reactions
Tommuhcommented, Jan 20, 2021

Thanks, I will make a feature request.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to change the status bar icon while service is running
The workaround is to just create a new notification with a new icon, so it'll replace the old one. EDIT: Here's a sample...
Read more >
Foreground services - Android Developers
The service has opted out of the behavior change by passing FOREGROUND_SERVICE_IMMEDIATE into setForegroundServiceBehavior() when setting up the notification.
Read more >
Foreground service icon appears in status bar on Android 8.1
Since roughly Android 4.2, the foreground service icon hasn't been visible in the status bar, but it has become visible again on Android...
Read more >
How to Start a Foreground Service in Android (With ... - YouTube
In this video we will learn how to start a foreground service in Android, which runs independently from other app components (like ...
Read more >
flutter_foreground_task | Flutter Package - Pub.dev
This plugin is used to implement a foreground service on the Android platform ... flutter_foreground_task 3.10.0 icon indicating copy to clipboard operation.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found