I'm developing an application, which has only one Service running in the background. I want this Service to run only when the user uses his phone, ie when the phone is unlocked, the Service records the sensor data and when the screen is locked the Service stops, But the problem is that my Service continues to record data even when the screen is off.
I have the following code and I do not see where the problem is!
public class ScreenReceiver extends BroadcastReceiver {
private boolean wasScreenOn = true;
#Override
public void onReceive(Context context, Intent intent) {
System.out.println(intent.getAction());
if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)){
wasScreenOn = true;
}else{
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
wasScreenOn = true;
}else{
if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
System.out.println(intent.getAction());
wasScreenOn = false;
}
}
}
Intent intent1 = new Intent(context, MyService.class);
intent1.putExtra("statut", wasScreenOn);
context.startService(intent1);
}
}
Code in the manifest
<receiver android:name=".ScreenReceiver">
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT"/>
</intent-filter>
</receiver>
<service
android:name=".MyService"
android:enabled="true" />
And in my service I call the receiver
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
boolean screenOn = intent.getBooleanExtra("statut", true);
System.out.println("statut********************************************************"+screenOn);
if(!screenOn){
System.out.println("END********************************************************");
try {
unregisterReceiver(mReceiver);
}catch(IllegalArgumentException e){}
SM.unregisterListener(this, Accelerometre);
SM.unregisterListener(this, Gyroscope);
SM.unregisterListener(this, Gravity);
stopSelf();
}
return START_STICKY;
}
Thank you!
Firstly, declare a method in ScreenReceiver.javaļ¼
private static boolean isServiceWorking(Context context, String serviceClassName) {
ActivityManager myManager=(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ArrayList<ActivityManager.RunningServiceInfo> runningService =
(ArrayList<ActivityManager.RunningServiceInfo>) myManager.getRunningServices(30);
for(int i = 0 ; i<runningService.size();i++) {
if(runningService.get(i).service.getClassName().equals(serviceClassName)) {
return true;
}
}
return false;
}
It can judge a service alive or not.Then change the code:
Intent intent1 = new Intent(context, MyService.class);
intent1.putExtra("statut", wasScreenOn);
context.startService(intent1);
to:
Intent intent1 = new Intent(context, MyService.class);
intent1.putExtra("statut", wasScreenOn);
if (wasScreenOn) {// if screen on
if (!isServiceWorking(context, MyService.class.getName())) {// the service is not working
context.startService(intent1); // start the service
}
} else {// if screen off
if (isServiceWorking(context, MyService.class.getName())) {// the service is working
context.stopService(intent1); // stop the service
}
}
I hope it can help you.
Related
i want to start my service even if user force stop the app or some other app force stop my app.
Here is my code.
#Override
public void onDestroy() {
super.onDestroy();
stopLocationUpdates();
AlarmManager alarmMgr = (AlarmManager)this.getSystemService(this.ALARM_SERVICE);
Intent i = new Intent(this, LocationUpdateService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, i, 0);
alarmMgr.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10, pendingIntent);
}
I start service in onDestroy().This code will work for me if any one have more efficient way to do this please comment on it.
#Override
public void onDestroy() {
super.onDestroy();
startLocationUpdateService();
}
First of all, it is really very bad pattern to run service forcefully against
the user's willingness.
Anyways, you can restart it by using a BroadcastReceiver which handles the
broadcast sent from onDestroy() of your service.
StickyService.java
public class StickyService extends Service
{
private static final String TAG = "StickyService";
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
sendBroadcast(new Intent("YouWillNeverKillMe"));
}
}
RestartServiceReceiver.java
public class RestartServiceReceiver extends BroadcastReceiver
{
private static final String TAG = "RestartServiceReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "onReceive");
context.startService(new Intent(context.getApplicationContext(),
StickyService.class));
}
}
Declare the components in manifest file
<service android:name=".StickyService" >
</service>
<receiver android:name=".RestartServiceReceiver" >
<intent-filter>
<action android:name="YouWillNeverKillMe" >
</action>
</intent-filter>
</receiver>
Start the StickyService in a Component (i.e. Application, Activity, Fragment):
startService(new Intent(this, StickyService.class));
I'm building an enterprise application that needs to get some information about the employees' rooted phones to do corporate management.
This thread needs to run each five minutes.
I'm using an Activity that is started by a broadcast(BOOT_COMPLETED) when the android boots up, and it starts an infinite thread to send this information to server.
My current problem is my application is being killed by android after the user opens a lot of others apps.
What would be the better way to keep a thread running in background to send this information to server?
Main Application Class
public static void startService(Context mContext){
try{
//Schedule Service.
scheduleService(mContext);
//Call onUpdate.
onUpdate();
}catch (Exception o){
Utilities.log(o.toString());
}
}
public static void scheduleService(Context mContext){
try{
final int NOTIFICATION_INTERVAL = 5 * 60 * 1000;
Intent mIntent = new Intent(mContext, ServiceReceiver.class);
AlarmManager mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
PendingIntent mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 0);
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), NOTIFICATION_INTERVAL, mPendingIntent);
}catch (Exception o){
Utilities.log(o.toString());
}
}
ServiceReceiver
public class ServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context mContext, Intent intent) {
Utilities.log("Service Received");
//Start Service.
MyApplication.startService(mContext);
}
}
AndroidManifest
<receiver
android:name=".BootUpReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.intent.action.REBOOT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<receiver android:name=".ServiceReceiver"/>
BootUpReceiver
public class BootUpReceiver extends BroadcastReceiver
{
public void onReceive(Context mContext, Intent mIntent){
Utilities.log("BootUp Received.");
//Start Service.
MyApplication.startService(mContext);
}
}
create a static broadcast receiver for Repeating Alarms and start Intent Service from broadcast don't use infinite Thread
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationStatus.setupNotification(context); // if you restart your phone
}
}
class NotificationStatus{
//Call only one time from app from any activity
public static void setupNotification(Context context) {
final int NOTIFICATION_INTERVAL = 5 * 60 * 1000;
Intent myIntent1 = new Intent(context, NotificationReceiver.class);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 1, myIntent1, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), NOTIFICATION_INTERVAL, pendingIntent1);
}
}
public class NotificationReceiver extends BroadcastReceiver {
private static final int mNotificationId = 0;
#Override
public void onReceive(Context context, Intent intent) {
//start your services here for sending data
Intent intent1 = new Intent(context, SyncService.class);
context.startService(intent1);
}
}
public class SyncService extends IntentService {
public SyncService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
//Write code here for sending data to server
}
}
AndroidManifest
<receiver android:name="NotificationReceiver" />
<receiver android:name="BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
Define Service in Manifest
<service android:name=".SyncService"/>
You need to make your application an Android service.
Please see edits before answering!
I have an app which contains a BackgroundService class:
public class BackgroundService extends Service {
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction("com.spotify.music.playbackstatechanged");
filter.addAction("com.spotify.music.metadatachanged");
filter.addAction("com.spotify.music.queuechanged");
registerReceiver(receiver, filter);
Log.e("Playing:", "APP IS PLAYING");
Notification notification = new Notification();
startForeground(1, notification);
}
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
long timeSentInMs = intent.getLongExtra("timeSent", 0L);
String action = intent.getAction();
if (action.equals(BroadcastTypes.METADATA_CHANGED)) {
String trackId = intent.getStringExtra("id");
String artistName = intent.getStringExtra("artist");
String albumName = intent.getStringExtra("album");
String trackName = intent.getStringExtra("track");
int trackLengthInSec = intent.getIntExtra("length", 0);
// Do something with extracted information...
} else if (action.equals(BroadcastTypes.PLAYBACK_STATE_CHANGED)) {
boolean playing = intent.getBooleanExtra("playing", false);
Log.e("Playing:","TRUE");
}
}
};
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
static final class BroadcastTypes {
static final String SPOTIFY_PACKAGE = "com.spotify.music";
static final String PLAYBACK_STATE_CHANGED = SPOTIFY_PACKAGE + ".playbackstatechanged";
static final String METADATA_CHANGED = SPOTIFY_PACKAGE + ".metadatachanged";
}
}
and this is declared in my manifest:
<service
android:name=".BackgroundService"
android:enabled="true" >
<intent-filter>
<action android:name="com.spotify.music.playbackstatechanged" />
<action android:name="com.spotify.music.metadatachanged" />
<action android:name="com.spotify.music.queuechanged" />
</intent-filter>
</service>
So essentially my objective is to have my BackgroundService initialized when my app is opened, and to have it continue to run in the Background doing whatever I need it to do. As of now, I am using logs to determine whether my "setup" is working, but when I run my app, I am unable to see an logs even after I tested all actions that should have triggered my BroadCastReceiver. Furthermore, my persistent notification should have changed had my service been running, but it does not...
Edit::
So, I added logs to my BackgroundService's onCreate() and onReceive() methods, however, neither seem to be appearing. Im wondering, do I need to do something in my launcher activity to initialize the service? Furthermore, no notification is shown so I assume the Service is not being started for some reason...
Latest Edit:
So I added the following code to my Main activity to see if it would make a difference:
startService(new Intent(this,BackgroundService.class));
And after debugging my app, I began to see the following error:
java.lang.RuntimeException: Unable to create service com.aurum.mutify.BackgroundService: java.lang.SecurityException: Isolated process not allowed to call registerReceiver
pointing to my BroadCast Receiver class.
Intent services are designed for short tasks. And your intent handling method is empty.
If you need long running task in the background use standard service and call start foreground. This will minimize chance of system destroying your service.
To learn more go here
EDIT
Try overriding onStartCommand method. this method is called when service is started and usually you do all stuff here. Remember that there are 3 options to return.
Edit 2:
try something like this
in on create
PendingIntent pi;
BroadcastReceiver br;
Intent myIntent;
#Override
public void onCreate()
{
super.onCreate();
myIntent = new Intent("something")
if(Build.Version.SDK_INT >= 16) //The flag we used here was only added at API 16
myIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
//use myIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); if you want to add more than one flag to this intent;
pi = PendingIntent.getBroadcast(context, 1, myIntent, 0);
br = new BroadcastReceiver ()
{
public void onReceive (Context context, Intent i) {
new thread(new Runnable()
{
public void run()
{
//do something
}
}).start();
}
};
And then in on start command
this.registerReceiver(br, new IntentFilter("something"));
I read several threads about repeat asynchronous tasks in background, I first used this way: https://stackoverflow.com/a/6532298 but for some reasons, it seems that after sometime (several hours), it stopped.
So, now I am using this way, but I don't know if this is a good way to proceed:
BroadcastReceiver
public class RetrieveDataTaskBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences mSharedPreferences = context.getSharedPreferences(MY_PREF, 0);
int delayInMs = mSharedPreferences.getInt("set_delay_refresh", 20)*60*1000;
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, RetrieveDataService.class);
PendingIntent pi = PendingIntent.getService(context, 0, i, 0);
am.cancel(pi);
if (delayInMs > 0) {
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + delayInMs,
delayInMs, pi);
}
}
}
My service class:
public class RetrieveDataService extends Service implements OnRefreshInterface {
private Context context;
private PowerManager.WakeLock mWakeLock;
private static final String TAG = "REFRESH_SERVICE";
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void handleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.acquire();
//do the work
callAsynchronousTask();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleIntent(intent);
return START_NOT_STICKY;
}
public void onDestroy() {
super.onDestroy();
mWakeLock.release();
}
#Override
public void onCreate() {
super.onCreate();
context = this;
callAsynchronousTask();
}
public void callAsynchronousTask() {
//My asynchronous task => execute a class that extends AsyncTask
[...]
}
#Override
public void onRefreshInterface(int cb_val1, int cb_val2) {
//Callback when refresh is done
[...]
}
}
androidmanifest.xml:
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<service
android:name="com.example.package.RetrieveDataService"
android:enabled="true"
android:label="Refresh Data">
</service>
<receiver
android:name="com.example.package.RetrieveDataTaskBroadcast"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
I also added a way to launch the service when the app starts:
MainActivity:
#Override
protected void onResume() {
super.onResume();
Thread t = new Thread(){
public void run(){
SharedPreferences mSharedPreferences = getSharedPreferences(PREF, 0);
int delayInMs = mSharedPreferences.getInt("set_delay_refresh", 20)*60*1000;
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(MainBaseActivity.this, RetrieveDataService.class);
PendingIntent pi = PendingIntent.getService(MainBaseActivity.this, 0, i, 0);
am.cancel(pi);
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + delayInMs,
delayInMs, pi);
}
};
t.start();
}
Thank you for your help and advice.
You dont need a service to launch the repeated task when the device starts. Your task will never run when the device is off.
You can set a repeating alarm using Alarm Manager.
If the trigger time you specify is in the past when the device was off, the alarm triggers immediately when the device turns on.
Check this - https://developer.android.com/training/scheduling/alarms.html
I made an app as a service which runs in background. This app is basically a battery alarm. It works fine but the only problem is that when this service is running it also displays this app in the active application task manager. So when I exit this app it stops that service as well. So what I want is to only stop this service when the user unchecks the box in the app settings. If it is checked then it should not be stopped even if it is closed in active application task manager.
How can I stop showing my app in task manager?
I think I should provide code over here This is my service class
public class BatteryService extends Service {
Notify notification = new Notify();
BatteryAlarm alarm = new BatteryAlarm();
private MediaPlayer mMediaPlayer;
boolean flag = false;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
//method to start service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
notification.initNotification(this, false);
this.registerReceiver(this.mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
return START_STICKY;
}
//Broadcast receiver to get battery info
private BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context c, Intent i) {
//notification.initNotification(c);
int level = i.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
int plugged = i.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
SharedPreferences getAlarm = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String alarms = getAlarm.getString("ringtones", "content://media/internal/audio/media/45"); // /system/media/audio/ringtones/ANDROMEDA.ogg , content://media/internal/audio/media/45
Uri uri = Uri.parse(alarms);
if(plugged == 2) {
if(level == 100) {
if(uri != null) {
if(flag == false) {
playAlarm(c, uri);
notification.initNotification(c, true);
Toast.makeText(c, "Battery charge is completed. Unplug your mobile phone!", Toast.LENGTH_LONG).show();
flag = true;
}
}
}
} else if (plugged == 0) {
if(uri != null) {
stopAlarm();
}
notification.cancelNotification(c);
//Toast.makeText(c, "Mobile is unplugged", Toast.LENGTH_LONG).show();
}
}
};
//play alarm method
private void playAlarm(Context c, Uri uri) {
mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.reset();
mMediaPlayer.setDataSource(getBaseContext(), uri);
final AudioManager audioManager = (AudioManager) c.getSystemService(Context.AUDIO_SERVICE);
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
} catch (Exception ex) {
ex.printStackTrace();
onDestroy();
}
}
//method to stop playing alarm
private void stopAlarm() {
mMediaPlayer.stop();
flag = false;
}
//method to stop service
public void onDestroy() {
super.onDestroy();
notification.cancelNotification(this);
unregisterReceiver(this.mBatInfoReceiver);
stopAlarm();
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
}
This is my main activity
public class BatteryNotify extends PreferenceActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.xml.prefs);
addPreferencesFromResource(R.xml.prefs);
SharedPreferences getCB = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
boolean cb = getCB.getBoolean("checkbox", true);
final CheckBoxPreference checkboxPref = (CheckBoxPreference) getPreferenceManager().findPreference("checkbox");
if(cb == true) {
startService(new Intent(getBaseContext(), BatteryService.class));
} else if(cb == false) {
stopService(new Intent(getBaseContext(), BatteryService.class));
}
checkboxPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
if(newValue.toString().equals("true")) {
startService(new Intent(getBaseContext(), BatteryService.class));
} else {
stopService(new Intent(getBaseContext(), BatteryService.class));
}
return true;
}
});
}
}
and here is my menifest file
<uses-sdk android:minSdkVersion="10" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".BatteryNotify"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".BatteryService"></service>
</application>
The best way to do this would be to create a BroadcastReceiver, register it in the manifest with the appropriate intent-filters and when it receives one it starts the Service or Activity to perform whatever task you need.
EDIT:
Create your BroadcastReceiver as a separate class and register it in the manifest. When it receives a battery event, create a PendingIntent to start the Service. That way it doesn't matter if your app isn't running. It will be started for you.
How can I stop showing my app in task manager?
You can't, for obvious security reasons.