I was linked to your library (once again, THANKS and excellent work).
I've been trying for the past two hours what the problem is but I've failed.
Here's the AlarmManager in my Login screen code:
Intent i = new Intent(con, LocationPoller.class);
i.putExtra(LocationPoller.EXTRA_INTENT, new Intent(con,
LocationReceiver.class));
i.putExtra(LocationPoller.EXTRA_PROVIDER,
LocationManager.NETWORK_PROVIDER);
gps = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcast(con, 0, i, PendingIntent.FLAG_NO_CREATE);
gps.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(),
10 * 1000, pi);
Log.d("Service: ",
"GPS Service started and scheduled with AlarmManager");
Here is the class I created myself (not the one from your demo, though similar):
public class LocationReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle b = intent.getExtras();
Location loc = (Location) b.get(LocationPoller.EXTRA_LOCATION);
String msg;
if (loc == null)
{
loc = (Location) b.get(LocationPoller.EXTRA_LASTKNOWN);
if (loc == null)
{
msg = intent.getStringExtra(LocationPoller.EXTRA_ERROR);
}
else
{
msg = "TIMEOUT, lastKnown=" + loc.toString();
}
}
else
{
msg = loc.toString();
}
if (msg == null)
{
msg = "Invalid broadcast received!";
}
Log.d("GPS Broadcast: ", "Location: " + msg);
}
}
Nothing's happening. I assume this because I'm not seeing any info in my logcat, at all. Plus the PollerThread (if that's the right term) keeps piling up when I look at the debug view, as if they're all waiting for something but not sending any broadcasts.
What am I doing wrong? Ascertaining location via Network shouldn't take much time should it? Even if that was the issue, I should have gotten SOME feedback..
Here are the entries in my manifest's application tag:
<receiver android:name="com.commonsware.cwac.locpoll.LocationPoller" />
<receiver android:name=".LocationReceiver" />
<service android:name="com.commonsware.cwac.locpoll.LocationPollerService" />
LocationPoller is designed for much longer polling periods: an hour, not 10 seconds. I have never tested LocationPoller with that frequent of a polling period, nor do I ever intend to support LocationPoller with a polling period shorter than the DEFAULT_TIMEOUT of two minutes.
Hence, the first thing you should do is figure out why you are bothering with LocationPoller in the first place. The point behind LocationPoller is to be able to occasionally figure out where the device is, without your code necessarily already running (e.g., you want to automatically check into Foursquare every hour). If you need to find out where the device is every 10 seconds, you need to use LocationManager yourself from a foreground activity.
Assuming you are convinced that LocationPoller is still the right solution, the next thing you should do is extend your polling period to something more reasonable, like 5 minutes, and see if that helps.
If that does not help, then try running the demo/ project without modification. If that does not work, then there's some bug in LocationPoller, or some incompatibility in your device that LocationPoller is tripping over, and I'd need to do some investigation.
If the demo/ project does work, make a copy, confirm the copy works, and then slowly modify the copy to look more like what your production code has, until it stops working -- at that point, your last set of changes represent what broke LocationPoller, and we can figure out if that represents a bug in LocationPoller or a bug in your use of it.
Related
I have an app that should show a notification every 2 hours and should stop if user has already acted upon the notif. Since background services are history now, I thought of using WorkManager ("android.arch.work:work-runtime:1.0.0-beta01") for the same.
My problem is that although the work manager is successfully showing the notifications when app is running, but it won't show notification consistently in the following cases(I reduced the time span from 2 hours to 2 minutes to check the consistency):
when app is killed from the background.
device is in screen off.
state device is in unplugged state(i.e not charging).
By consistency , i mean that the notifications show at least once in the given time span. for 2 minutes time span, the freq of notifications went from once every 4 minutes to completely not show any notification at all. for 2 hours timespan( the timespan that i actually want), its been 4 hours and i haven't got a single notification. Here is the Code i am using for calling WorkManger:
public class CurrentStreakActivity extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
setDailyNotifier();
...
}
private void setDailyNotifier() {
Constraints.Builder constraintsBuilder = new Constraints.Builder();
constraintsBuilder.setRequiresBatteryNotLow(false);
constraintsBuilder.setRequiredNetworkType(NetworkType.NOT_REQUIRED);
constraintsBuilder.setRequiresCharging(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
constraintsBuilder.setRequiresDeviceIdle(false);
}
Constraints constraints =constraintsBuilder.build();
PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest
.Builder(PeriodicNotifyWorker.class, 2, TimeUnit.HOURS);
builder.setConstraints(constraints);
WorkRequest request = builder.build();
WorkManager.getInstance().enqueue(request);
}
....
}
Here is the worker class(i can post showNotif(..) and setNotificationChannel(...) too if they might be erroronous):
public class PeriodicNotifyWorker extends Worker {
private static final String TAG = "PeriodicNotifyWorker";
public PeriodicNotifyWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
Log.e(TAG, "PeriodicNotifyWorker: constructor called" );
}
#NonNull
#Override
public Result doWork() {
// Log.e(TAG, "doWork: called" );
SharedPreferences sp =
getApplicationContext().getSharedPreferences(Statics.SP_FILENAME, Context.MODE_PRIVATE);
String lastcheckin = sp.getString(Statics.LAST_CHECKIN_DATE_str, Statics.getToday());
// Log.e(TAG, "doWork: checking shared preferences for last checkin:"+lastcheckin );
if (Statics.compareDateStrings(lastcheckin, Statics.getToday()) == -1) {
Log.e(TAG, "doWork: last checkin is smaller than today's date, so calling creating notification" );
return createNotificationWithButtons(sp);
}
else {
Log.e(TAG, "doWork: last checkin is bigger than today's date, so no need for notif" );
return Result.success();
}
}
private Result createNotificationWithButtons(SharedPreferences sp) {
NotificationManager manager =
(NotificationManager) getApplicationContext().getSystemService((NOTIFICATION_SERVICE));
String channel_ID = "100DaysOfCode_ID";
if (manager != null) {
setNotificationChannel(manager,channel_ID);
showNotif(manager, channel_ID, sp);
return Result.success();
}
else {
return Result.failure();
}
I am using a xiaomi miA2 androidOne device with Android Pie(SDK 28). There are a few other things that are troubling me:
What can i possibly do to know if my WorkManager is running? Other that just wait for 2 hours and hope for a notification. I actually tried something like that, keeping my phone connected to pc and checking android studio's logcat every now and then. It DOES run all the logs when the worker is actually called, but i don't think that's a correct way to test it, or is it?
In the above Code, the setDailyNotifier() is called from the onCreate() every time the app is opened. Isn't it Wrong? shouldn't there be some unique id for every WorkRequest and a check function like WorkManger.isRequestRunning(request.getID) which could let us check if a worker is already on the given task??If this was a case of AsyncTask, then boy we would have a mess.
I have also checked #commonsware's answer here about wakelock when screen is off, but i remember that work manager does use alarm manager in the inside when available. So what am I missing here?
Few comments:
WorkManager has a minimum periodic interval of 15minutes and does not guarantee to execute your task at a precise time. You can read more about this on this blog.
All the usual background limitation you've on newer Android releases are still relevant when you use WorkManager to schedule your tasks. WorkManager guarantees that the task are executed even if the app is killed or the device is restated, but it cannot guarantee the exact execution.
There's one note about the tasks being rescheduled when your app is killed. Some OEM have done modification to the OS and the Launcher app that prevents WorkManager to be able to accomplish these functionality.
Here's the issuetracker discussion:
Yes, it's true even when the phone is a Chinese phone.
The only issue that we have come across is the case where some Chinese OEMs treat swipe to dismiss from Recents as a force stop. When that happens, WorkManager will reschedule all pending jobs, next time the app starts up. Given that this is a CDD violation, there is not much more that WorkManager can do given its a client library.
To add to this, if a device manufacturer has decided to modify stock Android to force-stop the app, WorkManager will stop working (as will JobScheduler, alarms, broadcast receivers, etc.). There is no way to work around this. Some device manufacturers do this, unfortunately, so in those cases WorkManager will stop working until the next time the app is launched.
As of now , i have this app installed for last 8 days and i can confirm that the code is correct and app is working fine. as said by pfmaggi , the minimum time interval for work manager to schedule the work is 15 minutes, so there is a less chance that the WorkManager would have worked as expected in my testing conditions( of 2 minutes ) . Here are some of my other observations:
Like I said in the question that i was unable to recieve a notification for 4 hours even though i have passed the repeat interval as 2 hours. This was because of Flex Time. I passed in the flex time of 15 minutes and now it shows notifications between correct time interval. so i will be marking pfmaggi's answer as correct.
The problem of repeated work request can be solved by replacing WorkManager.getInstance().enqueue(request) with WorkManager.getInstance().enqueueUniqueWork(request,..)
I was still unable to find a way to test the work manager in the way i have described.
I am developing android native applications. My requirement is to get the current activity of the device like running,in_vehicle,still and so on. I used ActivityRecognitionAPI and set the pendingintent to receive the activity changes through IntentService. I gave 5 seconds interval for each updated. Its failed to provide the activity changes in certain period of time and again started providing activity. After that i preferred Awareness SnapshotAPI to get the activity state. Its also same result, failed to provide the activity regularly. Both APIs sometimes providing and many times not. I used GooglePlayServices 10.2.0 version for my developemnt. Anyone tell what is the reason for these things and solution to get regular activity updates..
Thanks in advance.
I am trying to show my app user's activity like he is walking, running and so on. This is my requirement.
Way 1:
//Google API client using ActivityRecognition.API
Intent intent = new Intent(mContext, RequestActivityService.class);
PendingIntent callbackIntent = PendingIntent.getService(mContext, 111,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(googleApiClient,5000, callbackIntent);
public class RequestActivityService extends IntentService {
public RequestActivityService() {
super("RequestActivityService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (ActivityRecognitionResult.hasResult(intent)) {
ActivityRecognitionResult result = ActivityRecognitionResult
.extractResult(intent);
DetectedActivity mostProbableActivity = result
.getMostProbableActivity();
int confidence = mostProbableActivity.getConfidence();
int activityType = mostProbableActivity.getType();
String activityName = getNameFromType(activityType);
}
}
** I tried this way to get activity updates. It started providing the activity info, but Intent service not called sometimes and again started firing the intent. So I am not able to show the correct activity information.
Way 2:
//Google API client using Awareness.API
Awareness.SnapshotApi.getDetectedActivity(googleApiClient).
setResultCallback(new ResultCallback<DetectedActivityResult>() {
#Override
public void onResult(#NonNull DetectedActivityResult detectedActivityResult) {
if (!detectedActivityResult.getStatus().isSuccess()) {
Log.i("Could not get the activity","");
return;
}
ActivityRecognitionResult ar = detectedActivityResult.getActivityRecognitionResult();
DetectedActivity probableActivity = ar.getMostProbableActivity();
String activityType = RequestActivityService.getNameFromType(probableActivity.getType());
int activityConfidence = probableActivity.getConfidence();
}
});
** I tried this another way, using this Api we can call this method recursively and get the activity information frequently. But Its also sometime providing and sometimes detectedActivityResult.getStatus() not success. If I am trying to get the status code and status message, status code returns 15 and status message will be null.
Both these ways are failed to give regular updates of activity and more over I used GooglePlayService 10.2.0 version. I have tested the GoogleSamples of ActivityRecognition from Github. That is also same result. I don't know what do to achieve my requirement. Hope now u can understand my requirement and things which I faced.
ActivityRecognitionAPI from Google doesn't give updates regularly. From what I have noticed, if there is a change in the confidence level of the activity or the activity changes altogether, then it'll send an update. Even then, it'll take time to ensure the data read isn't just noise of some kind.
I'm not sure why you need regular updates, but I would suggest changing the logic to accept the last given activity as the current activity, and only act upon the changes (i.e., STILL -> IN_VEHICLE).
Call this method again after getting response:
I would suggest to set detectionIntervalMillis to 0. That will lead to get data ASAP.( be aware of battery consumption )
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(googleApiClient,o, callbackIntent);
if there are no changes for long time, it will not send updates till change occur...
I read a lot of questions on here but couldn't figure out what the problem is.
I'm writing a field service application for Android. In one of the Activities (MyActivity.java) I have two buttons: Start and Stop.
When the field worker presses start I need to get his current location with GPS and send it to server in timely intervals (say it be 5 minutes default, here I set it to 20 secs. for testing). The customer wants this to see how long the workers spend time in traffic, the traffic in my city (Istanbul) is a mess.
I have an AlarmManager in my activity, when the start button is pressed the alarm is set by AlarmManager.setRepeating() to start the service (ServiceClass.java).
Intent intent = new Intent (MyActivity.this, ServiceClass.class);
mPendingIntent = PendingIntent.getService(MyActivity.this, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mAlarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 20*1000,
mPendingIntent);
I cancel the Alarm with the Stop button.
It works perfectly till here, the Service starts. Its onCreate(), onStart() and onDestroy() methods are executed. But I can't get the location. I'm not working on a real device so I'm using DDMS to send locations. But the application skips that step and prints Longitude and Latitude of my location as Lon:0 Lat:0.
Here's the code inside the service:
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.d("Testing", "Service got started, calling location updates:");
mLocationManager.requestSingleUpdate(mCriteria, mLocationListener,
getMainLooper());
Log.i("TESTING LOCATION UPDATE: LOCATION:", "\nLat:" + mLatitude +
" Lon:" + mLongitude);
stopSelf(startId);
Log.d("Testing", "Service Stopped!");
And finally, here's my LocationListener:
mLocationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
if(location != null){
mLatitude = location.getLatitude();
mLongitude = location.getLongitude();
Log.i("onLocationChanged(Location location)", "Lat:"+mLatitude + "
Lon:" + mLongitude);
}
Also something caught my eye, when I run the code:
mLocationProvider = mLocationManager.getBestProvider(mCriteria, true);
Log.i("BEST PROVIDER IS:", mLocationProvider);
It says BEST PROVIDER IS: gps. But this log inside onProviderEnabled() is never shown in logcat.
#Override
public void onProviderEnabled(String s) {
Log.v("onProviderEnabled", "ENABLED");
}
Two things to add, if I use:
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
mLocationListener);
it doesn't work either.
This however works and I can get the LastKnownLocation:
Location lastKnown = mLocationManager.getLastKnownLocation(
LocationManager.GPS_PROVIDER);
First of all, is this a good approach for doing this? If it is please check to see what I am missing. If it is not, can you please tell me how can I implement this any better?
Thank you. :)
First, you cannot register for location updates, then shut down the service. At best, you will leak threads. At worst, Android will terminate your process (thinking there is nothing running in it) and you will not get the update. Also, GPS takes a while to warm up, so you might not get a fix within 20 seconds, particularly in an urban setting. Also, you have to make sure the device stays awake while you are trying to collect a fix.
As a result, getting periodic location fixes in the background is a rather complicated problem.
I wrote a now-discontinued LocationPoller to try to address this, and another developer has forked and extended it. You could try the fork or simply use it as a source of ideas.
try this:
AlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,,,);
I am doing for get one's current location with GPS, but my project works every 10 seconds. I have no idea now. And my code :
AlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),6000000,pi);
I'm trying to put a device into sleep mode for a certain amount of time, say x, by calling..
powerManager.goToSleep(xNumberOfMilliseconds);
However, the api never seems to work consistently, and never for any amount of time greater than 1000 milliseconds. I'm stumped. I have the appropriate permissions, my application has its sharedUserId set to "android.uid.system" in the manifest, and the application is signed with the same key the firmware itself is signed with (platform key).
It is a pretty simple API call, so I don't really know what on earth is going wrong. I've been able to get this problem on both a device running android 2.3 and a device running android 3.2.
Any ideas?
I have done this but it works at random on several android 4.0.x plaforms.
powerManager.goToSleep(SystemClock.uptimeMillis() + timeMs)
Did anyone managed to use the method the way he has intended to?
Edit:
It seems the right answer was what figure in the code below:
public void sleepFor(long time, Context context) {
//Create a new PendingIntent, to wake-up at the specified time, and add it to the AlarmManager
Intent intent = new Intent(context, this.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent wakeupIntent = PendingIntent.getActivity(context, CODE_WAKE_UP_DEVICE, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// CODE_WAKE_UP_DEVICE is a dummy request code.
AlarmManager am = getAlarmManager();
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + time, wakeupIntent);
powerService.goToSleep(SystemClock.uptimeMillis() + 1);
}
ContentResolver cr= getContentResolver();
android.provider.Settings.System.putInt(cr,android.provider.Settings.System.SCREEN_OFF_TIMEOUT
,1000);
According to the documentation, current system time would be more appropriate parameter for goToSleep() than the desired sleep duration:
powerManager.goToSleep(SystemClock.uptimeMillis())
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Intent to launch the clock application on android
I have a widget that displays the time and if one taps on it, it launches the com.android.alarmclock/.AlarmClock activity with an PendingIntent. This works great before-Froyo, but with Froyo, I have to launch the com.android.deskclock/.AlarmClock. So I want to put in code that checks for the class existence and launch the appropriate activity/intent. Here is what I tried, but it does not work.
Intent alarmIntent = new Intent();
try {
if (Class.forName("com.android.deskclock.AlarmClock") != null) {
Log.i(TAG, "setting deskclock alarm -- must be Froyo!");
alarmIntent.setClassName("com.android.deskclock",
"com.android.deskclock.AlarmClock");
}
} catch (ClassNotFoundException e) {
Log.i(TAG, "setting alarmclock alarm -- must be Eclair!");
alarmIntent.setClassName("com.android.alarmclock",
"com.android.alarmclock.AlarmClock");
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, REQUEST_UPDATE_TIME_NOW,
alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.text_timeofday, pendingIntent);
It always thinks it is "Eclair" and therefore fails on Froyo. Is this the best approach, or should I check the application-level? I prefer to work with the class existence.
if (Class.forName("com.android.deskclock.AlarmClock") != null)
That won't work, because that class is not in your project. At most, it might be in some other project on the device.
There is no documented supported Intent for launching an alarm clock in the Android SDK. Your approach of hard-wiring in package and class names is fragile, as you're discovering. It won't work on some devices, if they do not have that application (e.g., replaced by one from the device manufacturer). Plus, as you've seen, it may change in future versions of Android. I am having a rough enough time trying to convince device manufacturers not to break the SDK; having third-party developers do it weakens my case.
That being said, the general way to see if something will respond to an Intent is to use PackageManager (e.g., queryIntentActivities()).