Proximity Alert Class Doesn't Fire Android - java

I'm trying to set up a proximity alarm based on the location of a selected marker, the coordinates for which are stored in an external file and read into an array, which in turn draws the coordinates.
googleMap.setOnInfoWindowClickListener(
new OnInfoWindowClickListener(){
public void onInfoWindowClick(Marker marker) {
LatLng clickedMarkerLatLng = marker.getPosition();
double lat = clickedMarkerLatLng.latitude;
double long1 = clickedMarkerLatLng.longitude;
Log.e("hello", "Output=" + lat + long1);
LocationManager lm;
// double lat=0;
// double long1=0; //Defining Latitude & Longitude
float radius=3000;
lm=(LocationManager) getSystemService(LOCATION_SERVICE);
Intent i= new Intent("com.example.sleepertrain5.proximityalert"); //Custom Action
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), -1, i, 0);
lm.addProximityAlert(lat, long1, radius, -1, pi);
Toast.makeText(getBaseContext(),
"Info Window clicked#" + lat + "dddjdj" + long1,
Toast.LENGTH_SHORT).show();
class ProximityReceiver extends android.content.BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
// The reciever gets the Context & the Intent that fired the broadcast as arg0 & agr1
String k=LocationManager.KEY_PROXIMITY_ENTERING;
// Key for determining whether user is leaving or entering
boolean state=arg1.getBooleanExtra(k, false);
//Gives whether the user is entering or leaving in boolean form
if(state){
// Call the Notification Service or anything else that you would like to do here
Toast.makeText(arg0, "Welcome to my Area", 600).show();
}else{
//Other custom Notification
Toast.makeText(arg0, "Thank you for visiting my Area,come back again !!", 600).show();
}
}
}
}
});
}
The coordinates of the selected marker are passed to the location manager, but the proximity alarm doesn't work. Obviously at the moment, it just displays a toast, but it's not even doing that. According to the Log, the Proximity receiver class is never called, but I can't figure out why. I've tried it with varying sizes of radius and it still doesn't work. Any ideas or help?

You need to register your BroadcastReceiver with the Intents action you used for the PendingIntent. You can do this in the AndroidManifest.xml by adding these lines:
<receiver android:name="MyScheduleReceiver" >
<intent-filter>
<action android:name="com.example.sleepertrain5.proximityalert" />
</intent-filter>
</receiver>

Related

Android 11 - LocationManager.addProximityAlert does not trigger alerts

The addProximityAlert call stopped triggering alerts on Android 11 devices.
I call the addProximityAlert for the special locations (calculated for the user location) from the Application.onCreate method or whenever the ACCESS_FINE_LOCATION permission is granted using the following code:
mLocationManager = (LocationManager) mApplicationContext.getSystemService(Context.LOCATION_SERVICE);
if (mLocationManager != null) {
final Criteria criteria = new Criteria();
//criteria.setAccuracy(Criteria.ACCURACY_COARSE);
criteria.setAccuracy(Criteria.ACCURACY_FINE);
String provider = mLocationManager.getBestProvider(criteria, true);
if (!TextUtils.isEmpty(provider)) {
mLocationUpdatelistener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
subscribeForProximityAlert(location);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
};
final Location lastKnownLocation = mLocationManager.getLastKnownLocation(provider);
if (lastKnownLocation == null) {
try {
mLocationManager.requestSingleUpdate(criteria, mLocationUpdatelistener, Looper.getMainLooper());
} catch (Throwable e) {
e.printStackTrace();
}
} else {
subscribeForProximityAlert(lastKnownLocation);
}
}
}
The subscribeForProximityAlert function is as follows (it is called actually after the successful single location update - I've checked that):
void subscribeForProximityAlert(Location location) {
String id;
double lat;
double lng;
long radius;
// ... compute the params above using the location
final Intent intent = new Intent(ACTION_FILTER);
intent.putExtra("_id", id);
intent.putExtra("_lat", lat);
intent.putExtra("_lng", lng);
intent.putExtra("_rad", radius);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(mApplicationContext, i, intent, 0);
mPendingIntents.add(pendingIntent);
mLocationManager.addProximityAlert(
lat,
lng,
(float) radius,
24 * 60 * 60 * 1000,
pendingIntent
);
}
The ACTION_FILTER is the com.example.appname.ProximityAlert exactly the value I use in manifest to subscribe for the Proximity Alert broadcasts (com.example.appname is the package name of the app):
<application>
<receiver android:name="com.example.appname.ProximityAlertBroadcastReceiver">
<intent-filter>
<action android:name="com.example.appname.ProximityAlert" />
</intent-filter>
</receiver>
</application>
The ProximityAlertBroadcastReceiver can be as simple as:
public class ProximityAlertBroadcastReceiver extends BroadcastReceiver {
public ProximityAlertBroadcastReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
}
}
its onReceive method is never called on Android 11 devices (checked with Lod.d and Toast.makeText...show() calls). Not when the app is running, not when it's in background. Not when I'm already in the radius of specified point, not when I'm entering/exiting.
Tried to add the android.permission.ACCESS_BACKGROUND_LOCATION permission to the manifest (nothing about it in the LocationManager.addProximityAlerts docs anyway) and grant the permission in system settings for the app, but it didn't help.
Also tried to reduce the targetSdkVersion from 30 to 28, but it didn't help.
The problem happened because of the implicit intent for the broadcast receiver, which is prohibited for the app targeting Android 8+ (SDK version 26):
https://developer.android.com/about/versions/oreo/background#broadcasts
After changing the
final Intent intent = new Intent(ACTION_FILTER);
to
final Intent intent = new Intent(mApplicationContext, ProximityAlertBroadcastReceiver.class);
I started to receive the broadcasts.
UPDATE: There's a bug in recent Android versions (11, 12, maybe others) which makes Geofences unresponsive on some devices and completely non-working on other devices if no app is actively requesting location at the moment:
https://issuetracker.google.com/issues/218335535
addProximityAlert creates a geofence under the hood, so it's affected too.

Getting sensor data in an IntentService and receiving using a broadcast

I am developing an application to set system alarms automatically by judging the movement and environment of a mobile phone using accelerometer and light sensor data.For doing this, I have am using IntentService + Alarm Manager . I want my service to get the sensor data and broadcast it. I capture the broadcast in another activity and write the sensor values to a file. I use alarm manager so that I can get the sensor values periodically. I'm facing two problems :
I'm not able to capture sensor data in my service.
Receive data from the service and write it to a file.
As I can see on my Logcat, only 'onCreate' and 'onHandleIntent' methods of my intentservice are being executed. The 'onSensorChanged' method is not being executed. Is it because I'm sending a broadcast in the 'onHandle' method and the service doesn't execute anything else other than that. If this is so, please guide me as to how can I achieve my use case of getting sensor data in a service and sending it back to activity to perform further processing at regular intervals.
Following is my code :
MainActivity.java
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scheduleAlarm();
}
// Setup a recurring alarm every 15 minutes
public void scheduleAlarm() {
Toast.makeText(MainActivity.this, "Scheduling Alarm.", Toast.LENGTH_SHORT).show();
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(this, AlarmReceiver.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every 5 seconds
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
AlarmManager.INTERVAL_FIFTEEN_MINUTES, pIntent);
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
public static final String ACTION = "com.example.tyagi.smartalarm.alarm";
// Triggered by the Alarm periodically (starts the service to run task)
#Override
public void onReceive(Context context, Intent intent) {
Log.d("AlarmReceiver", "Alarm called.");
Intent i = new Intent(context, sensorService.class);
i.putExtra("foo", "bar");
context.startService(i);
}
}
IntentService.java
public class sensorService extends IntentService implements SensorEventListener {
public static final String ACTION = "com.example.tyagi.smartalarm.sensorService";
private SensorManager sensorManager; // this instance of SensorManager class will be used to get a reference to the sensor service.
private Sensor mSensor,lSensor; // this instance of Sensor class is used to get the sensor we want to use.
private float[] mGravity;
private float mAccel;
private float mAccelCurrent;
private float mAccelLast;
TextView xCoor; // declare X axis object
TextView yCoor; // declare Y axis object
TextView zCoor; // declare Z axis object
TextView lightVal;
// constructor for the java class. Mandatory, otherwise was showing error.
public sensorService() {
super("sensorService");
}
#Override
public void onCreate() {
super.onCreate(); // if you override onCreate(), make sure to call super().
// If a Context object is needed, call getApplicationContext() here.
Log.d("sensorService","onCreate");
sensorManager=(SensorManager) getSystemService(SENSOR_SERVICE); // get an instance of the SensorManager class, lets us access sensors.
mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // get Accelerometer sensor from the list of sensors.
lSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); // get light sensor from the list of sensors.
mAccel = 0.00f;
mAccelCurrent = SensorManager.GRAVITY_EARTH;
mAccelLast = SensorManager.GRAVITY_EARTH;
}
public void onAccuracyChanged(Sensor sensor,int accuracy){
}
// // if sensor value is changes, change the values in the respective textview.
public void onSensorChanged(SensorEvent event){
Log.d("sensorService", "onSensorChanged.");
/* check sensor type */
if(event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
mGravity = event.values.clone();
// assign directions
float x=event.values[0];
float y=event.values[1];
float z=event.values[2];
xCoor.setText("X: "+x);
yCoor.setText("Y: "+y);
zCoor.setText("Z: "+z);
float x1=event.values[0];
float y1=event.values[1];
float z1=event.values[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float)Math.sqrt(x*x + y*y + z*z); // we calculate the length of the event because these values are independent of the co-ordinate system.
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel*0.9f + delta;
if(mAccel > .5)
{
Toast.makeText(sensorService.this, "Movement Detected.", Toast.LENGTH_SHORT).show();
}
}
else if(event.sensor.getType()==Sensor.TYPE_LIGHT)
{
float l = event.values[0];
lightVal.setText(l+"");
}
/* unregister if we just want one result. */
sensorManager.unregisterListener(this);
}
#Override
protected void onHandleIntent(Intent intent) {
// This describes what will happen when service is triggered
// Fetch data passed into the intent on start
String val = intent.getStringExtra("foo");
// Construct an Intent tying it to the ACTION (arbitrary event namespace)
Intent in = new Intent(ACTION);
in.putExtra("resultCode", Activity.RESULT_OK);
in.putExtra("resultValue","My result value. Passed in : " + val);
// Fire the broadcast with intent packaged
LocalBroadcastManager.getInstance(this).sendBroadcast(in);
// or sendBroadcast(in) for a normal broadcast;
Log.d("sensorService", "Service running");
}
}
RegularService : as suggested by #Mike I tried using a regular service. This time also, only the onCreate method of this is getting executed. Rest nothing happens.
public class MyService extends Service implements SensorEventListener{
public MyService() {
}
private SensorManager sensorManager; // this instance of SensorManager class will be used to get a reference to the sensor service.
private Sensor mSensor,lSensor; // this instance of Sensor class is used to get the sensor we want to use.
private float[] mGravity;
private float mAccel;
private float mAccelCurrent;
private float mAccelLast;
#Override
public void onCreate() {
super.onCreate(); // if you override onCreate(), make sure to call super().
// If a Context object is needed, call getApplicationContext() here.
Log.d("MyService", "onCreate");
sensorManager=(SensorManager) getSystemService(SENSOR_SERVICE); // get an instance of the SensorManager class, lets us access sensors.
mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // get Accelerometer sensor from the list of sensors.
lSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); // get light sensor from the list of sensors.
mAccel = 0.00f;
mAccelCurrent = SensorManager.GRAVITY_EARTH;
mAccelLast = SensorManager.GRAVITY_EARTH;
}
public int onStartCommand(){
Log.d("MyService","onStartCommand");
return START_STICKY;
}
public void onAccuracyChanged(Sensor sensor,int accuracy){
}
// // if sensor value is changes, change the values in the respective textview.
public void onSensorChanged(SensorEvent event){
Log.d("sensorService", "onSensorChanged.");
Toast.makeText(MyService.this, "onSensorChanged.", Toast.LENGTH_SHORT).show();
/* check sensor type */
if(event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
mGravity = event.values.clone();
// assign directions
float x=event.values[0];
float y=event.values[1];
float z=event.values[2];
float x1=event.values[0];
float y1=event.values[1];
float z1=event.values[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float)Math.sqrt(x*x + y*y + z*z); // we calculate the length of the event because these values are independent of the co-ordinate system.
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel*0.9f + delta;
if(mAccel > 3)
{
Toast.makeText(MyService.this, "Movement Detected.", Toast.LENGTH_SHORT).show();
}
}
else if(event.sensor.getType()==Sensor.TYPE_LIGHT)
{
float l = event.values[0];
}
/* unregister if we just want one result. */
// sensorManager.unregisterListener(this);
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}

Why don't I get proximity alterts even though I've registered alerts?

I'm trying to simply set a proximity later for an area an for testing, I simply added this to the onCreate method of my main activity.
public void onCreate(Bundle bndBundle) {
IntentFilter filter = new IntentFilter(WidgetService.ACTION_STOP_PROXIMITY);
registerReceiver(new ProximityIntentReceiver(), filter);
LocationManager locManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);
Intent ittIntent = new Intent(this, ProximityIntentReceiver.class);
ittIntent.putExtra(WidgetService.KEY_STOP_IDENTIFIER, 1000);
PendingIntent pitIntent = PendingIntent.getBroadcast(this, 0, ittIntent, 0);
locManager.addProximityAlert(60.15769, 24.94150, 150, -1, pitIntent);
super.onCreate(bndBundle);
getActionBar().setDisplayHomeAsUpEnabled(false);
}
..and here's the simple receiver class that I'm using
public class ProximityIntentReceiver extends BroadcastReceiver {
private static final int NOTIFICATION_ID = 1000;
#Override
public void onReceive(Context context, Intent intent) {
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");
}
}
}
I'm testing this on my emulator and when I use the DDMS console to set the co-ordinates of the phone manually, I still don't see the log message.
My manifest file doesn't have any special code. I've added the correct permissions and have the code for a simple activity- no services or anything.
I read through a whole bunch of posts on StacKOverflow but I haven't been able to resolve the issue. Am I missing something in my snippet?
You are registering this receiver dynamically, through registerReceiver(), to have it respond to broadcasts whose action string is WidgetService.ACTION_STOP_PROXIMITY.
However, the actual broadcast you are sending is trying to use an explicit Intent, identifying your receiver class. This does not line up with the IntentFilter that you are using with registerReceiver().
Either:
Register your receiver in the manifest and get rid of registerReceiver(), in which case your explicit Intent will work, or
Use new Intent(WidgetService.ACTION_STOP_PROXIMITY) instead of new Intent(this, ProximityIntentReceiver.class), so your Intent lines up with your IntentFilter
You cannot use explicit Intent objects to send broadcasts to receivers registered via registerReceiver(). An explicit Intent will only work with a manifest-registered receiver.
make sure you type in the right coordinates. in DDMS they're reversed, longitude first, then latitude

Android Proximity Alerts Not Working

I'mm trying to create an app that allows you to set a proximity alert for marker when you click on it's info window.
googleMap.setOnInfoWindowClickListener(
new OnInfoWindowClickListener(){
public void onInfoWindowClick(Marker marker) {
LatLng clickedMarkerLatLng = marker.getPosition();
double lat = clickedMarkerLatLng.latitude;
double long1 = clickedMarkerLatLng.longitude;
Log.e("hello", "Output=" + lat + long1);
LocationManager lm;
// double lat=123,long1=34; //Defining Latitude & Longitude
float radius=30; //Defining Radius
lm=(LocationManager) getSystemService(Context.LOCATION_SERVICE);
Intent i= new Intent("com.example.sleepertrain5.ProximityReceiver"); //Custom Action
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, i, PendingIntent.FLAG_CANCEL_CURRENT);
lm.addProximityAlert(lat, long1, radius, -1, pendingIntent);
}
This is the code that calls the Broadcast Receiver
public class ProximityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
// The reciever gets the Context & the Intent that fired the broadcast as arg0 & agr1
String k=LocationManager.KEY_PROXIMITY_ENTERING;
// Key for determining whether user is leaving or entering
boolean state=arg1.getBooleanExtra(k, false);
//Gives whether the user is entering or leaving in boolean form
if(state){
// Call the Notification Service or anything else that you would like to do here
Toast.makeText(arg0, "Welcome to my Area", 600).show();
}else{
//Other custom Notification
Toast.makeText(arg0, "Thank you for visiting my Area,come back again !!", 600).show();
}
}
The above is the Broadcast receiver. None of this works and I can't figure out why. Any help would be great.
Use below code for Pending Intent:
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
nId, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Where nId will be any uniq number that represent particular pending intent.

Orientation change and Notification

I want to implement the following scenario:
When a user presses the Home key a Notification is displayed in the Status bar and the App is normally hidden. When user taps the Notification App is normally restored.
Here is my code for this:
private int NOTIFICATION = R.string.local_service_started;
private NotificationManager mNM;
private void showNotification() {
CharSequence text = getText(R.string.local_service_started);
Notification notification = new Notification(R.drawable.icon, text, System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, JingleCartoucheActivity.class), 0);
notification.setLatestEventInfo(this, getText(R.string.local_service_label), text, contentIntent);
mNM.notify(NOTIFICATION, notification);
}
#Override
public void onPause() {
super.onPause();
if (!isFinishing()) {
showNotification();
}
}
#Override
public void onResume() {
super.onResume();
mNM.cancel(NOTIFICATION);
}
All of this is working well except for one thing:
When the App is run and the user rotates the phone, the notification is created and immediately destroyed. Is there a way to detect the phone orientation change in onPause() and not show this Notification?
You can get the current orientation using the getResources().getConfiguration().orientation. At the onCreate you store the orientation value and then you can compare it later. Be sure to store the value into a static variable, since when you rotate the phone, the activity is destroyed and so are it's values.
When the user rotate the screen the activity is destroyed and recreated , If you want to display the notification after orientation change make a static flag in onDestroy method and check it in the onCreate method to display the notification like
public void onDestroy() {
Flag = 1;
}
and
public static int Flag = 0;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(Flag == 1) {
showNotification();
}
else {
.......//
}
}

Categories

Resources