I have an app that requires capturing location information in a foreground service. It has been working until I raised my SDK versions to API 34 based on other needs. I understand there are new requirements for foreground services in API 34 and have done my best to follow the recommended changes. From testing, the parameters getting passed in ForegroundLocationService.class statement
ServiceCompat.startForeground(this, 100, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
is lost when it goes through SystemForegroundService.class and causes the error as follows:
FATAL EXCEPTION: main
Process: com.grgmobilesolutions.peepsconnection, PID: 18488
android.app.InvalidForegroundServiceTypeException: Starting FGS with type none callerApp=ProcessRecord{ed24bae 18488:com.grgmobilesolutions.peepsconnection/u0a190} targetSDK=34 has been prohibited
at android.app.InvalidForegroundServiceTypeException$1.createFromParcel(InvalidForegroundServiceTypeException.java:53)
at android.app.InvalidForegroundServiceTypeException$1.createFromParcel(InvalidForegroundServiceTypeException.java:49)
at android.os.Parcel.readParcelableInternal(Parcel.java:4870)
at android.os.Parcel.readParcelable(Parcel.java:4852)
at android.os.Parcel.createExceptionOrNull(Parcel.java:3052)
at android.os.Parcel.createException(Parcel.java:3041)
at android.os.Parcel.readException(Parcel.java:3024)
at android.os.Parcel.readException(Parcel.java:2966)
at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:6761)
at android.app.Service.startForeground(Service.java:862)
at androidx.work.impl.foreground.SystemForegroundService$Api29Impl.startForeground(SystemForegroundService.java:173)
at androidx.work.impl.foreground.SystemForegroundService$1.run(SystemForegroundService.java:127)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
The following is my manifest items for permissions and the services
<service
android:name="ForegroundLocationService"
android:foregroundServiceType="location"
android:enabled="true"
android:exported="true">
</service>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
The following is my ForegroundLocationService.class
package com.grgmobilesolutions.peepsconnection;
import static android.content.ContentValues.TAG;
import android.Manifest;
import android.app.Service;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.ServiceCompat;
import androidx.core.content.ContextCompat;
import com.bugfender.sdk.Bugfender;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.function.Consumer;
public class ForegroundLocationService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
public PendingIntent pendingIntent;
public Context context;
public BroadcastReceiver receiver;
public IntentFilter intentFilter;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
//Log.i(TAG, "LocationWorkManager ForegroundLocationService appLifecycleEvent onCreate: ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Log.i(TAG, "LocationWorkManager " + Thread.currentThread().getId() + " ForegroundLocationService appLifecycleEvent onStartCommand: ");
context = getApplicationContext();
String input = "PeepsConnection is capturing current location if you have an open check in";
createNotificationChannel();
Intent notificationIntent = new Intent(this, Login.class);
// this is to verify permissions take out after testing
boolean permissionGrantedStatus = (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
if (!permissionGrantedStatus) {
Bugfender.e(TAG, "ForegroundLocationService onStartCommand: ACCESS_FINE_LOCATION= " + permissionGrantedStatus);
}
permissionGrantedStatus = (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED);
if (!permissionGrantedStatus) {
Bugfender.e(TAG, "ForegroundLocationService onStartCommand: ACCESS_COARSE_LOCATION= " + permissionGrantedStatus);
}
permissionGrantedStatus = (ContextCompat.checkSelfPermission(context,
Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE) == PackageManager.PERMISSION_GRANTED);
if (!permissionGrantedStatus) {
Bugfender.e(TAG, "ForegroundLocationService onStartCommand: FOREGROUND_SERVICE_CONNECSTED_DEVICE= " + permissionGrantedStatus);
}
permissionGrantedStatus = (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED);
if (!permissionGrantedStatus) {
Bugfender.e(TAG, "ForegroundLocationService onStartCommand: ACCESS_BACKGROUND_LOCATION= " + permissionGrantedStatus);
}
permissionGrantedStatus = (ContextCompat.checkSelfPermission(context,
Manifest.permission.FOREGROUND_SERVICE) == PackageManager.PERMISSION_GRANTED);
if (!permissionGrantedStatus) {
Bugfender.e(TAG, "ForegroundLocationService onStartCommand: FOREGROUND_SERVICE= " + permissionGrantedStatus);
}
permissionGrantedStatus = (ContextCompat.checkSelfPermission(context,
Manifest.permission.FOREGROUND_SERVICE_LOCATION) == PackageManager.PERMISSION_GRANTED);
if (!permissionGrantedStatus) {
Bugfender.e(TAG, "ForegroundLocationService onStartCommand: FOREGROUND_SERVICE_LOCATION= " + permissionGrantedStatus);
}
// through here
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
(ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
(ContextCompat.checkSelfPermission(context,
Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE) == PackageManager.PERMISSION_GRANTED &&
(ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED &&
(ContextCompat.checkSelfPermission(context,
Manifest.permission.FOREGROUND_SERVICE) == PackageManager.PERMISSION_GRANTED &&
(ContextCompat.checkSelfPermission(context,
Manifest.permission.FOREGROUND_SERVICE_LOCATION) == PackageManager.PERMISSION_GRANTED)))))) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent,
PendingIntent.FLAG_IMMUTABLE);
} else {
pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent,
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
}
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Location Service Running")
.setContentText(input)
.setSmallIcon(R.drawable.map_marker_down)
.setContentIntent(pendingIntent)
.build();
ServiceCompat.startForeground(this, 100, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
}
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
When the app runs the method startForeground() in SystemForegroundService.class, this code is passed the parameters (1,0,Notification). I have not been able to track it backwards to see where it is lost.
public void startForeground(
final int notificationId,
final int notificationType,
@NonNull final Notification notification) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Api29Impl.startForeground(SystemForegroundService.this, notificationId,
notification, notificationType);
} else {
startForeground(notificationId, notification);
}
}
Attached is my build.gradle in case it a version issue.
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 34
defaultConfig {
applicationId "com.grgmobilesolutions.peepsconnection"
minSdkVersion 34
targetSdkVersion 34
versionCode 2
versionName "Beta 2.0.1"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
customDebugType {
debuggable true
}
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
namespace 'com.grgmobilesolutions.peepsconnection'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
implementation 'androidx.core:core:1.12.0'
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
def work_version = "2.5.0"
// (Java only)
implementation "androidx.work:work-runtime:$work_version"
// optional - Test helpers
androidTestImplementation "androidx.work:work-testing:$work_version"
// optional - Multiprocess support
implementation 'com.bugfender.sdk:android:3.+'
implementation 'com.google.firebase:firebase-appcheck-debug:17.1.1'
implementation 'com.google.firebase:firebase-appcheck-playintegrity:17.1.1'
implementation 'com.android.billingclient:billing:6.1.0'
implementation "androidx.work:work-multiprocess:$work_version"
implementation group: 'org.locationtech.jts', name: 'jts-core', version: '1.15.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.navigation:navigation-fragment:2.4.2'
implementation 'androidx.navigation:navigation-ui:2.4.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.google.android.gms:play-services-ads:22.5.0'
implementation 'com.google.firebase:firebase-ads:22.5.0'
implementation 'androidx.work:work-runtime:2.8.0-alpha02'
implementation 'androidx.preference:preference:1.2.0'
implementation 'com.google.android.gms:play-services-maps:18.2.0'
implementation 'com.google.firebase:firebase-auth:22.3.0'
implementation 'androidx.annotation:annotation:1.3.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
implementation 'com.google.firebase:firebase-database:20.3.0'
implementation 'com.google.firebase:firebase-functions:20.4.0'
implementation 'androidx.wear:wear:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation "com.github.MikeOrtiz:TouchImageView:1.4.1" // last SupportLib version
implementation platform('com.google.firebase:firebase-bom:30.4.1')
implementation 'com.google.firebase:firebase-analytics:21.5.0'
implementation 'com.google.firebase:firebase-messaging:23.3.1'
implementation 'com.google.firebase:firebase-appcheck-playintegrity'
implementation 'com.firebaseui:firebase-ui-database:3.2.1'
implementation 'com.firebaseui:firebase-ui-auth:6.4.0'
implementation 'com.google.android.material:material:1.5.0'
implementation 'com.google.android.gms:play-services-gcm:17.0.0'
implementation 'com.android.volley:volley:1.2.1'
implementation 'com.google.android.gms:play-services-location:20.0.0'
implementation 'com.android.support:multidex:1.0.3'
implementation 'com.google.android.libraries.maps:maps:3.1.0-beta'
implementation 'androidx.biometric:biometric:1.2.0-alpha04'
implementation 'com.google.auto.value:auto-value-annotations:1.6.5'
implementation 'com.google.maps.android:android-maps-utils:2.4.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.androidmapsextensions:android-maps-extensions:2.4.0'
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
implementation('com.mikepenz:materialdrawer:5.9.5@aar') {
transitive = true
exclude group: 'com.android.support'
}
implementation files('libs/activation.jar')
implementation files('libs/additionnal.jar')
implementation files('libs/mail.jar')
// Room components
implementation "androidx.room:room-runtime:2.6.1"
annotationProcessor "androidx.room:room-compiler:2.6.1"
androidTestImplementation "androidx.room:room-testing:2.6.1"
implementation 'androidx.sqlite:sqlite:2.4.0'
//implementation "net.zetetic:android-database-sqlcipher:4.5.3"
implementation 'net.zetetic:sqlcipher-android:4.5.5@aar'
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.archLifecycleVersion"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$rootProject.archLifecycleVersion"
// UI
implementation "com.google.android.material:material:1.3.0"
// Testing
androidTestImplementation "androidx.arch.core:core-testing:$rootProject.coreTestingVersion"
compileOnly 'com.google.android.wearable:wearable:2.8.1'
}