addProximityAlert and KEY_PROXIMITY_ENTERING - java

In the documentation, when discussing addProximityAlert , the description about Intent confuses me a bit. Specifically this part..
The fired Intent will have a boolean extra added with key
KEY_PROXIMITY_ENTERING. If the value is true, the device is entering
the proximity region; if false, it is exiting.
This may sound like a dumb question but.. how do I get true or false when I'm entering/ or in a certain radius of a location.
I'm not sure how this would work exactly.
Do I have to write my own code and check when I'm in the proximity of my location and then have it return true and false as I'm exiting?
I can't figure it out.

I believe this works in conjunction with a BroadcastReceiver. You might set the addProximityAlert() method to fire the onReceive() method on this receiver, which will provide you an Intent as a parameter and then get that extra Boolean called KEY_PROXIMITY_ENTERING. So, step by step:
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// You need to declare an Intent for your class and declare a PendingIntent on it,
// so it might be passed to the addProximityAlert method as the fifth parameter.
Intent intent = new Intent("com.yourdomain.yourproject.MyAlert");
PendingIntent proxIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
lm.addProximityAlert(your_latitude, your_longitude, RADIUS_IN_METERS, -1, proxIntent);
Explaination of the parameters set here:
your_longitude: The longitude you want to calculate the Radius on
your_latitude: The latitude you want to calculate the Radius on
RADIUS_IN_METERS: This is a constant defined by yourself where you specify the length of the radius you want to trace from the coordinate defined by the above parameters. If you set it to be, for example, 1000, you're saying that if someone gets closer than 1 km to your coordinate, the KEY_PROXIMITY_ENTERING will be true if the previous execution of onReceive() was more distant than 1 km, and analogously otherwise.
-1: This is the time in milliseconds after which the proximity alert will stop. If set to -1, it will never expire.
proxIntent: The proximity Intent that will fire your BroadcastReceiver.
Further, you'll also need this:
IntentFilter filter = new IntentFilter("com.yourdomain.yourproject.MyAlert");
registerReceiver(new AlertOnProximityReceiver(), filter);
This way you're activating the Receiver for the filter you just set. This will fire the onReceive() event on it. So now, there's just one thing left, declare the BroadcastReceiver.
public class AlertOnProximityReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Boolean getting_closer = intent.getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
if (getting_closer)
Log.d("Radius", "Hey, I just entered your radius!");
else
Log.d("Radius", "I just exited your radius!");
}
}
---- UPDATE ----
I'm now seeing this in the documentation:
Throws
SecurityException if ACCESS_FINE_LOCATION permission is not present
So make sure you include this permission in your AndroidManifest.xml file.

Using addProximityAlert you specify the "special area" which should fire the proximity alert using the arguments it have (bold)
Parameters
latitude the latitude of the central point of the alert
region
longitude the longitude of the central point of the alert
region
radius the radius of the central point of the alert region, in
meters expiration
time for this proximity alert, in milliseconds, or
-1 to indicate no expiration
intent a PendingIntent that will be used to generate an Intent to fire when entry to or exit from the alert
region is detected
When the user enters the area declared when you called the method the intent is called and inside this you found this extra KEY_PROXIMITY_ENTERING which alerts you if you enter or leave this area.
I don't know really how it works, but it could be something like:
To know it will check if he is in the radius latitude and longitudine, if yes send the intent when he leaves call the intent again passing "false".
The answer to your question is anyway you shouldn't care about this fact, it's done by the System and you don't need to do anything.
The only thing you need to do is to read this extra and use it if you need.
From documentation:
Due to the approximate nature of position estimation, if the device passes through the given area briefly, it is possible that no Intent will be fired. Similarly, an Intent could be fired if the device passes very close to the given area but does not actually enter it.

Use this Code it will help you a lot.
Intent intent = new Intent(PROX_ALERT_INTENT);
PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
locationManager.addProximityAlert(
lat, // the latitude of the central point of the alert region
lon, // the longitude of the central point of the alert region
POINT_RADIUS, // the radius of the central point of the alert region, in meters
PROX_ALERT_EXPIRATION, // time for this proximity alert, in milliseconds, or -1 to indicate no expiration
proximityIntent // will be used to generate an Intent to fire when entry to or exit from the alert region is detected
);
IntentFilter filter = new IntentFilter(PROX_ALERT_INTENT);
registerReceiver(new ProximityIntentReceiver(orderStatusObject.getBidId()), filter);
Class - for Approximate Alert broadcast
public class ProximityIntentReceiver extends BroadcastReceiver{
private static final int NOTIFICATION_ID = 1000;
public Context mcontext;//Context of calling BroadCast Receiver
private String bidId; //Hold the value of bid Id
public ProximityIntentReceiver() {
// TODO Auto-generated constructor stub
}
public ProximityIntentReceiver(String bidId) {
// TODO Auto-generated constructor stub
this.bidId = bidId;
}
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String key = LocationManager.KEY_PROXIMITY_ENTERING;
Boolean entering = intent.getBooleanExtra(key, false);
if (entering) {
Log.d(getClass().getSimpleName(), "entering");
}
else {
Log.d(getClass().getSimpleName(), "exiting");
}
sendNotification(context);
}
public void sendNotification(Context mcontext){
// String extra=arg1.getExtras().getString("alert").toString();
long when = System.currentTimeMillis();
String message = "You are near of driver pickup area.";
NotificationManager notificationManager = (NotificationManager) mcontext.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher,message, when);
String title = "Proximity Alert!";
Intent notificationIntent = new Intent();
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(mcontext, 0,notificationIntent, 0);
notification.setLatestEventInfo(mcontext, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults = Notification.DEFAULT_ALL;
notificationManager.notify(0, notification);
}

Related

Notification in Android Studio Not Coming on Time

I am currently developing an app on android studio using java where I want the user to be able to receive notifications from calendar events that they create. However, my notifications are not coming on time as they are either lagging or just not showing.
Here is my coding for the alarm receiver which sets up the notification:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String event = intent.getStringExtra("event");
String time = intent.getStringExtra("time");
int notId = intent.getIntExtra("id", 0);
Intent activityIntent = new Intent(context, CalendarActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, activityIntent, PendingIntent.FLAG_ONE_SHOT);
String channelId = "channel_id";
CharSequence name = "channel_name";
String description = "description";
NotificationChannel channel = new NotificationChannel(channelId, name, NotificationManager.IMPORTANCE_HIGH);
channel.setDescription(description);
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setContentTitle(event)
.setContentText(time)
.setDeleteIntent(pendingIntent)
.setGroup("Group_calendar_view")
.build();
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
notificationManagerCompat.notify(notId,notification);
}
}
Here is my CustomCalendarView Activity that sets up the alarm:
private void setAlarm(Calendar calendar, String event, String time, int RequestCode){
Intent intent = new Intent(context.getApplicationContext(), AlarmReceiver.class);
intent.putExtra("event",event);
intent.putExtra("time",time);
intent.putExtra("id",RequestCode);
#SuppressLint("UnspecifiedImmutableFlag") PendingIntent pendingIntent = PendingIntent.getBroadcast(context,RequestCode,intent,PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis() ,pendingIntent);
}
For example: When I set an alarm for 10:20 am, the notification either doesn't pop up or pops up really late like at 10:22 am. Please help! Let me know if I need to provide any more information.
You should use exact alarms for firing alarm on time,
use alarmManager.setExact() instead of alarmManager.set().
setExact() method is like set(), but does not permit the OS to adjust the delivery time. The alarm will be delivered as nearly as possible to the requested trigger time.
Put setExact() instead of set
alarmManager.setExact(...);
But with different devices and interface updates, the performance of the application work differed from one device to another, in this case you must put some settings in your application such as Disable Software Battery Optimizations, make the application run in the background even after closing, give Permissions Autostart, turn on all notifications and display them etc. Finally, call the functions in the onStop() event of the Activity.
Yes, correct. You should ask user to allow Battery Optimization and in Android 12 or higher you should ask user to enable Alarms & Reminders permission as well.
But, when your app wants to fire alarms exactly on time you have to use exact alarms.

Notification passes old Intent Extras when the Activity that read the extras values is on top

Notification is giving old values.
I read the stackoverflow link but still not working for me:
Notification passes old Intent Extras
I have a Activity A.
When I am on the activity B and touch the Notification, the Extra parameter is given correctly and shows the Activity A with the correctc values read with getExtras(..);
Then the Activity A is still on the top - showing on the screen:
I click on the second notification with new values of putExtras(newValue) to create a new activity A but with new values.
The problem:
The intent.getExtras()` is reading old values of the first notification clicked instead new values given by the second notification.
I made a lot of combinations of Flags of Pending Intent and the combinations of the link on top, but the aplication is still taking the old values(the values of the first touched notification) for the second Notification. I tried the flag: PendingIntent.FLAG_UPDATE_CURRENT to update the values instead create a new one Activity and some others Flags.
How can I make the second notification give the correct values for the activity A when the Activity A is still shown on the screen?
The snippet of the code creating the notification.
public void notificationCreateGu(String newMessageUserUidOfSender) {
Intent it = new Intent(this,ActivityA.class);
it.putExtra(USER_UID_READER,newMessageUserUidOfSender);
StoreValuesClass.count=StoreValuesClass.count+2;
PendingIntent pi = PendingIntent.getActivity(this, StoreValuesClass.count,it, 0);
Notification notification = new NotificationCompat.Builder(this)
.setTicker(newMessageUserUidOfSender )
.setSmallIcon(android.R.mipmap.sym_def_app_icon)
.setContentTitle("Title Message ")
.setContentText(String.valueOf(newMessageUserUidOfSender))
.setContentIntent(pi)
.setAutoCancel(true)
.build();
int m;
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
m= StoreValuesClass.count=StoreValuesClass.count+2;
notificationManager.notify((m), notification);
}
//StoreValueClass.count is a static values that can be read by the activity to give an unique id for the notification.
the snippet of code reading the values.
userUidReader = getIntent().getExtras().getString(USER_UID_READER)
I tried to reload the values into onResume() but into onResume() the still taking the old values of the first time the getExtras() is read.
i understood that the operational system Android are not creating a new Activity but only giving it to the top.
using the answser of CommonsWare that helped with the override onNewIntetn and the link:
http://www.helloandroid.com/tutorials/communicating-between-running-activities
1 into xmlFile: put th android:launchMode="singleTask"
for the activity will receive the extra parameters with getExtras.
<activity android:name=".ActivityWillReceiveWithGetExtras"
android:launchMode="singleTask"
android:taskAffinity=""
android:excludeFromRecents="true">
</activity>
2.into the activity you that will receive the values with get_extras(...) override a method called onNewIntent:
2.1 Observation: put the line:
setIntent(intent);
to set the identifier of the intent.
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);//must store the new intent unless getIntent() will return the old one
getExtraParameterActual();
}
2.2 get the Extra parameters into a function that will have inside the command getExtras(...
getExtraParameterActual();
Write the function of the top getExtraParameterActual();
private void getExtraParameterActual() {
Intent intent = getIntent();//take back the value set with //setintenT of pass 2.1
user = getIntent().getExtras().getString(USER);//
}
5.
into OnCreate() call the e getExtraParameterActual();
and if necessary reload your views with a method for example reloadMyViews()
into onResume() reload your views again with the same function of the pass 5 reloadMyViews()
7 the notificatio code I used take care with the FLAGS
public void notificationCreateGu(String User) {
Log.d(TAG,nameOfTheService+"BUG createnotification for received CHAT messages useruidOfTheFriendNear="+newMessageUserUidOfSender);
Intent it = new Intent(this,ActivityWillReceiveWithGetExtras.class);
it.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
it.putExtra(USER,user);
StoreValuesClass.count=StoreValuesClass.count+2;
PendingIntent pi = PendingIntent.getActivity(this, StoreValuesClass.count,it, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this)
.setTicker(newMessageUserUidOfSender )
.setSmallIcon(android.R.mipmap.sym_def_app_icon)
.setContentTitle("Title Message ")
.setContentText(String.valueOf(newMessageUserUidOfSender))
.setContentIntent(pi)
.setAutoCancel(true)
.build();
int m;
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
m= StoreValuesClass.count=StoreValuesClass.count+2;
notificationManager.notify((m), notification);
}
Override onNewIntent() in your activity.
getIntent() returns the Intent that was used to initially create the activity. If an existing activity instance is brought back to the foreground via a startActivity() call, onNewIntent() is called to deliver to you the Intent used for that most recent startActivity() call.

Why do Android alarms fire at the same time?

Below is a pretty simple method that takes a Date and an id for an alarm to be fired which starts a countdown. For some reason I don't understand, if I call it once with one date and id 0 and call it again with another date and id 1 (i.e., two different countdowns), Android will fire both alarms at the same time (specifically the first date passed with id 0) so both countdowns start at the same time.
Can anyone tell me why and how to fix it? Thanks!
public void setCountdownAlarm(Date fireTime, int id)
{
// startCountdown will be called at fireTime
BroadcastReceiver startCountdown = new BroadcastReceiver() {
#Override public void onReceive( Context context, Intent theIntent )
{
countdownTimer = new Timer();
countdownTimer.schedule(new TimerTask() {
#Override
public void run() {
onSecondTick(showtime);
}
}, 0, 100); // call every 10th of a second
}
};
this.registerReceiver( startCountdown, new IntentFilter("com.counter.app.CountActivity.COUNT") );
Intent intent = new Intent("com.counter.app.CountActivity.COUNT");
PendingIntent pintent = PendingIntent.getBroadcast( this, id, intent, 0 );
AlarmManager manager = (AlarmManager)(this.getSystemService( Context.ALARM_SERVICE ));
if (Build.VERSION.SDK_INT >= 19)
manager.setExact(AlarmManager.RTC_WAKEUP, fireTime.getTime(), pintent);
else
manager.set(AlarmManager.RTC_WAKEUP, fireTime.getTime(), pintent);
}
Editing to say that when I waited for the second alarm to fire, Android actually calls startCountdown twice -- once again for each alarm. Help!
I figured out what I did wrong. As explained in answers to similar questions, the second parameter of PendingIntent.getBroadcast (requestCode) must be unique if you want to get a unique pending intent. I took care of that by passing "id".
The second problem was that I registered the BroadcastReceiver each time I called setCountdownAlarm. The BroadcastReceiver should only be registered once, typically in the onCreate method of the activity.

Location Manager.RequestLocationUpdates using pendingIntent always broadcasting the same location, when gps provider takes long time to get location

I am new to android development, I want my device to get GPS location every 40 seconds in background mode, even after the app got killed. For that, In MyAlarm.class, I have setRepeating the Alarm every 40 seconds to call a "RepeatingAlarm.class(which extends BroadcastReceiver)" using the pending intent. In the onReceive method of the "RepeatingAlarm.class" called every 40 seconds, I have created another pending intent to call MyReceiver.class(which extends BroadcastReceiver). I have passed this pending intent created in the "RepeatingAlarm.class" to a requestLocationUpdate function, to get the GPS location.
My problem is that, sometimes I will get the same lat and long values repeatedly every 40 seconds continuing about atleast 3 minutes.
Then, the onReceive method of my MyReceiver.class is calling every second, instead of calling once the GPS location got received. I have pasted my code below, Please help me with a solution.
MyAlarm.class
public void StartAlarm(Context context)
{
AlarmManager alm=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, RepeatingAlarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
alm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 40000, pi);
}
RepeatingAlarm.class
public class RepeatingAlarm extends BroadcastReceiver
{
public static LocationManager locationManager = null;
public static PendingIntent pendingIntent = null;
#Override
public void onReceive(Context context, Intent intent)
{
locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
Intent intentp = new Intent(context, MyReceiver.class);
pendingIntent = PendingIntent.getBroadcast(context, 0, intentp, PendingIntent.FLAG_UPDATE_CURRENT);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
provider = locationManager.getBestProvider(criteria, true);
if(provider != null)
{
locationManager.requestSingleUpdate(locationManager.GPS_PROVIDER, pendingIntent);
}
}
}
MyReceiver.class
public class MyReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
String locationKey = LocationManager.KEY_LOCATION_CHANGED;
if (intent.hasExtra(locationKey))
{
Location location = (Location)intent.getExtras().get(locationKey);
double mlatitude = location.getLatitude();
double mlongitude = location.getLongitude();
if(RepeatingAlarm.locationManager != null && RepeatingAlarm.pendingIntent)
{
RepeatingAlarm.locationManager.removeUpdates(RepeatingAlarm.pendingIntent);
}
}
}
}
In the above code, the GPS location is receiving good once in every 40 seconds. But, sometimes, if once GPS takes long time to get the location say 15 minutes, after that every 40 seconds the same previous location is repeating till about 4 minutes. This is my major problem.
Then, the MyReceiver.class is calling frequently every seconds. Please help me with some example lines of code to solve this issue. Thank You all.
As per the developer documents requestSingleUpdate() method "Register for a single location update using a named provider and pending intent."
You need to use requestLocationUpdates() method instead.
The second parameter of this method minimum time interval between location updates, in milliseconds will allow you to fetch location again & again.

Android: Managing Multiple Notifications

I am trying to create multiple notifications in my application. To identify each notification uniquely, i have given them an unique identificationId. Following is my code:
private void updateNotification(int notificationId, int clockStatusID, CharSequence text) {
//notificationManager.cancel(notificationId);
// throws up an ongoing notification that the timer is running
Log.i("TIMERCOUNT", "Notification id: " + notificationId);
Notification not = new Notification(clockStatusID, // the
// icon
// for
// the
// status
// bar
text, // the text to display in the ticker
System.currentTimeMillis() // the timestamp for the
// notification to appear
);
Intent intent = new Intent();
intent.putExtra("notificationID", notificationId);
intent.setAction("actionstring" + System.currentTimeMillis());
intent.setClassName("com.chander.time.android.activities",
"com.chander.time.android.activities.Tabs");
not.setLatestEventInfo(self,
getText(R.string.timer_notification_title),
getText(R.string.timer_on_notification_text), PendingIntent
.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT));
not.flags += Notification.FLAG_ONGOING_EVENT;
not.flags += Notification.FLAG_NO_CLEAR;
notificationManager.notify(notificationId, not);
}
Problem:
When a notification is selected, Tabs activity is called passing the intent. I want to access the unique notificationId of the notification that was selected in Tabs. I tried intent.putExtra() to save the notificationId in the intent. But, for multiple notifications its overwriting the notificationId and returns the latest one. I dont understand as to why this is happening and how can i avoid this overwriting of notificationId.
Thanks,
Chander
I got the answer. The intents were getting cached in. To, make a new intent, just add the following piece of code:
saveCallIntent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
This makes the intent unique.
Also, someone suggested me the following piece of code to make the intent unique:
saveCallIntent.setAction("actionstring" + System.currentTimeMillis());
It didnt help me, but might be of help to someone else.
--Chander
just place the notificationId instead of 0 in pendingIntent.
PendingIntent.getActivity(this, notificationId, intent,PendingIntent.FLAG_UPDATE_CURRENT));
The user must also update the following code together with the above one to get it working.
mNotificationManager.notify(notificationId, mBuilder.build());

Categories