this thing is behaving very strange with us. Some devices hit onmsgrcv, while others dont when the app is closed. How come apps like Whatsapp receives notification when they are closed? Why dont I receive when my app is closed? Need help...
alert.php
$divisions = $_GET['divisions'];
$tokens = array();
$tokens[0] = "e3-nlNImIR8:APA91bGQ3WJW_jWfelz5mEp6L6--wNgdZtb93Bx7kZBSsXUaGYOvdg0_RaP7KlnlfGBD4Xqs3Kyr-IKc0s3072DPGCvToeFeO0w9EHazGOqZt30KbNE7zQr4gbklJ9nZlypyU8IyYzIl";
$tokens[1] = "fWFN3lpvIjI:APA91bF1Kkh-EBEEi8-qkrBgtwxzFAK4WfupWvgjA1PlWjquKTg8yUzMALO9UeTBJHw8UMbE_SLM2cObpf_PolQNkg4AW10Dsg7rtwvI41tIL83Kpm8BZ8cs4GEGXOYrbF0KaB_GG3jo";
$tokens[2] = "eimGs3j1bsA:APA91bFhJHRtxTKldSsrIVr8d12fVLId1DYkUIKgiczTrXGgKLQnoud9ZMIvi1wKHHQWkGcV2ptmLqLfHywgIwWzRxpfaJuICNvgqF2OUnfKist3_t-2XuASukuc4_6Ua9sER29c-oi9";
$data = array(
"divisions" => $divisions
);
$fields = array(
'to' => "/topics/ALERT",
'data' => $data
);
$headers = array(
'Authorization:key = AAAAjCAUSaQ:APA91bGa0FsAjY-5tjEBIiavo960rU39UmendbRC-akMdKxJIdSsqwwlNl4YMl1iAIYd2evyp_5kWe6l_RmpzLGXHiY91NY8LRKa75XNruD9Jvnyu8xNA2IIinLlkJLi8TL5Ud4M9hjY',
'Content-Type: application/json'
);
$ch = curl_init();
$url = "https://fcm.googleapis.com/fcm/send";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch, CURLOPT_POSTFIELDS,json_encode($fields));
$result = curl_exec($ch);
echo $result;
curl_close($ch);
?>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:hardwareAccelerated="false"
android:largeHeap="true"
android:label="#string/app_name"
android:roundIcon="#drawable/ic_launcher"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:name="android.support.multidex.MultiDexApplication"
>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_launcher" />
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorAccent" />
<activity
android:name="com.kayhanswarup.avtro.prokriti.ui.HomeActivity"
android:configChanges="locale|orientation"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
</activity>
<!-- <service android:name=".services.MyService" android:process=":my_service" /> -->
<service android:name="com.kayhanswarup.avtro.prokriti.services.CloudMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name="com.kayhanswarup.avtro.prokriti.services.InstanceTokenService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<provider android:authorities="com.facebook.app.FacebookContentProvider1697853730520523"
android:name="com.facebook.FacebookContentProvider"
android:exported="true"/>
<meta-data android:name="com.facebook.sdk.ApplicationId"
android:value="#string/facebook_app_id"/>
<activity android:name="com.kayhanswarup.avtro.prokriti.ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="#string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="#string/fb_login_protocol_scheme" />
</intent-filter>
</activity>
</application>
CloudMessagingService.java
public class CloudMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
if (remoteMessage.getData().size() > 0) {
ML.d("Message data exists. Should go background: " + remoteMessage.getData());
goBackend(remoteMessage.getData().get("divisions"));
}
else if (remoteMessage.getNotification() != null) {
ML.d("Message Notification Body: " + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody());
}
}
public int currentDivisionIndex = -1;
public String currentDivision="";
private void goBackend(final String messageBody){
ML.setTagServer(true);
ML.i("Reached with data: "+messageBody);
final Intent intent1 = new Intent(this,HomeActivity.class);
final String[] divisions = ApiEndPoints.DIVISIONS;
try {
provider = LocationManager.NETWORK_PROVIDER;
locationManager=(LocationManager)getBaseContext().getSystemService(Context.LOCATION_SERVICE);
final Location location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(location!=null){
ML.d("location(lng,lat) value in background app: "+location.getLongitude()+","+location.getLatitude());
ApiClient.getInstance(getBaseContext())
.getWeather(location.getLatitude()+"", location.getLongitude()+"", new OnResponse<Weather, ANError>() {
#Override
public void onResponse(Weather response) {
try{
currentDivision= response.getQuery().getResults().getChannel().getLocation()
.getRegion();
}catch (Exception e){
ML.e("Exception during api client weather: "+e.getMessage());
return;
}
ML.d("Current DIVISION: "+currentDivision);
if(currentDivision!=null&¤tDivision.length()>=3){
ML.d("current Division is: "+currentDivision);
for(int i=0;i<divisions.length;i++){
ML.i("No#"+i+" division: "+divisions[i]);
if((currentDivision.toLowerCase().contains(divisions[i].toLowerCase()))||divisions[i].toLowerCase().contains(currentDivision.toLowerCase())){
ML.d("We got a match: "+i);
currentDivisionIndex = i;
}else{
ML.d("Current division: "+currentDivision.toLowerCase());
ML.d("INDEX DIVISION: "+divisions[i].toLowerCase());
}
}
ML.d("Current: "+currentDivisionIndex);
if(currentDivisionIndex<0||(currentDivisionIndex>=0&&messageBody.substring(currentDivisionIndex,currentDivisionIndex+1).equals("0"))){
ML.d("Returning from background" +
"DONE");
ML.d("Reached background but location mismatched");
if(currentDivisionIndex>=0){
ML.d("What is this: "+messageBody.substring(currentDivisionIndex,currentDivisionIndex+1));
}
return;
}else{
ML.d("Atleast found sth...");
}
ML.d("VALUE ACCORDING TO : "+messageBody.substring(currentDivisionIndex,currentDivisionIndex+1));
int val=0;
try {
val= Integer.parseInt(messageBody.substring(currentDivisionIndex,currentDivisionIndex+1));
} catch (Exception e) {
ML.e("Integer parsing error: "+e.getMessage());
}
if(currentDivisionIndex>=0&&val!=0){
String lang = "en";
try {
lang = isLangBangla()?"bn":"en";
} catch (Exception e) {
ML.e("GOT EXCEPTION");
lang="bn";
}
FirebaseDatabase.getInstance().getReference("versions")
.child("001")
.child("locales")
.child(lang)
.child("alert")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ML.d("Will show an alert... IF LUCKY...");
final Alert alert = dataSnapshot.getValue(Alert.class);
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("versions").child("001")
.child("LOG");
String key = ref.push().getKey();
ref.child(key).setValue(ML.getLog() + "", new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if(databaseError==null)
Log.d("Prokriti","sent");
ML.setTagServer(false);
Notify.getInstance().setHasNotification(true);
String title = getString(R.string.alert_title);
String body = getString(R.string.alert_body);
try {
if(alert!=null){
ML.d("Alert: "+alert.toString());
title = alert.getTitle();
body = alert.getBody();
}else ML.e("Alert is null");
} catch (Exception e) {
ML.e("no alert found"+e.getMessage());
}
try {
Notify.getInstance().setTitle(title);
Notify.getInstance().setDescription(body);
} catch (Exception e) {
ML.e("Notify error: "+e.getMessage());
Notify.getInstance().setTitle("Title");
Notify.getInstance().setDescription("Danger");
}
PendingIntent pendingIntent = PendingIntent.getActivity(CloudMessagingService.this, 0 /* Request code */, intent1,
PendingIntent.FLAG_UPDATE_CURRENT);
ML.d("Pack res path: "+getPackageResourcePath());
ML.d("Pack res: "+getPackageName());
Uri defaultSoundUri= Uri.parse("android.resource://"+getPackageName()+"/"+ R.raw.alert);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(CloudMessagingService.this)
.setSmallIcon(R.drawable.ic_cloud)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
});
// intent.putExtra("locale","notify");
}
#Override
public void onCancelled(DatabaseError databaseError) {
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("versions").child("001")
.child("LOG");
String key = ref.push().getKey();
ref.child(key).setValue(ML.getLog() + "", new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if(databaseError==null)
Log.d("Prokriti","sent");
ML.setTagServer(false);
}
});
}
});
}
}
}
#Override
public void onError(ANError error) {
ML.e("Error: "+error.getMessage());
}
});
}
} catch (Exception e) {
ML.e("Still shows fucking ERROR: "+e.getMessage());
}
}
public static boolean isLangBangla(){
return LocaleManager.getInstance().getLocale().getDisplayLanguage().toLowerCase().contains("bengali");
}
LocationManager locationManager=null;
String provider;
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// provider = LocationManager.NETWORK_PROVIDER;
// locationManager=(LocationManager)getBaseContext().getSystemService(Context.LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(provider);
if(location!=null){
ML.d("location(lng,lat): "+location.getLongitude()+","+location.getLatitude());
}else ML.d("location is null...");
intent.putExtra("locale","notify");
Notify.getInstance().setHasNotification(true);
Notify.getInstance().setTitle("Title");
Notify.getInstance().setDescription("ED");
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
ML.d("Pack res path: "+getPackageResourcePath());
ML.d("Pack res: "+getPackageName());
Uri defaultSoundUri= Uri.parse("android.resource://"+getPackageName()+"/"+ R.raw.alert);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_cloud)
.setContentTitle(getString(R.string.alert_title))
.setContentText(getString(R.string.alert_body))
.setAutoCancel(false)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
LocationListener locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
};
}
Related
I'm trying to use the transition API to detect user activity so I defined a pending intent and built a service for it to run but it just doesn't run.
Also, I don't know if it matters much but anyway, the service is supposed to communicate with a server I built once it detects that the device is still, but if I debug the program with breakpoints it just looks like it doesn't even enter the service.
It only started the service when I wrote the line pendingIntent.send() but it just wouldn't help me anyway since the intent didn't receive any data anyway.
The onCreate method in which the intent is also defined:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_running);
// Go fullscreen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mContext = this;
activityRecognitionClient = ActivityRecognition.getClient(mContext);
Intent intent = new Intent(this, TransitionIntentService.class);
pendingIntent = PendingIntent.getService(this, 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
configureSettingsButton();
}
The activity detection build:
public void registerHandler(final View view) {
transitions = new ArrayList<>();
transitions.add(new ActivityTransition.Builder()
.setActivityType(DetectedActivity.STILL)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
.build());
transitions.add(new ActivityTransition.Builder()
.setActivityType(DetectedActivity.STILL)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
.build());
transitions.add(new ActivityTransition.Builder()
.setActivityType(DetectedActivity.IN_VEHICLE)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
.build());
transitions.add(new ActivityTransition.Builder()
.setActivityType(DetectedActivity.IN_VEHICLE)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
.build());
transitions.add(new ActivityTransition.Builder()
.setActivityType(DetectedActivity.WALKING)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
.build());
transitions.add(new ActivityTransition.Builder()
.setActivityType(DetectedActivity.WALKING)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
.build());
transitions.add(new ActivityTransition.Builder()
.setActivityType(DetectedActivity.RUNNING)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
.build());
transitions.add(new ActivityTransition.Builder()
.setActivityType(DetectedActivity.RUNNING)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
.build());
ActivityTransitionRequest activityTransitionRequest = new ActivityTransitionRequest(transitions);
Task<Void> task = activityRecognitionClient.requestActivityTransitionUpdates(activityTransitionRequest, pendingIntent);
task.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
textView = findViewById(R.id.textView4);
scan = findViewById(R.id.startSearching);
textView.setVisibility(View.VISIBLE);
scan.setVisibility(View.INVISIBLE);
Toast.makeText(mContext, "Started scanning", Toast.LENGTH_LONG).show();
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(mContext, "Failed to build transition object", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
});
}
The service itself:
public class TransitionIntentService extends IntentService {
String answer;
//boolean gotMatch = false;
boolean stopScanning = false;
public void onCreate() {
super.onCreate();
Log.d("TransitionIntentService", ">>>onCreate()");
}
public TransitionIntentService() {
super("TransitionIntentService");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, startId, startId);
Log.i("LocalService", "Received start id " + startId + ": " + intent);
return START_STICKY;
}
#Override
protected void onHandleIntent(Intent intent) {
if (null != intent) {
if (ActivityTransitionResult.hasResult(intent)) {
ActivityTransitionResult result = ActivityTransitionResult.extractResult(intent);
for (ActivityTransitionEvent event : result.getTransitionEvents()) {
if(event.getActivityType() == 3) //user is still
{
if(event.getTransitionType() == 0) //the user has entered a still state
{
SendDriving sendDriving = new SendDriving();
sendDriving.start();
while (sendDriving.isAlive()){}
GetMatch getMatch = new GetMatch();
getMatch.start();
}
else if (event.getTransitionType() == 1) //the user has left the still state
{
stopScanning = true;
SendDrivingEnd sendDrivingEnd = new SendDrivingEnd();
sendDrivingEnd.start();
}
}
}
}
}
}
Thanks in advance!
Edit: my manifest file:
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".profile" />
<activity android:name=".settingInterests" />
<activity android:name=".languages" />
<activity android:name=".settings" />
<activity android:name=".Login" />
<service android:name=".TransitionIntentService"></service>
<activity android:name=".running" />
<activity android:name=".SignupPage2" />
<activity android:name=".SignupPage1" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Receiver works on all android versions from 4.2 upto 8.0. Even if app is removed from Recent Apps But if removed from Recent Apps in Android Oreo, it then never triggers receiver again.
my manifest.xml :
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".WatchMan"
android:enabled="true"
android:exported="true" />
<receiver
android:name=".Receiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
My receiver.java :
public class Receiver extends BroadcastReceiver
{
public String PhoneNumber = "UNKNOWN";
#Override
public void onReceive(Context context, Intent intent)
{
Log.d("RECEIVER :","CAPTURED THE EVENT.....");
try
{
PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, WatchMan.class));
}
else
{
context.startService(new Intent(context, WatchMan.class));
}
}
catch (Exception e)
{
e.printStackTrace();
Log.e("RECEIVER EXCEPTION : ", "Exception is : ", e);
}
}
I want to know if i am doing any mistake in code? Android Developers Documentation asking to register receiver runtime using context. Then i searched for registering it in runtime on stackoverflow but looks no proper thread accepted as answer. How can make receiver to to be ready again, even if removed from recents of Android Oreo?
Thanking you in advance.
I have deleted unrelated posts. I am posting final answer as it may help others. #WIZARD help was thankful.
PHONE_STATE is implicit and will not be triggered on android Oreo or higher. So just place permissions in manifest like :
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".WatchMan"
android:enabled="true"
android:exported="true">
</service>
<service
android:name=".CatchNumbers"
android:enabled="true"
android:exported="true">
</service>
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
Register implicit receivers from foreground service :
public class WatchMan extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "17";
private boolean running;
private BroadcastReceiver mCallBroadcastReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
String PhoneNumber = "UNKNOWN";
Log.d("RECEIVER : ","HERE HERE");
try
{
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(state == null)
{
PhoneNumber = "UNKNOWN";
}
else if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
{
PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d("INCOMING ","Incoming number : "+PhoneNumber);
}
if(intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
{
PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d("OUTGOING ","Outgoing number : "+PhoneNumber);
}
if(!PhoneNumber.contentEquals("UNKNOWN"))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, CatchNumbers.class));
}
else
{
context.startService(new Intent(context, CatchNumbers.class));
}
}
}
catch (Exception e)
{
e.printStackTrace();
Log.e("RECEIVER EXCEPTION : ", "Exception is : ", e);
}
}
};
public WatchMan() { }
#Override
public void onCreate()
{
super.onCreate();
mBuilder = new NotificationCompat.Builder(this, null);
IntentFilter filterstate = new IntentFilter();
filterstate.addAction("android.intent.action.NEW_OUTGOING_CALL");
filterstate.addAction("android.intent.action.PHONE_STATE");
this.registerReceiver(mCallBroadcastReceiver, filterstate);
Log.d("RECEIVER : ", "\nCreated....");
mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, null);
mBuilder.setContentTitle("Insta Promo")
.setContentText("Insta Promo Is Up..")
.setTicker("Insta Promo Is Up..")
.setSmallIcon(R.drawable.ic_launcher_background)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_ALL)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setOngoing(true)
.setAutoCancel(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotifyManager.createNotificationChannel(notificationChannel);
}
running = true;
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(17, mBuilder.build());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("RECEIVER : ", "\nOnStartCommand....");
new Thread(new Runnable()
{
public void run()
{
while(running)
{
try
{
Log.d("RECEIVER : ", "\nALIVE..");
Thread.sleep(10000);
}
catch (InterruptedException e)
{
Log.d("RECEIVER : ", "\nThread : InterruptedException in Receiver...");
Log.e("RECEIVER : ", "\nException is : ", e);
}
catch (Exception e)
{
Log.d("RECEIVER : ", "\nThread : Exception Error in Receiver...");
Log.e("RECEIVER : ", "\nException is : ", e);
}
}
}
}).start();
return START_STICKY;
}
#Override
public void onDestroy()
{
this.unregisterReceiver(mCallBroadcastReceiver);
running = true;
Log.d("RECEIVER : ", "\nDestroyed....");
Log.d("RECEIVER : ", "\nWill be created again....");
}
#Override
public IBinder onBind(Intent intent)
{
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onTaskRemoved(Intent rootIntent)
{
super.onTaskRemoved(rootIntent);
Log.d("SERVICE : ", "\nTask Removed....");
}
}
There are some intent actions like NEW_OUTGOING_CALL AND BOOT_COMPLETED which are excluded and can be implemented in receiver and placed in manifest like :
public class MyReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.d("INSTA_BOOT : ", "\nBOOT_COMPLETE_EVENT_OF_INSTA....");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, WatchMan.class));
}
else
{
context.startService(new Intent(context, WatchMan.class));
}
}
}
As i wanted to re-register or say want to restart foreground service on REBOOT OR BOOT-COMPLETE
CatchNumbers.java is a simple service which performs operation when receiver triggers perticular actions.
It works good on every restart and as android:excludeFromRecents="true" is not needed anymore as even if user removes it from recents on Oreo it will restart the service as it is STICKY. Hope it helps someone like me..!!
Based on the documentation for restrictions on implicit broadcast in Android 8, you cannot use implicit receivers in your manifest (although there are some exceptions, but phone state receiver is not among those exceptions)
You have to use foreground service and register your receiver in your foreground service instead of manifest
remove phone state receiver from manifest
register receiver in onCreate of Service:
#Override
public void onCreate() {
super.onCreate();
phoneStateReceiver = new PhoneStateReceiver();
registerReceiver(phoneStateReceiver, new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED));
}
unregister in onDestroy:
#Override
public void onDestroy() {
unregisterReceiver(phoneStateReceiver);
super.onDestroy();
}
add a static method to your service to start service:
// start service even if your app is in stopped condition in android 8+
static void requestStart(#NonNull final Context context, #NonNull final String action){
final Context appContext = context.getApplicationContext();
Intent intent = new Intent(appContext, AppService.class);
intent.setAction(action);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// this is required to start the service if there is
// no foreground process in your app and your app is
// stopped in android 8 or above
appContext.startForegroundService(intent);
} else {
appContext.startService(intent);
}
}
start foreground in your onStartCommand
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(ACTION_START.equals(intent.getAction()))
startForeground(ID, notification);
else if(ACTION_STOP.equals(intent.getAction()))
stopForeground(true);
return START_STICKY;
}
I have a service that listens for an event posted by a Particle Photon (microcontroller) and then gives a notification to the user. The event listener is registered when the Service is started in the onStartCommand function in a separate thread (Because the action requires that it not be started in the main thread) Everything works fine even when the app isn't running but after about 5 minutes it just stops. The service from what I can tell is never destroyed (I have it display something if it gets destroyed and it never has) so my gut feeling is the event listener stops working. Any help would be appreciated! The code is below!
Note: Event listener does use an internet connection if that is of any consequence
Service Code below:
public class NotificationService extends Service implements ParticleEventHandler{
//private long weightChangeSubscriptionID;
private long lockedChangeSubscriptionID;
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
final String deviceID;
final SharedPreferences sharedPreferences = this.getSharedPreferences("justintime.com.productscale", Context.MODE_PRIVATE);
deviceID = sharedPreferences.getString("deviceID"," ");
ParticleCloudSDK.init(this);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
if(!deviceID.equals(" ")) {
//weightChangeSubscriptionID = ParticleCloudSDK.getCloud().subscribeToDeviceEvents("weightChange", deviceID, NotificationService.this);
lockedChangeSubscriptionID = -1;
lockedChangeSubscriptionID = ParticleCloudSDK.getCloud().subscribeToDeviceEvents("lockWtChange", deviceID, NotificationService.this);
if(lockedChangeSubscriptionID != -1){
sharedPreferences.edit().putBoolean("serviceRunning", true).apply();
}
}
else
Log.w("Error", "Not started! Possible no deviceID available");
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
return START_STICKY;
}
#Override
public void onDestroy() {
final SharedPreferences sharedPreferences = this.getSharedPreferences("justintime.com.productscale", Context.MODE_PRIVATE);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//try {
//ParticleCloudSDK.getCloud().unsubscribeFromEventWithID(weightChangeSubscriptionID);
//ParticleCloudSDK.getCloud().unsubscribeFromEventWithID(lockedChangeSubscriptionID);
sharedPreferences.edit().putBoolean("serviceRunning", false).apply();
Log.w("Subsction", "unsibscribed from lockedWeightchange");
//} catch (ParticleCloudException e) {
// e.printStackTrace();
//}
}
});
t.start();
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onEventError(Exception e) {
Log.wtf("error", "error on event");
}
#Override
public void onEvent(String eventName, ParticleEvent particleEvent) {
//if(eventName.equals("weightChange")) {
// DisplayActivity.updateScaleReading();
//}
if(eventName.equals("lockWtChange")) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.scale)
.setContentTitle("Scale change!")
.setContentText("Scales Value Has Changed While Locked!!")
.setPriority(Notification.PRIORITY_HIGH)
.setVibrate(new long[]{500, 1000, 500})
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setCategory(Notification.CATEGORY_EVENT)
.setAutoCancel(true)
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
.setColor(Color.GREEN);
Intent resultIntent = new Intent(this, MainScreen.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainScreen.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1234, mBuilder.build());
}
}
}
I am running the service from the main activity by checking if it is already running or not and then running it using the following code: (It is also run on boot using a boot reciever class)
#Override
protected void onResume() {
super.onResume();
updateScaleReading();
updateLockValue();
subscribeToEvents();
if (!isMyServiceRunning()){
Intent serviceIntent = new Intent(getApplicationContext(), justintime.com.productscale.NotificationService.class);
getApplicationContext().startService(serviceIntent);
}else{
Log.w("Service", "Service is already running!");
}
}
isMyServiceRunning() function:
private boolean isMyServiceRunning() {
SharedPreferences sharedPreferences = this.getSharedPreferences("justintime.com.productscale", Context.MODE_PRIVATE);
//return sharedPreferences.getBoolean("serviceRunning", false);
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (NotificationService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
Manifest File:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/scale_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/scale_launcher"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainScreen"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DisplayActivity"
android:screenOrientation="portrait" />
<activity android:name=".SelectionActivity"
android:screenOrientation="portrait"/>
<service android:enabled="true" android:exported="false" android:name=".NotificationService">
<intent-filter>
<action android:name="justintime.com.productscale.NotificationService" />
</intent-filter>
</service>
<receiver
android:name=".BootReceiver"
android:enabled="true"
android:exported="true"
android:label="BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
Here is my full code, in this. If the app is running, then i'll get push notification that too for public void handleResponse method. But if i quit the app, i wont get push notification itself, please help.
Mainactivity.java
public class MainActivity extends AppCompatActivity {
private static final String YOUR_APP_ID = "2C25D658-240D-4350-FF8A-6CF4DBD88F00";
private static final String YOUR_SECRET_KEY = "24DB6F44-8C97-1DCF-FF22-060777780600";
String appVersion = "v1";
Subscription subscription;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Backendless.initApp(this, YOUR_APP_ID, YOUR_SECRET_KEY, "v1");
Backendless.Messaging.registerDevice("183254839430", "default", new AsyncCallback<Void>() {
#Override
public void handleResponse(Void aVoid) {
Toast.makeText(MainActivity.this, "Registered", Toast.LENGTH_LONG).show();
}
#Override
public void handleFault(BackendlessFault backendlessFault) {
Toast.makeText(MainActivity.this, backendlessFault.getMessage(), Toast.LENGTH_LONG).show();
}
});
Backendless.Messaging.subscribe( "default",
new AsyncCallback<List<Message>>() {
#Override
public void handleResponse(List<Message> response) {
Toast.makeText(MainActivity.this, "Notification arrived successfully", Toast.LENGTH_LONG).show();
for (Message message : response) {
String publisherId = message.getPublisherId();
Object data = message.getData();
}
}
#Override
public void handleFault(BackendlessFault fault) {
Toast.makeText(MainActivity.this, fault.getMessage(), Toast.LENGTH_SHORT).show();
}
},
new AsyncCallback<Subscription>()
{
#Override
public void handleResponse( Subscription response )
{
subscription = response;
}
#Override
public void handleFault( BackendlessFault fault )
{
Toast.makeText( MainActivity.this, fault.getMessage(), Toast.LENGTH_SHORT ).show();
}
}
);
}
}
pushreceiver.java.
This code itself is not triggering, i'm confused why :-(
public class PushReceiver extends GcmListenerService {
//This method will be called on every new message received
#Override
public void onMessageReceived(String from, Bundle data) {
Toast.makeText(getApplicationContext(), "Notification came PushReceiver", Toast.LENGTH_LONG).show();
//Getting the message from the bundle
String message = data.getString("message");
//Displaying a notiffication with the message
sendNotification(message);
}
//This method is generating a notification and displaying the notification
private void sendNotification(String message) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
int requestCode = 0;
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, intent, PendingIntent.FLAG_ONE_SHOT);
Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder noBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText(message)
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, noBuilder.build()); //0 = ID of notification
}
}
My Manifest file.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="feelzdroid.backednlessgcm">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="feelzdroid.backednlessgcm.permission.C2D_MESSAGE"/>
<permission android:name="feelzdroid.backednlessgcm.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="feelzdroid.backednlessgcm"/>
</intent-filter>
</receiver>
<service android:name=".PushReceiver" android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
</intent-filter>
</service>
</application>
Log.
07-03 16:43:31.893 11026-11143/feelzdroid.backednlessgcm I/GMPM: App measurement is starting up
07-03 16:43:31.915 11026-11143/feelzdroid.backednlessgcm E/GMPM: getGoogleAppId failed with status: 10
07-03 16:43:31.918 11026-11143/feelzdroid.backednlessgcm E/GMPM: Uploading is not possible. App measurement disabled
I was working a little with push notifications, which I managed to put working so far and with the Firebase Cloud Messaging Api, now I was trying to save the Token in the database, was following a tutorial and the token doesn't seem to register.
MainActivity.java
http://prntscr.com/bgadg6
MyFirebaseInstanceIDService.java
http://prntscr.com/bgadxd
MyFirebaseMessagingService extends Firebase Messaging Service{
private static final String TAG = "MyFirebaseMsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
//Displaying data in log
//It is optional
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
//Calling method to generate notification
sendNotification(remoteMessage.getNotification().getBody());
}
//This method is only generating push notification
//It is same as we did in earlier posts
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, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Firebase Push Notification")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Adding Internet Permission -->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--
Defining Services
-->
<service
android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
</application>
Try this, with volley library & asyntask:
//Creating a string request
StringRequest req = new StringRequest(Request.Method.POST, Constants.REGISTER_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//dismissing the progress dialog
progressDialog.dismiss();
//if the server returned the string success
if (response.trim().equalsIgnoreCase("success")) {
//Displaying a success toast
Toast.makeText(MainActivity.this, "Registered successfully", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Choose a different email", Toast.LENGTH_SHORT).show();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
//adding parameters to post request as we need to send firebase id and email
params.put("firebaseid", uniqueId);
params.put("email", email);
return params;
}
and register.php
<?php
if($_SERVER['REQUEST_METHOD']=='POST'){
//getting the request values
$firebaseid = $_POST['firebaseid'];
$email = $_POST['email'];
//connecting to database
$con = mysqli_connect('localhost','root','','pushnotification');
//creating an sql query
$sql = "INSERT INTO register (firebaseid, email) VALUES ('$firebaseid','$email')";
//executing the query to the database
if(mysqli_query($con,$sql)){
echo 'success';
}else{
echo 'failure';
}
}