Search code examples
androidandroid-notificationsforeground-serviceproximityproximitysensor

startForeground fails to show my notification


startForeground() fails to show the notification below, which is meant to keep a service that monitors the changes in the Proximity sensor alive. There's no error in the logcat.

This's where I start the service

    Intent intent = new Intent(ctx, ProximityService.class);
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        ctx.startForegroundService(intent);
    } else {
        ctx.startService(intent);
    }

ProximityService class

public class ProximityService extends IntentService implements SensorEventListener {

@RequiresApi(api = Build.VERSION_CODES.O)
private void startMyOwnForeground(){

    String NOTIFICATION_CHANNEL_ID = "com.example.xxxxxx";
    String channelName = "Background Proximity Service";
    NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_HIGH);
    chan.setLightColor(Color.BLUE);
    chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    assert manager != null;
    manager.createNotificationChannel(chan);

    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
    Notification notification = notificationBuilder.setOngoing(true)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle("App is running in background")
            .setPriority(NotificationManager.IMPORTANCE_HIGH)
            .setCategory(Notification.CATEGORY_SERVICE)
            .build();
    startForeground(1, notification);
}

@Override
public void onCreate() {
    super.onCreate();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        startMyOwnForeground();
    else
        startForeground(1, new Notification());
}

@Override
public int onStartCommand(Intent aIntent, int aFlags, int aStartId){
    super.onStartCommand(aIntent, aFlags, aStartId);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        startMyOwnForeground();
    else
        startForeground(1, new Notification());


    return START_STICKY;
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {

        if (event.values[0] < event.sensor.getMaximumRange()) {
            // near
            Toast.makeText(getApplicationContext(), "near", Toast.LENGTH_SHORT).show();
        } else {
            // far
            Toast.makeText(getApplicationContext(), "far", Toast.LENGTH_SHORT).show();
        }
    }
}

public ProximityService() {
    super("Proximity Service");
}


protected void onHandleIntent(Intent workIntent) {
    SensorManager m_sensor_manager = (SensorManager) getSystemService(SENSOR_SERVICE);
    Sensor m_prox = m_sensor_manager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

    m_sensor_manager.registerListener(this, m_prox, SensorManager.SENSOR_DELAY_NORMAL);
}

AndroidManifest.xml

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<service android:enabled="true" android:name=".ProximityService"/>

build.gradle

android {
compileSdkVersion 29
buildToolsVersion "29.0.3"

defaultConfig {
    applicationId "com.example.xxxxxx"
    minSdkVersion 16
    targetSdkVersion 29
    versionCode 1
    versionName "1.0"

Solution

  • The problem is that the customized foreground service is extending from the IntentService instead of the Service class; and when the onHandleIntent() get completed, the IntentService will automatically stop, and therefore no notification comes up. Check here for complete understanding.

    So, you need to extend from the Service class, and override onBind() accordingly. So, append it to your class:

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    

    Also notice that the IntentService is deprecated as of API level 30, and replaced by WorkManager or JobIntentService