Android - read all sensors every X minutes - java

I need to read all the device sensors in my app.
I've made an Android Service that implements the SensorEventListener interface.
Here is the code:
public class SensorService extends Service implements SensorEventListener {
private static final String DEBUG_TAG = "SensorService";
private SensorManager sensorManager = null;
private Sensor sensor = null;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
for (Sensor sensor : sensors)
{
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// nothing
}
#Override
public void onSensorChanged(SensorEvent event) {
//do something with values
...
// unregisterthe sensor
sensorManager.unregisterListener(this,event.sensor);
// stop the service
stopSelf();
}
}
}
But the problem is that I only want to read the values every minute, beacuse of the drain of battery. So, I decided to call the
service using the AlarmManager from the activity, every minute:
(My Activity)
...
public void startService(View view) {
//Starts the service every minute
AlarmManager scheduler = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getApplicationContext(), SensorService.class );
PendingIntent scheduledIntent = PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
scheduler.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60000, scheduledIntent);
}
public void stopService(View view) {
//Stops the servicee
AlarmManager scheduler = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this,SensorService.class );
PendingIntent scheduledIntent = PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
scheduler.cancel(scheduledIntent);
}
...
I start the service with the AlarmManager, then I read the values and I call the stopSelf method ir order to stop the service.
The problem is the values read are old because the sensor doesn't changed because the service is stopped (I think so).
The other problem is the stopSelf method is called every time a sensor is read, instead of being called once.
I don't know if there is a better way for doing this. I'd really appreciate your help.
Thank you.

Related

Change Variable in BroadcastReceiver

I want to change a variable of a BroadcastReceiver. Unfortunately the App crashed everytime I try to access it.
Here is an example:
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.buttonAlarm).setOnClickListener(new View.OnClickListener() {
setAlarm();
});
}
public void setAlarm(){
Calendar calendar = Calendar.getInstance();
calendar.set(datePicker.getYear(),datePicker.getMonth(),datePicker.getDayOfMonth(),timePicker.getCurrentHour(),timePicker.getCurrentMinute(), 0);
am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this, MyAlarm.class);
pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), Interval*60000, pi);
}
}
This is the MyAlarm.java Class that extends the BroadcastReceiver:
public class MyAlarm extends BroadcastReceiver {
int RecordTimeMinutes;
public void onReceive(final Context context, Intent intent) {
new Handler().postDelayed(new Runnable() {
#Override
public void run(){
//do some stuff
}
}, RecordTimeMinutes * 60000);
}
}
So basically I want to acces the Variable RecordTimeMinutes of the MyAlarm class within the MainActivity class. Is that possible?
For your use-case, why don't you save the value of RecordTimeMinutes into a sharedpreference key?
That way you will be able to access it from both the Activity and the Receiver without any issues.
Directly accessing the variable in the activity might not be possible unless you make it static, which is something you should not do!
Pass the variable from the Activity via the Intent extras:
public void setAlarm(){
Calendar calendar = Calendar.getInstance();
calendar.set(datePicker.getYear(),datePicker.getMonth(),datePicker.getDayOfMonth(),timePicker.getCurrentHour(),timePicker.getCurrentMinute(), 0);
am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this, MyAlarm.class);
i.putInt("Interval", 42); // Pass "interval" value here
pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), Interval*60000, pi);
}
And then in the receiver:
public class MyAlarm extends BroadcastReceiver {
public void onReceive(final Context context, Intent intent) {
int interval = intent.getIntExtra("Interval", 0) // Get "interval" value here
new Handler().postDelayed(new Runnable() {
#Override
public void run(){
//do some stuff
}
}, interval * 60000); // Use "interval" here
}
}
That said - you should not be posting a handler to fire in the future inside a BroadcastReceiver. There is no guarantee that your process will still be alive 1 minute from now to execute your code. Instead you could schedule another alarm or use WorkManager to schedule a job to run later.
Hope that helps!

How to keep alive a service, after starting, until the application be closed or killed in Android?

I am developing android application, so I am starting a service with alarm:
public void scheduleLocationCheckerAlarm() {
Intent intent = new Intent(getApplicationContext(), LocationCheckerReceiver.class);
final PendingIntent pIntent = PendingIntent.getBroadcast(this, LocationCheckerReceiver.REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long firstMillis = System.currentTimeMillis();
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis, 600000, pIntent);
}
LocationCheckerReceiver:
public class LocationCheckerReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, LocationNotificator.class);
context.startService(i);
}
Service:
public class LocationNotificator extends Service {
public LocationNotificator() {
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Location checker", "Service running");
//My code is here
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("Location checker", "Service destroyed");
}
So I want this service to be checking for something every 1 minute and to be running all the time, even when the application is closed by the user.
You must call startForeground(FOREGROUND_ID, buildForegroundNotification(filename)); in order to ensure that your service running continuously. Also, this will post a notification from your app to show the user about the service state. Please follow the reference.
Here is the code :
public class LocationNotificator extends Service {
private static int FOREGROUND_ID=1338;
public LocationNotificator() {
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Location checker", "Service running");
//My code is here
startForeground(FOREGROUND_ID,
buildForegroundNotification(filename));
stopForeground(true);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("Location checker", "Service destroyed");
}
private Notification buildForegroundNotification(String filename) {
NotificationCompat.Builder b=new NotificationCompat.Builder(this);
b.setOngoing(true);
b.setContentTitle("Some Title")
.setContentText("some File name")
.setSmallIcon(android.R.drawable.stat_sys_download)
.setTicker("downloading");
return(b.build());
}
You need to read this first. https://developer.android.com/guide/components/services.html
In a nutshell, start your service as a foreground service so there's lesser chance of Android killing your service. As a foreground service, you need to display an on-going notification in the status bar.
There's no direct way of making sure your service is never killed by the Android system. A workaround is to send a broadcast in onDestroy() of your service, and have a Receiver in your Android application start the service upon receiving the broadcast.
By the way, it seems that your service is sending location updates periodically to your backend server. This might be better implemented using Firebase Job Dispatcher library or Evernote's Android-Job library.

Android service running but overlay activity flicks and disappears

Background info: I'm trying to create a service. I create it in my main activity. I know the service is running because the notification is showing. So the service doesn't stop at any point.
What i want to happen: when the screen is locked/turned off i want a certain activity to be displayed for when the screen is turned back on.
What is happening: first, When the screen is turned back on the main activity shows and then the activity i want shows over that. I dont want the main activity to show at all when the screen is turned on .
Then i changed a few things: and now the desired activity flickers on the main screen and then vanishes. It seems very unreliable and only comes a few times.
That should be enough info, here is the code so far (specifically onReceive())
public class OverlayService extends Service{
//IN THIS CLASS CHECK WHETHER LOCK BUTTON WAS PRESSED OR IF PHONE WHEN TO SLEEP.. UPON AWAKENING START THE OVERLAY ACTIVITY...
private BroadcastReceiver mReceiver;
private boolean isShowing = false;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
private WindowManager windowManager;
WindowManager.LayoutParams params;
#Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
//Register receiver for determining screen off and if user is present
mReceiver = new OverlayStateReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mReceiver, filter);
makeNotification();
}
void makeNotification() {
Notification notification = new NotificationCompat.Builder(this)
//TODO change icon
.setSmallIcon(R.drawable.test)
.setContentTitle("App")
.setContentText("service is running...")
.setPriority(Notification.PRIORITY_LOW)
.build();
startForeground(1, notification);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public class OverlayStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.i("app", "load view");
showOverlayActivity(context);
}
}
}
private void showOverlayActivity(Context context) {
Intent intent = new Intent(context, OverlayActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
#Override
public void onDestroy() {
//unregister receiver when the service is destroy
if (mReceiver != null) {
unregisterReceiver(mReceiver);
}
//TODO remove view if it is showing and the service is destroy
super.onDestroy();
}
}

Service not run on app closed

The service works normally when is started from the MainActivity however when the application is removed from the recent apps or when activity is closed, the service is restarted instead of continuing from where it left off.
public class ServiceExample extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO: Implement this method
return null;
}
#Override
public void onCreate() {
// TODO: Implement this method
super.onCreate();
//Do Something
}
I need to perform an action in the background but it can not be stopped or restarted when the activity ends. The Service Statement is the best to Use?
Try putting this inside your service class.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
Add below code to service and override onStartCommand and return START_STICKY
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceTask = new Intent(getApplicationContext(),this.getClass());
restartServiceTask.setPackage(getPackageName());
PendingIntent restartPendingIntent = PendingIntent.getService(getApplicationContext(), 1,restartServiceTask, PendingIntent.FLAG_ONE_SHOT);
AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
myAlarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartPendingIntent
);
super.onTaskRemoved(rootIntent);
}

IntentService not working

I am building an application whereby the notification will ring at a specific time and after which disappear if it is left unattended for 15 minutes. It works when i plug in my device and runs the code. However, once i unplug my device and runs the app, the notification works but it does not disappear after 15 minutes if it is left unattended. Please advice me how should i run the app like how it does when the device is plug into the computer. Also, it should work when the app is killed.
FYI, i'm using notification, alarmmanager, broadcast receiver and intentservice. Below is the snippet of my codes.
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Notification(context, "Wifi Connection On");
Intent background = new Intent(context, BackgroundService.class);
context.startService(background);
}
public void Notification(final Context context, String message) {
// notification codes
}
}
BackgroundService.java
public class BackgroundService extends IntentService {
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
//countdown 15 minutes and cancel notification automatically
Timer timer=new Timer();
TimerTask task=new TimerTask() {
#Override
public void run() {
// Create Notification Manager
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Dismiss Notification
notificationmanager.cancelAll();
}
};
timer.schedule(task, 900000);
}
}
Manifest.xml
<receiver android:name=".AlarmReceiver" android:process=":remote" />
<service android:name=".BackgroundService" />
Please provide me some suggestions. Thank you.
This service will run twice: first time it does nothing except rescheduling, second time it cancels notifications.
public class BackgroundService extends IntentService {
private static final int REQUEST_CODE = 42;
private static final String ACTION_CANCEL_NOTIFS = "CancelNotifications";
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null && ACTION_CANCEL_NOTIFS.equals(intent.getAction())) {
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationmanager.cancelAll();
}
else {
reschedule();
}
}
private void reschedule() {
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MINUTE, 15);
final Intent serviceIntent = new Intent(this, getClass());
serviceIntent.setAction(ACTION_CANCEL_NOTIFS);
PendingIntent pendingIntent = PendingIntent.getService(this, REQUEST_CODE, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
Explanation:
In your code, I assume, you start your service with startService(new Intent(this, BackgroundService.class)). This intent is passed as a parameter in onHandleIntent(Intent), which means you can access it from inside your service.
Intent allows you to pass additional data, such as action (useful for IntentFilters) or extras. Because you haven't set any, the first time around the execution goes to the else branch of onHandleIntent() method. AlarmManager is then scheduled to run your service in 15 minutes with serviceIntent. Note serviceIntent.setAction(ACTION_CANCEL_NOTIFS). So the second time around the execution goes to the if branch and cancels notifications.
A better approach would be creating a pending intent right from inside your activity instead of starting a service with startService. That would make your service simpler and more cohesive.
Service only runs when CPU is awake. If CPU gets off, service will not run.
SO to make your service to be run if phone goes to sleep, you need to aquire wake lock.
BackgroundService class
public class BackgroundService extends IntentService {
private PowerManager.WakeLock wl;
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Partial lock permission");
wl.acquire();
//countdown 15 minutes and cancel notification automatically
Timer timer=new Timer();
TimerTask task=new TimerTask() {
#Override
public void run() {
// Create Notification Manager
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Dismiss Notification
notificationmanager.cancelAll();
wl.release();
}
};
timer.schedule(task, 900000);
}
}
If this does work out, try to give below permission in Android Manifest file
<uses-permission android:name="android.permission.WAKE_LOCK" />

Categories

Resources