notification sound is not playing in android 10 - android-studio

I am sending notifications through Firebase Cloud Messaging But the sound and vibration are not playing on my phone which has Android 10 but Sound is playing in the android emulator which has android 9. As it is an emulator I can not say it having vibration or not.
I already checked other StackOverflow posts but can not get the solution.
Here is my code-
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
/**
* NOTE: There can only be one service in each app that receives FCM messages. If multiple
* are declared in the Manifest then the first one will be chosen.
* <p>
* In order to make this Java sample functional, you must remove the following from the Kotlin messaging
* service in the AndroidManifest.xml:
* <p>
* <intent-filter>
* <action android:name="com.google.firebase.MESSAGING_EVENT" />
* </intent-filter>
*/
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* #param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
}
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
String channelId = getString(R.string.default_notification_channel_id);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.logo)
.setContentTitle("Brain Filter")
.setColor(getResources().getColor(R.color.colorAccent))
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
I also added Vibration and Internet permission in the manifest.xml and always enable sound in Firebase console when pushing any notification.

Uninstall your app and Install again will fix the issue.
The settings are set the first time you create the channel and then not modified unless you do it manually by fresh install or clearing data.

Related

how to open a specific UserInterface, onClicking on firebase push notification in android studio?

I am using firebase push notification and also my android device get notification too.
if I get notification, while app is open and I can read "title" and "Message" and it take me to "UserDetailsActivity" a specific class .But I also want to do the same thin on click the the notification. But when click on the notification it doesn't open the "UserDetailsActivity" and it open launchering clas and i can't read the message . Any one have solution for it?
firebaseService class
public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService {
private static int count = 0;
#Override
public void onMessageReceived(#NonNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
startService(new Intent(getApplicationContext(),UserDetailsActivity.class));
/*
Message data payload:
Message Notification Body:
*/
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
}
}
*androidMainfest
<service
android:name=".backgroundService.FirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
As per the documentation, when messages with both notification and data payload are received and application is in background mode, the notification is delivered to the device’s system tray, and the data payload is delivered in the extras of the intent of launcher Activity.
Option 1:
You can try to to handle the data in launch activity and from there launch UserDetailsActivity and finish launcher activity quickly without showing UI.
https://firebase.google.com/docs/cloud-messaging/android/receive
Option 2:
Dont send notification part from FCM and send only payload part. In onmessagereceived() method ,construct the notification with pending intent for UserDetails activity or service.
On launcher activer
if (getIntent().getExtras() != null) {
for (String key : getIntent().getExtras().keySet()) {
String value = getIntent().getExtras().getString(key);
Log.d(TAG, "Key: " + key + " Value: " + value);
}
}

TarsosDSP in Android Studio

This is my first post on SO and I am trying to combine my music skills with computer science.
I am using Android studio 3.1.2 with gradle 4.5, Nexus 5X, API 25, Android 7.1.1, Windows 7.
I followed very careful these instructions:
Create a project called Pitchbender
Download the .jar of TarsosDSP and included in
C:\Users\Carlos\AndroidStudioProjects\Pitchbender\app\libs\TarsosDSP-Android-latest
I checked the build.gradle of my project:
dependencies { implementation fileTree(dir: ‘libs’, include: [‘*.jar’]) }
In my project, I have the following imports automatically done by Android Studio:
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import be.tarsos.dsp.AudioEvent
import be.tarsos.dsp.io.android.AudioDispatcherFactory
import be.tarsos.dsp.pitch.PitchDetectionHandler
import be.tarsos.dsp.pitch.PitchDetectionResult
import be.tarsos.dsp.pitch.PitchProcessor
import kotlinx.android.synthetic.main.activity_main.*
import be.tarsos.dsp.pitch.PitchProcessor.PitchEstimationAlgorithm
import be.tarsos.dsp.AudioProcessor
import android.widget.TextView
import be.tarsos.dsp.AudioDispatcher
I have this permission in my manifest file
uses-permission android:name=”android.permission.RECORD_AUDIO”
Android Studio gives the option to convert to Kotlin the first line of the following code:
AudioDispatcher dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(22050,1024,0);
If I respond to “No” to the Kotlin conversion, I have the following compilation error:
Clasifier “AudioDispatcher” does not have any companion object, and thus must be initialized here.
What can I do?
If I respond “Yes” to the Kotlin conversion question, that statement is converted to
val dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(22050, 1024, 0)
and then, when I run this program, Android informs me that there is an error and closes my project and keeps closing my project. What to do?
Please help to run at least that first instruction of the complete code:
PitchDetectionHandler pdh = new PitchDetectionHandler() {
#Override
public void handlePitch(PitchDetectionResult res, AudioEvent e){
final float pitchInHz = res.getPitch();
runOnUiThread(new Runnable() {
#Override
public void run() {
processPitch(pitchInHz);
}
});
}
};
AudioProcessor pitchProcessor = new PitchProcessor(PitchEstimationAlgorithm.FFT_YIN, 22050, 1024, pdh);
dispatcher.addAudioProcessor(pitchProcessor);
Thread audioThread = new Thread(dispatcher, "Audio Thread");
audioThread.start();
Question:
Do you have any simple project in Android Studio, so that I can see what my errors are?
I had a similar problem when I tried to run this example and my solution (Sep. 2019) was to add a runtime confirmation of the record permission. I'm not sure if it's the same case, buuuut
Here is my code to it:
private boolean permissionToRecordAccepted = false;
private String [] permissions = {Manifest.permission.RECORD_AUDIO};
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200;
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case REQUEST_RECORD_AUDIO_PERMISSION:
permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
break;
}
if (!permissionToRecordAccepted ) finish();
}

Receiving messages from Azure IOT Hub using MQTT

I am trying to send messages to Azure IOT hub using MQTT and using Azure Device SDK libraries. There are two devices which are configured on IOT Hub. Both devices have different connection string.
Connection string for device 1
connString = "HostName=ABC.azure-devices.net;DeviceId=ABC;SharedAccessKey=sharedKey";
Connection string for device 2
connString = "HostName=DEF.azure-devices.net;DeviceId=DEF;SharedAccessKey=sharedKey";
I have wrote two publishers that will send the messages to IOT hub and the subscriber that will recieve message from IOT Hub sent by the publishers.
In first publisher I have passed connection string for device 1 and for second publisher the connection string for device 2. Now when I am running both the publisher classes simultaneously, subscriber is recieving messages from both the publishers. Can anyone let me know how can I modify the code so that the subscriber will only only recieve messages sent by publisher 1 even when both the publisher are running simultaneously.
Here is my code for Publisher 1.
package com.iot.mqtt.connection;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.gson.Gson;
import com.microsoft.azure.sdk.iot.device.DeviceClient;
import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol;
import com.microsoft.azure.sdk.iot.device.IotHubEventCallback;
import com.microsoft.azure.sdk.iot.device.IotHubStatusCode;
import com.microsoft.azure.sdk.iot.device.Message;
//import com.microsoft.docs.iothub.samples.SimulatedDevice.EventCallback;
//import com.microsoft.docs.iothub.samples.SimulatedDevice.MessageSender;
//import com.microsoft.docs.iothub.samples.SimulatedDevice.TelemetryDataPoint;
public class SimulatedDevice {
// The device connection string to authenticate the device with your IoT hub.
// Using the Azure CLI:
// az iot hub device-identity show-connection-string --hub-name {YourIoTHubName} --device-id MyJavaDevice --output table
private static String connString = "HostName=ABC.azure-devices.net;DeviceId=ABC;SharedAccessKey=aTVNu55sN9a2Y9+V0BCAOXdo8nSFDNzByfiTqMvNb20=";
// Using the MQTT protocol to connect to IoT Hub
private static IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
private static DeviceClient client;
// Specify the telemetry to send to your IoT hub.
private static class TelemetryDataPoint {
public double temperature;
public double humidity;
public String message;
public String timeStamp;
// Serialize object to JSON format.
public String serialize() {
Gson gson = new Gson();
return gson.toJson(this);
}
}
// Print the acknowledgement received from IoT Hub for the telemetry message sent.
private static class EventCallback implements IotHubEventCallback {
public void execute(IotHubStatusCode status, Object context) {
System.out.println("IoT Hub responded to message with status: " + status.name());
if (context != null) {
synchronized (context) {
context.notify();
}
}
}
}
private static class MessageSender implements Runnable {
public void run() {
try {
// Initialize the simulated telemetry.
double minTemperature = 20;
double minHumidity = 60;
String message;
Random rand = new Random();
InputStream is = null;
Properties prop = null;
prop = new Properties();
is = new FileInputStream("C:\\Users\\H251970\\eclipse-workspace\\IOTMqttTestProject\\resources\\config.properties");
prop.load(is);
message = prop.getProperty("message");
minTemperature = Double.parseDouble(prop.getProperty("temperature"));
minHumidity = Double.parseDouble(prop.getProperty("humidity"));
//System.out.println(message);
while (true) {
// Simulate telemetry.
double currentTemperature = minTemperature + rand.nextDouble() * 15;
double currentHumidity = minHumidity + rand.nextDouble() * 20;
String datatimeStamp= new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());;
TelemetryDataPoint telemetryDataPoint = new TelemetryDataPoint();
telemetryDataPoint.temperature = currentTemperature;
telemetryDataPoint.humidity = currentHumidity;
telemetryDataPoint.message = message;
telemetryDataPoint.timeStamp = datatimeStamp;
// Add the telemetry to the message body as JSON.
String msgStr = telemetryDataPoint.serialize();
Message msg = new Message(msgStr);
// Add a custom application property to the message.
// An IoT hub can filter on these properties without access to the message body.
msg.setProperty("temperatureAlert", (currentTemperature > 30) ? "true" : "false");
System.out.println("Sending message: " + msgStr);
Object lockobj = new Object();
// Send the message.
EventCallback callback = new EventCallback();
client.sendEventAsync(msg, callback, lockobj);
synchronized (lockobj) {
lockobj.wait();
}
Thread.sleep(3000);
}
} catch (Exception e) {
System.out.println("Exception: " + e);
} /*finally {
inputStream.close();
}*/
}
}
public static void main(String[] args) throws IOException, URISyntaxException {
// Connect to the IoT hub.
client = new DeviceClient(connString, protocol);
client.open();
// Create new thread and start sending messages
MessageSender sender = new MessageSender();
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.execute(sender);
// Stop the application.
System.out.println("Press ENTER to exit.");
System.in.read();
executor.shutdownNow();
client.closeNow();
}
}
Code for publisher 2 is also same just the connection-string is different.
connString = "HostName=DEF.azure-devices.net;DeviceId=DEF;SharedAccessKey=aTVNu55sN9a2Y9+V0BCAOXdo8nSFDNzByfiTqMvNb20=";
The subscriber is recieving the message in following form.
Sending message: {"temperature":"27.739594911863872°C","voltage":"15.81301816513805V","motorspeed":"5.0m/s","inverterName":"i550","timeStamp":"22/08/2018 11:18:03"}
IoT Hub responded to message with status: OK_EMPTY
Here is the code for Subscriber class
package com.microsoft.docs.iothub.samples;
import com.microsoft.azure.eventhubs.ConnectionStringBuilder;
import com.microsoft.azure.eventhubs.EventData;
import com.microsoft.azure.eventhubs.EventHubClient;
import com.microsoft.azure.eventhubs.EventHubException;
import com.microsoft.azure.eventhubs.EventPosition;
import com.microsoft.azure.eventhubs.EventHubRuntimeInformation;
import com.microsoft.azure.eventhubs.PartitionReceiver;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.nio.charset.Charset;
import java.net.URI;
import java.net.URISyntaxException;
public class ReadDeviceToCloudMessages {
// az iot hub show --query properties.eventHubEndpoints.events.endpoint --name {your IoT Hub name}
//private static final String eventHubsCompatibleEndpoint = "{your Event Hubs compatible endpoint}";
private static final String eventHubsCompatibleEndpoint = "sb://ihsuprodmares009dednamespace.servicebus.windows.net/";
// az iot hub show --query properties.eventHubEndpoints.events.path --name {your IoT Hub name}
//private static final String eventHubsCompatiblePath = "{your Event Hubs compatible name}";
private static final String eventHubsCompatiblePath = "eventHubsCompatiblePathString";
// az iot hub policy show --name iothubowner --query primaryKey --hub-name {your IoT Hub name}
private static final String iotHubSasKey = "iotHubSasKeyString=";
private static final String iotHubSasKeyName = "iothubowner";
// Track all the PartitionReciever instances created.
private static ArrayList<PartitionReceiver> receivers = new ArrayList<PartitionReceiver>();
// Asynchronously create a PartitionReceiver for a partition and then start
// reading any messages sent from the simulated client.
private static void receiveMessages(EventHubClient ehClient, String partitionId)
throws EventHubException, ExecutionException, InterruptedException {
final ExecutorService executorService = Executors.newSingleThreadExecutor();
// Create the receiver using the default consumer group.
// For the purposes of this sample, read only messages sent since
// the time the receiver is created. Typically, you don't want to skip any messages.
ehClient.createReceiver(EventHubClient.DEFAULT_CONSUMER_GROUP_NAME, partitionId,
EventPosition.fromEnqueuedTime(Instant.now())).thenAcceptAsync(receiver -> {
System.out.println(String.format("Starting receive loop on partition: %s", partitionId));
System.out.println(String.format("Reading messages sent since: %s", Instant.now().toString()));
receivers.add(receiver);
while (true) {
try {
// Check for EventData - this methods times out if there is nothing to retrieve.
Iterable<EventData> receivedEvents = receiver.receiveSync(100);
// If there is data in the batch, process it.
if (receivedEvents != null) {
for (EventData receivedEvent : receivedEvents) {
System.out.println(String.format("Telemetry received:\n %s",
new String(receivedEvent.getBytes(), Charset.defaultCharset())));
System.out.println(String.format("Application properties (set by device):\n%s",receivedEvent.getProperties().toString()));
System.out.println(String.format("System properties (set by IoT Hub):\n%s\n",receivedEvent.getSystemProperties().toString()));
}
}
} catch (EventHubException e) {
System.out.println("Error reading EventData");
}
}
}, executorService);
}
public static void main(String[] args)
throws EventHubException, ExecutionException, InterruptedException, IOException, URISyntaxException {
final ConnectionStringBuilder connStr = new ConnectionStringBuilder()
.setEndpoint(new URI(eventHubsCompatibleEndpoint))
.setEventHubName(eventHubsCompatiblePath)
.setSasKeyName(iotHubSasKeyName)
.setSasKey(iotHubSasKey);
// Create an EventHubClient instance to connect to the
// IoT Hub Event Hubs-compatible endpoint.
final ExecutorService executorService = Executors.newSingleThreadExecutor();
final EventHubClient ehClient = EventHubClient.createSync(connStr.toString(), executorService);
// Use the EventHubRunTimeInformation to find out how many partitions
// there are on the hub.
final EventHubRuntimeInformation eventHubInfo = ehClient.getRuntimeInformation().get();
// Create a PartitionReciever for each partition on the hub.
for (String partitionId : eventHubInfo.getPartitionIds()) {
receiveMessages(ehClient, partitionId);
}
// Shut down cleanly.
System.out.println("Press ENTER to exit.");
System.in.read();
System.out.println("Shutting down...");
for (PartitionReceiver receiver : receivers) {
receiver.closeSync();
}
ehClient.closeSync();
executorService.shutdown();
System.exit(0);
}
}
Now I am trying to figure out how to recieve messages from publisher 1 only even when both publishers are running simultaneously. Thanks in Advance.
Azure IoT Hub is not a generic MQTT broker. It only supports the following topics:
devices/{device_id}/messages/devicebound/
devices/{device_id}/messages/devicebound/{property_bag}
And Event Hub can't specify device id too. Like what you have found.
There is a workaround but it is only working when your devices less and equal 10. This because the maximum custom endpoint you can create is 10.
That is you can use Service Bus Topic instead of Event Hub:
Device -> Azure IoT Hub -> Routing -> Endpoint "Service Bus Topic"
Add two service bus topic endpoints.
Add two routes for two endpoints:
Receive from the service bus topic:
subscriptionClient = new SubscriptionClient(ServiceBusConnectionString, TopicName, SubscriptionName);

Unfortunately app has stopped error in notification sending

import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.google.android.gms.gcm.GcmListenerService;
import com.htl.jsfshoppingfestival.DataBaseHandler;
public class MyGcmListenerService extends GcmListenerService {
private static final String TAG = "MyGcmListenerService";
private NotificationManager mNotificationManager;
Context ctx;
int countNotification=0;
public void onMessageReceived(String from, Bundle data) {
String message = data.getString("Message");
Log.d(TAG, "From: " + from);
Log.d(TAG, "Message: " + message);
// Toast.makeText(getApplicationContext(), "Notification :"+message, Toast.LENGTH_LONG).show();
// Toast.makeText(getApplicationContext(),from+message,Toast.LENGTH_LONG).show();
if (from.startsWith("/topics/")) {
// message received from some topic.
} else {
// normal downstream message.
}
// [START_EXCLUDE]
/**
* Production applications would usually process the message here.
* Eg: - Syncing with server.
* - Store message in local database.
* - Update UI.
*/
/**
* In some cases it may be useful to show a notification indicating to the user
* that a message was received.
*/
sendNotification(message);
// [END_EXCLUDE]
}
// [END receive_message]
/**
* Create and show a simple notification containing the received GCM message.
*
* #param message GCM message received.
*/
private void sendNotification(String message) {
DataBaseHandler db = new DataBaseHandler(this);
db.addMessage(message);
countNotification=db.getRowCount();
db.close();
Log.d("sender", "Broadcasting message");
Intent localIntent = new Intent("badge count");
// You can also include some extra data.
localIntent.putExtra("Count", countNotification);
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
}
}
I did not get the message as a notification when I send the notification, my app shows:
Unfortunately app has stopped
In debugging I got message=null and app gives error.
In which block you got null? OnMessageReceived or SendNotification?
You need check the message not equal to null.
if(message != null && !message.trim().isEmpty())
{
sendNotification(message);
}

Android Geofence eventually stop getting transition intents

I have an app that started with the Google's geofencing sample code. It works great for a few days, and I get all the transition intents as I anticipate. However, after a bit of time, something like 3 days, the app stops getting these intents, and I don't know why.
When I create my fences, I'm setting the expiration duration to Geofence.NEVER_EXPIRE
Here is my IntentService where I get the transition intents before they stop working:
public class ReceiveTransitionsIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
Intent broadcastIntent = new Intent();
broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);
// First check for errors
if (LocationClient.hasError(intent)) {
...handle errors
} else {
// Get the type of transition (entry or exit)
int transition = LocationClient.getGeofenceTransition(intent);
// Test that a valid transition was reported
if ((transition == Geofence.GEOFENCE_TRANSITION_ENTER)
|| (transition == Geofence.GEOFENCE_TRANSITION_EXIT)) {
// Post a notification
NEVER GETS HERE
} else {
...log error
}
}
}
}
Here is pertinent part of the manifest:
<service
android:name="com.aol.android.geofence.ReceiveTransitionsIntentService"
android:exported="false" >
</service>
In my GeofenceRequester class, it is almost identical to the sample code. Here are the pertinent parts:
// Get a PendingIntent that Location Services issues when a geofence transition occurs
mGeofencePendingIntent = createRequestPendingIntent();
// Send a request to add the current geofences
mLocationClient.addGeofences(mCurrentGeofences, mGeofencePendingIntent, this);
private PendingIntent createRequestPendingIntent() {
// Create an Intent pointing to the IntentService
Intent intent = new Intent(context, ReceiveTransitionsIntentService.class);
return PendingIntent.getService(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
}
Can anyone see why this would stop working?
So after playing around with this a bit, it looks like the ReceiveTransitionsIntentService as defined in the sample code will stop getting the notifications when the app is not around. I think this is a big problem with the example code... Seems like that will trip folks like me up.
So I used a broadcast receiver instead, and so far it seems to be working from my tests.
Add this to the manifest:
<receiver android:name="com.aol.android.geofence.GeofenceReceiver"
android:exported="false">
<intent-filter >
<action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/>
</intent-filter>
</receiver>
Then in the GeofenceRequester class you need to change the createRequestPendingIntent method so that it goes to your BroadcastReceiver instead of the ReceiveTransitionsIntentService
private PendingIntent createRequestPendingIntent() {
// If the PendingIntent already exists
if (null != mGeofencePendingIntent) {
// Return the existing intent
return mGeofencePendingIntent;
// If no PendingIntent exists
} else {
// Create an Intent pointing to the IntentService
Intent intent = new Intent("com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE");
// Intent intent = new Intent(context, ReceiveTransitionsIntentService.class);
/*
* Return a PendingIntent to start the IntentService.
* Always create a PendingIntent sent to Location Services
* with FLAG_UPDATE_CURRENT, so that sending the PendingIntent
* again updates the original. Otherwise, Location Services
* can't match the PendingIntent to requests made with it.
*/
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
}
Then I added the GeofenceReceiver class that looks something like this:
public class GeofenceReceiver extends BroadcastReceiver {
Context context;
Intent broadcastIntent = new Intent();
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);
if (LocationClient.hasError(intent)) {
handleError(intent);
} else {
handleEnterExit(intent);
}
}
private void handleError(Intent intent){
// Get the error code
int errorCode = LocationClient.getErrorCode(intent);
// Get the error message
String errorMessage = LocationServiceErrorMessages.getErrorString(
context, errorCode);
// Log the error
Log.e(GeofenceUtils.APPTAG,
context.getString(R.string.geofence_transition_error_detail,
errorMessage));
// Set the action and error message for the broadcast intent
broadcastIntent
.setAction(GeofenceUtils.ACTION_GEOFENCE_ERROR)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, errorMessage);
// Broadcast the error *locally* to other components in this app
LocalBroadcastManager.getInstance(context).sendBroadcast(
broadcastIntent);
}
private void handleEnterExit(Intent intent) {
// Get the type of transition (entry or exit)
int transition = LocationClient.getGeofenceTransition(intent);
// Test that a valid transition was reported
if ((transition == Geofence.GEOFENCE_TRANSITION_ENTER)
|| (transition == Geofence.GEOFENCE_TRANSITION_EXIT)) {
// Post a notification
List<Geofence> geofences = LocationClient
.getTriggeringGeofences(intent);
String[] geofenceIds = new String[geofences.size()];
String ids = TextUtils.join(GeofenceUtils.GEOFENCE_ID_DELIMITER,
geofenceIds);
String transitionType = GeofenceUtils
.getTransitionString(transition);
for (int index = 0; index < geofences.size(); index++) {
Geofence geofence = geofences.get(index);
...do something with the geofence entry or exit. I'm saving them to a local sqlite db
}
// Create an Intent to broadcast to the app
broadcastIntent
.setAction(GeofenceUtils.ACTION_GEOFENCE_TRANSITION)
.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_ID, geofenceIds)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_TRANSITION_TYPE,
transitionType);
LocalBroadcastManager.getInstance(MyApplication.getContext())
.sendBroadcast(broadcastIntent);
// Log the transition type and a message
Log.d(GeofenceUtils.APPTAG, transitionType + ": " + ids);
Log.d(GeofenceUtils.APPTAG,
context.getString(R.string.geofence_transition_notification_text));
// In debug mode, log the result
Log.d(GeofenceUtils.APPTAG, "transition");
// An invalid transition was reported
} else {
// Always log as an error
Log.e(GeofenceUtils.APPTAG,
context.getString(R.string.geofence_transition_invalid_type,
transition));
}
}
/**
* Posts a notification in the notification bar when a transition is
* detected. If the user clicks the notification, control goes to the main
* Activity.
*
* #param transitionType
* The type of transition that occurred.
*
*/
private void sendNotification(String transitionType, String locationName) {
// Create an explicit content Intent that starts the main Activity
Intent notificationIntent = new Intent(context, MainActivity.class);
// Construct a task stack
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the main Activity to the task stack as the parent
stackBuilder.addParentStack(MainActivity.class);
// Push the content Intent onto the stack
stackBuilder.addNextIntent(notificationIntent);
// Get a PendingIntent containing the entire back stack
PendingIntent notificationPendingIntent = stackBuilder
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Get a notification builder that's compatible with platform versions
// >= 4
NotificationCompat.Builder builder = new NotificationCompat.Builder(
context);
// Set the notification contents
builder.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(transitionType + ": " + locationName)
.setContentText(
context.getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
// Get an instance of the Notification manager
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(0, builder.build());
}
}
Hopefully that helps someone else.
Following can be the reasons why the App is not getting Pending Intents according to the official google documentation -
1.The device is rebooted.
2.The app is uninstalled and re-installed.
3.The app's data is cleared.
4.Google Play services data is cleared.
5.The app has received a GEOFENCE_NOT_AVAILABLE alert.(When Android Location Provider gets switched off)
You have to re-register the geofence after these events.
In my case Location provider gets switched off and also device gets rebooted that's why I was not getting the pending intents.
In my case I had to clear Google Play Services app cache from the app settings, then everything started to work fine again.

Resources