Android: cannot bind to already running service, onServiceConnected not called - java

I have running service (previously successfuly binded, started and unbinded with main activity):
Intent startingIntent = new Intent(this, SturkoPlayerService.class);
startingIntent.setAction(SturkoPlayerService.PLAYER_START);
bindService(startingIntent, connection, Context.BIND_AUTO_CREATE);
When I successfuly close mainactivity (service is unbinded and keeps running) and want to reopen mainactivity with notification intent:
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.putExtra("Service", 1);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); //tried also another flags
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
and then try to bind my running service
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
if (getIntent() != null && getIntent().hasExtra("Service")) {
if (!bound) {
bindService(new Intent(this, SturkoPlayerService.class), connection, 0);
}
}
}
the onServiceConnected function of my Connection variable is not called
private ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
SturkoPlayerService.LocalBinder mBinder = (SturkoPlayerService.LocalBinder) service;
sturkoService = mBinder.getService();
bound = true;
sturkoService.registerClient(MainActivity.this);
}
#Override
public void onServiceDisconnected(ComponentName name) {
bound = false;
}
};
Manifest:
...
<activity android:name=".MainActivity"
android:screenOrientation="portrait"
android:launchMode="singleTask"> //tried other modes too
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".Service.SturkoPlayerService"
android:enabled="true"
android:exported="true"
android:singleUser="true">
</service>
...
P.S.: Catlog did not show somthing

A service will only be running if:
There are 1+ clients bound to it, or
You called startService() on it and nothing has stopped it (e.g., stopSelf(), stopService())
Otherwise, once the last bound connection is unbound, the service stops.

Related

boot_completed not working on Android 10 Q API level 29

I have an application that starts an Intent after the boot that works from Android 6 to Android 9 API level 28.
But this code does not work on Android 10 API level 29, Broadcast simply does not receive any events and does not run onReceive on MyClassBroadcastReceiver after the boot. Is there any extra permission on Android 10 or configuration that needs to be done?
Dry part of the example: Manifest:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.softniels.autostartonboot">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.softniels.autostartonboot.ForegroundService"
android:label="My Service">
<intent-filter>
<action android:name="com.softniels.autostartonboot.ForegroundService" />
</intent-filter>
</service>
<receiver
android:name=".StartMyServiceAtBootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
</application>
Here the part that doesn't run on Android 10.
public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.i("onReceive", "call onReceive ACTION_BOOT_COMPLETED");
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}
I know that this may be old but I have faced the same problem and according to this:
https://developer.android.com/guide/components/activities/background-starts
The easiest solution I came up with was simply adding
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
And setting up the receiver:
<receiver
android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
To the manifest.
Receiver code:
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
// Intent n = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
// n.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
// Intent.FLAG_ACTIVITY_CLEAR_TASK);
// context.startActivity(n);
Intent myIntent = new Intent(context, MainActivity.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(myIntent);
}
}
Both options work. The only downside I see is that it takes rather a while for app to load (can be up to 10 seconds from my testings)
Leaving this here for other people if they encounter this as well.
This only applies to android 10 and up. There is a need to request "Display over other apps" permission
This requires drawing overlay, which can be done with:
if (!Settings.canDrawOverlays(getApplicationContext())) {
Intent myIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
Uri uri = Uri.fromParts("package", getPackageName(), null);
myIntent.setData(uri);
startActivityForResult(myIntent, REQUEST_OVERLAY_PERMISSIONS);
return;
}
Guess I found a 'solution' for me.
public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
Log.e(TAG, "launching from special > API 28 (" + Build.VERSION.SDK_INT + ")"); // You have to schedule a Service
JobServiceScheduler jobServiceScheduler = new JobServiceScheduler(context);
boolean result = jobServiceScheduler.scheduleMainService(20L); // Time you will wait to launch
} else {
Log.e(TAG, "launching from normal < API 29"); // You can still launch an Activity
try {
Intent intentMain = new Intent(context, YourActivity.class);
intentMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT < 28) {
context.startService(intentMain);
} else {
context.startForegroundService(intentMain);
}
} catch (ActivityNotFoundException ex) {
Log.e(TAG, "ActivityNotFoundException" + ex.getLocalizedMessage());
}
}
}
boolean scheduleMainService(Long segundos) {
ComponentName serviceComponent = new ComponentName(context, YourService.class);
JobInfo.Builder builder = getCommonBuilder(serviceComponent, YOUR_SERVICE_JOB_ID);
builder.setMinimumLatency(TimeUnit.SECONDS.toMillis(segundos / 2)); // wait at least
builder.setOverrideDeadline(TimeUnit.SECONDS.toMillis(segundos)); // maximum delay
PersistableBundle extras = new PersistableBundle();
extras.putLong("time", segundos);
builder.setExtras(extras);
JobScheduler jobScheduler = getJobScheduler(context);
if (jobScheduler != null) {
jobScheduler.schedule(builder.build());
return true;
} else {
return false;
}
}
context.startActivity() is not launching, I solved it the following way:
private void restartApp( Context mContext) {
try {
long restartTime = 1000*5;
Intent intents = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
PendingIntent restartIntent = PendingIntent.getActivity(mContext, 0, intents, PendingIntent.FLAG_ONE_SHOT);
AlarmManager mgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mgr.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
I solved it with this permission in the manifest:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
And in the main activity :
if (!Settings.canDrawOverlays(getApplicationContext())) {
startActivity(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
}
The correct import for Settings is:android.provider
The first time the app boots the permission will be prompted for controlling which apps can draw on top of other apps, the next device will start the application will boot up using the typical broadcast receiver.
Here is the doc

ACTION_POWER_DISCONNECTED on Android Background Service

I'm trying to create a service which starts when I plug the battery charger and stop when unplug it. The problem is when I unplug the charger my service don't stop while when I plug it's all fine.
Here is my code:
public class PowerConnectionReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)){
Intent i = new Intent(context,MyService.class);
context.startService(i);
}
if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)){
Intent j = new Intent(context,MyService.class);
context.stopService(j);
}
}
}
Here is my Manifest:
<receiver android:name=".PowerConnectionReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
</intent-filter>
</receiver>

Event Listener in Android Service Seems to stop

I have a service that listens for an event posted by a Particle Photon (microcontroller) and then gives a notification to the user. The event listener is registered when the Service is started in the onStartCommand function in a separate thread (Because the action requires that it not be started in the main thread) Everything works fine even when the app isn't running but after about 5 minutes it just stops. The service from what I can tell is never destroyed (I have it display something if it gets destroyed and it never has) so my gut feeling is the event listener stops working. Any help would be appreciated! The code is below!
Note: Event listener does use an internet connection if that is of any consequence
Service Code below:
public class NotificationService extends Service implements ParticleEventHandler{
//private long weightChangeSubscriptionID;
private long lockedChangeSubscriptionID;
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
final String deviceID;
final SharedPreferences sharedPreferences = this.getSharedPreferences("justintime.com.productscale", Context.MODE_PRIVATE);
deviceID = sharedPreferences.getString("deviceID"," ");
ParticleCloudSDK.init(this);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
if(!deviceID.equals(" ")) {
//weightChangeSubscriptionID = ParticleCloudSDK.getCloud().subscribeToDeviceEvents("weightChange", deviceID, NotificationService.this);
lockedChangeSubscriptionID = -1;
lockedChangeSubscriptionID = ParticleCloudSDK.getCloud().subscribeToDeviceEvents("lockWtChange", deviceID, NotificationService.this);
if(lockedChangeSubscriptionID != -1){
sharedPreferences.edit().putBoolean("serviceRunning", true).apply();
}
}
else
Log.w("Error", "Not started! Possible no deviceID available");
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
return START_STICKY;
}
#Override
public void onDestroy() {
final SharedPreferences sharedPreferences = this.getSharedPreferences("justintime.com.productscale", Context.MODE_PRIVATE);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//try {
//ParticleCloudSDK.getCloud().unsubscribeFromEventWithID(weightChangeSubscriptionID);
//ParticleCloudSDK.getCloud().unsubscribeFromEventWithID(lockedChangeSubscriptionID);
sharedPreferences.edit().putBoolean("serviceRunning", false).apply();
Log.w("Subsction", "unsibscribed from lockedWeightchange");
//} catch (ParticleCloudException e) {
// e.printStackTrace();
//}
}
});
t.start();
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onEventError(Exception e) {
Log.wtf("error", "error on event");
}
#Override
public void onEvent(String eventName, ParticleEvent particleEvent) {
//if(eventName.equals("weightChange")) {
// DisplayActivity.updateScaleReading();
//}
if(eventName.equals("lockWtChange")) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.scale)
.setContentTitle("Scale change!")
.setContentText("Scales Value Has Changed While Locked!!")
.setPriority(Notification.PRIORITY_HIGH)
.setVibrate(new long[]{500, 1000, 500})
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setCategory(Notification.CATEGORY_EVENT)
.setAutoCancel(true)
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
.setColor(Color.GREEN);
Intent resultIntent = new Intent(this, MainScreen.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainScreen.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1234, mBuilder.build());
}
}
}
I am running the service from the main activity by checking if it is already running or not and then running it using the following code: (It is also run on boot using a boot reciever class)
#Override
protected void onResume() {
super.onResume();
updateScaleReading();
updateLockValue();
subscribeToEvents();
if (!isMyServiceRunning()){
Intent serviceIntent = new Intent(getApplicationContext(), justintime.com.productscale.NotificationService.class);
getApplicationContext().startService(serviceIntent);
}else{
Log.w("Service", "Service is already running!");
}
}
isMyServiceRunning() function:
private boolean isMyServiceRunning() {
SharedPreferences sharedPreferences = this.getSharedPreferences("justintime.com.productscale", Context.MODE_PRIVATE);
//return sharedPreferences.getBoolean("serviceRunning", false);
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (NotificationService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
Manifest File:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/scale_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/scale_launcher"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainScreen"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DisplayActivity"
android:screenOrientation="portrait" />
<activity android:name=".SelectionActivity"
android:screenOrientation="portrait"/>
<service android:enabled="true" android:exported="false" android:name=".NotificationService">
<intent-filter>
<action android:name="justintime.com.productscale.NotificationService" />
</intent-filter>
</service>
<receiver
android:name=".BootReceiver"
android:enabled="true"
android:exported="true"
android:label="BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>

StartService() doesn't active onStartCommand() function (Manifest is correct)

I'm trying to active my service with StartService(), and it should go next to the onStartCommand() function, but it doesn't.
I tried many ways to not use the onStartCommand() function, but I need the information from the Intent in my service.
Here is the code:
MainAcitivty - OnCreate:
dbHelper = new DBHelper(this);
listTasks = (ListView)findViewById(R.id.list_todo);
loadTaskList();
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show();
eventIntent = new Intent(view.getContext(), NewEventActivity.class);
startActivityForResult(eventIntent, ADD_EVENT_REQUEST);
}
});
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("dbHelper", (Parcelable)dbHelper);
if (!isMyServiceRunning(MyService.class))
{
startService(serviceIntent);
}
}
//gets any service class and check if its alive (running)
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
MyService:
DBHelper dbHelper;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
startServiceThread();
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bundle extras = intent.getExtras();
if (extras != null) {
dbHelper = (DBHelper)extras.get("dbHelper");
}
return super.onStartCommand(intent, flags, startId);
}
Manifest:
(Here i also tried to add the service just with name=".MyService", but it did not change anything)
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:name=".MyApplication">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
</activity>
<activity android:name=".NewEventActivity" />
<activity android:name=".LockApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.example.user.project.MyService" />
</application>
It is crash in startServiceThread() because it can't get the information from the intent
Then perhaps you should not be starting the thread until onStartCommand().
Anyway, the onStartCommand() does not calls after the startService()
That is because you are crashing on onCreate(). Stop crashing in onCreate(), and you should have better luck with onStartCommand().

Android - Unable to receive local broadcast in my activity from service

I have my main activity that start a service (Location service) and I want that service to broadcast the new location each time a new location is found.
Thanks to the log I know the service is working and I have new locations every seconds or so, but I never get the broadcast.
MainActivity.java
public class MainActivity extends Activity {
private static final String TAG = "mainActivity";
private CMBroadcastReceiver mMessageReceiver = new CMBroadcastReceiver();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
// Start Service
startService(new Intent(this, LocationService.class));
super.onCreate(savedInstanceState);
}
#Override
public void onResume()
{
LocalBroadcastManager.getInstance(this).registerReceiver(
mMessageReceiver, new IntentFilter(CMBroadcastReceiver.RECEIVE_LOCATION_UPDATE));
super.onResume();
}
#Override
public void onPause()
{
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
}
CMBroadcastReceiver.java
public class CMBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "CMBroadcastReceiver";
public static final String RECEIVE_LOCATION_UPDATE = "LOCATION_UPDATES";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Received broadcast");
String action = intent.getAction();
if (action.equals(RECEIVE_LOCATION_UPDATE))
{
Log.i(TAG, "Received location update from service!");
}
}
}
LocationService.java
/**
* Callback that fires when the location changes.
*/
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
Log.i(TAG, "onLocationChanged " + location);
Intent intent = new Intent(CMBroadcastReceiver.RECEIVE_LOCATION_UPDATE);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Log.i(TAG, "Broadcast sent");
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cyclemapapp.gpstracker">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main"
android:theme="#style/AppTheme.NoActionBar">
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".LocationService" android:process=":location_service" />
</application>
I the log I can see that "Broadcast Sent" But I never get the "Broadcast Received"
Any help will would be greatly appreciated.
EDIT:
Edited how the intent was created in the location service as Shaishav suggested.
Still doesn't work.
LocalBroadcastManager does not work across processes. Your Service is running in a separate process.
You can either run your Service in the same process as the Activity - by removing the process attribute from the <service> element - or use some sort of IPC instead - e.g., by sending and receiving the broadcasts on a Context instead of LocalBroadcastManager.
In your LocationService, send local broadcast using:
Intent intent = new Intent(CMBroadcastReceiver.RECEIVE_LOCATION_UPDATE);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
<service android:name=".LocationService" android:process=":location_service" />
Your service is in a separate process from the activity. LocalBroadcastManager is only for use in one process. Either remove android:process from the <service>, or use some IPC mechanism (e.g., system broadcasts, properly secured).

Categories