I try to implement a simple notification for new event happen on my app but when i try to open my app from a notification clicked app crash.
It's said this error
Process: it.breakingbad.crimegoaway, PID: 13239
java.lang.RuntimeException: Unable to start activity ComponentInfo{it.breakingbad.crimegoaway/it.breakingbad.crimegoaway.NavBarActivity}: android.view.InflateException: Binary XML file line #15 in it.breakingbad.crimegoaway:layout/activity_nav_bar: Binary XML file line #19 in it.breakingbad.crimegoaway:layout/content_nav_bar: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3520)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3692)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5580)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5486)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
i think the error is in my navbarActivity in the onCreate on this line ActivityNavBarBinding.inflate(getLayoutInflater());
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
try {
binding = ActivityNavBarBinding.inflate(getLayoutInflater());
// ... rest of body of onCreateView() ...
} catch (Exception e) {
Log.e("TAG", "onCreateView", e);
}
setContentView(binding.getRoot());
setSupportActionBar(binding.appBarNavBar.toolbar);
DrawerLayout drawer = binding.drawerLayout;
NavigationView navigationView = binding.navView;
View headerView = navigationView.getHeaderView(0);
// Get Username and Email TextViews
TextView userName = headerView.findViewById(R.id.nav_username);
TextView userEmail = headerView.findViewById(R.id.nav_email);
// set user name and email
userName.setText("Username");
Users.writeUsernameNavBar(userName);
userEmail.setText(Users.getCurrentUser().getCurrentUser().getEmail());
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_add_alert, R.id.nav_profile, R.id.nav_view_alerts, R.id.nav_my_alerts, R.id.nav_exit)
.setOpenableLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_nav_bar);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
//work manager declaration if not present
if(getIntent().getExtras() == null) {
WorkManager.getInstance(getApplicationContext()).cancelAllWorkByTag(TAG_ALERTS);
WorkRequest workAlertRequest = new PeriodicWorkRequest.Builder(AlertCheckerWorker.class, 4, TimeUnit.MINUTES)
/*.setInitialDelay(3, TimeUnit.MINUTES)*/
.addTag(TAG_ALERTS).build();
WorkManager.getInstance(getApplicationContext()).enqueue(workAlertRequest);
WorkManager.getInstance(getApplicationContext()).cancelAllWorkByTag(TAG_COMMENTS);
WorkRequest workCommentRequest = new PeriodicWorkRequest.Builder(CommentCheckerWorker.class, 4, TimeUnit.MINUTES)
/*.setInitialDelay(3, TimeUnit.MINUTES)*/
.addTag(TAG_COMMENTS).build();
WorkManager.getInstance(getApplicationContext()).enqueue(workCommentRequest);
}
//used for notification "re-routing"
if(getIntent().getExtras() != null){
Bundle bundle = getIntent().getExtras();
if(bundle.getParcelable("alert") != null) {
Alert alert = bundle.getParcelable("alert");
DetailAlertFragment fragment_alert = new DetailAlertFragment();
fragment_alert.setArguments(bundle);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.nav_host_fragment_content_nav_bar, fragment_alert);
transaction.commit();
}
}
}
the notification are cath from here
Intent resultIntent = new Intent(getApplicationContext(), NavBarActivity.class);
Bundle bundle = new Bundle();
bundle.putParcelable("alert", tempAlert);
resultIntent.putExtras(bundle);
//resultIntent.putExtra("alert", tempAlert);
Log.d("AlertCheckerWorker", "doWork: " + tempAlert.toString());
// Create the TaskStackBuilder and add the intent, which inflates the back stack
TaskStackBuilder stackBuilder = TaskStackBuilder.create(getApplicationContext());
stackBuilder.addNextIntentWithParentStack(resultIntent);
// Get the PendingIntent containing the entire back stack
int notificationId = (int) (System.currentTimeMillis() + new Random().nextInt());
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(notificationId,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);
Notification notification = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
.setSmallIcon(R.drawable.category_crime)
.setContentTitle("Alert Title: " + tempAlert.getTitle())
.setContentText("Description: " + tempAlert.getDescription())
.setContentIntent(resultPendingIntent)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build();
notificationManager.notify(notificationId, notification);
passed to navbaractivity and after passed to the detailalertfragment
alert = getArguments().getParcelable("alert");
//GraphicTools.showToast(getContext(),alert.toString());
alertTitleTextView.setText(alert.getTitle());
alertAddCommentImageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(alertAddCommentEditText.getText().toString().length()>0){
Comment comment=new Comment(alertAddCommentEditText.getText().toString(), Timestamp.now(), FirebaseAuth.getInstance().getCurrentUser().getUid());
Comments.addCommentInFirestore(alert.getDocumentId(),comment);
alertAddCommentEditText.setText("");
}else {
alertAddCommentEditText.setError("Add a comment");
}
}
});
alertDescriptionTextView.setText(alert.getDescription());
here i put a simple schema to understand how work my application
Related
I am using onesignal and firebase to push notifications from wordpress blog to Android app and when I click on notification that just arrived, application will open only if it run in the background. If it is completely closed, clicking on notification will do nothing. How do I achieve clicking on notification opens app even if app is not in the background opened?
Below is the code that handles notifications:
class nyonNotificationOpenedHandler implements OneSignal.NotificationOpenedHandler {
// This fires when a notification is opened by tapping on it.
#Override
public void notificationOpened(OSNotificationOpenResult result) {
OSNotificationAction.ActionType actionType = result.action.type;
JSONObject data = result.notification.payload.additionalData;
String customKey;
if (data != null) {
customKey = data.optString("customkey", null);
if (customKey != null)
Log.i("OneSignalnyon", "customkey set with value: " + customKey);
}
if (actionType == OSNotificationAction.ActionType.ActionTaken)
Log.i("OneSignalnyon", "Button pressed with id: " + result.action.actionID);
// The following can be used to open an Activity of your choice.
// Replace - getApplicationContext() - with any Android Context.
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
The code which I am using for opening app on the click of notification, which is working perfectly fine :
Intent resultIntent = new Intent(getApplicationContext(), YourActivity.class);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
//if you want to send some data
resultIntent.putExtra(AppConstants.NOTIFICATION, data);
Now you have to create PendingIntent
PendingIntent: As per docs by creating pending intent means you are granting it the right to perform the operation you have specified as if the other application was yourself. https://developer.android.com/reference/android/app/PendingIntent
PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT
);
Now when you are creating your Notification set this pending intent setContentIntent(resultPendingIntent) to that notification.
Notification notification;
notification = mBuilder.setSmallIcon(icon).setTicker(title).setWhen(0)
.setAutoCancel(true)
.setContentTitle(title)
.setContentIntent(resultPendingIntent)
.setStyle(inboxStyle)
.setWhen(getTimeMilliSec(System.currentTimeMillis() + ""))
.setSmallIcon(R.drawable.ic_app_icon)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), icon))
.setContentText(message)
.setChannelId(CHANNEL_ID)
.build();
Well to solve this problem, first thing is to read documentation more clearly (what I didn't do) so here it is:
By default OneSignal will open or resume your launcher Activity when a notification is tapped on. You can disable this behavior by adding the meta-data tag com.onesignal.NotificationOpened.DEFAULT set to DISABLE inside your application tag in your AndroidManifest.xml.
Make sure that you register it inside android manifest, e.g.:
<application ...>
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT" android:value="DISABLE" />
</application>
Create handler for opened notifications, e.g.:
public class MyNotificationOpenedHandler implements OneSignal.NotificationOpenedHandler {
private final Context context;
public MyNotificationOpenedHandler(Context context) {
this.context = context;
}
#Override
public void notificationOpened(OSNotificationOpenResult result) {
if (result.action.type == OSNotificationAction.ActionType.Opened) {
JSONObject data = result.notification.payload.additionalData;
if (data == null) {
return;
}
String category = data.optString("category", null);
if (category == null) {
return;
}
if (category.equals("global")) {
Intent intent = new Intent(context, NotificationDetailsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
}
}
Next point is:
Make sure you are initializing OneSignal with setNotificationOpenedHandler in the onCreate method in your Application class. You will need to call startActivity from this callback.
You'll need to extend Application class, e.g.:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
OneSignal.startInit(this)
.inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
.setNotificationOpenedHandler(new MyNotificationOpenedHandler(getApplicationContext()))
.unsubscribeWhenNotificationsAreDisabled(true)
.init();
}
}
Set application name inside android manifest, e.g.:
<application
android:name=".MyApplication"
android:icon="#mipmap/ic_launcher"
android:roundIcon="#mipmap/ic_launcher_round"
android:theme="#style/AppTheme">
And you're ready to handle notifications when app is closed.
Set "setNotificationOpenedHandler"
OneSignal.startInit(this)
.inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
.setNotificationOpenedHandler(new NotificationOpenedHandler())
.init();
Add this class to your launcher activity ( make sure notification have "additionalData" )
public class NotificationOpenedHandler implements OneSignal.NotificationOpenedHandler {
// This fires when a notification is opened by tapping on it.
#Override
public void notificationOpened(OSNotificationOpenResult result) {
//OSNotificationAction.ActionType actionType = result.action.type;
JSONObject data = result.notification.payload.additionalData;
String customKey;
if (data != null) {
customKey = data.optString("Data", null);
if (customKey != null)
{
Log.d("LOGGED", "notificationOpened: " + customKey);
if(customKey.equals("Notification"))
{
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
else
{
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
//Toast.makeText(MainActivity.this, "Value is : " + customKey, Toast.LENGTH_SHORT).show();
}
}
More Info
https://documentation.onesignal.com/docs/android-native-sdk#section--notificationopenedhandler-
Add the following to your AndroidManifest.xml to prevent the launching of your main Activity
<application ...>
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT" android:value="DISABLE" />
</application>
I'm getting notification from fcm when app is in foreground or background.
I don't want to show the notification When app in a specific activity how to disable notification when app is in specific activity.
I'm using datapaylod to for notification
You can check current top activity by:
public static Activity getActivity() {
Class activityThreadClass = Class.forName("android.app.ActivityThread");
Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
activitiesField.setAccessible(true);
Map<Object, Object> activities = (Map<Object, Object>) activitiesField.get(activityThread);
if (activities == null)
return null;
for (Object activityRecord : activities.values()) {
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord)) {
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
Activity activity = (Activity) activityField.get(activityRecord);
return activity;
}
}
return null;
}
you can check if top activity is the activity in which you don't want to show notification and then return the call from service.
Try this,
private void sendNotification(String msg) {
Intent notificationIntent = null;
notificationIntent = new Intent(currentactivity.this, Main2Activity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(GCMNotificationIntentService.this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationManager nm = (NotificationManager) GCMNotificationIntentService.this.getSystemService(Context.NOTIFICATION_SERVICE);
Resources res = GCMNotificationIntentService.this.getResources();
NotificationCompat.Builder builder = new NotificationCompat.Builder(GCMNotificationIntentService.this);
builder.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.app_logo_small_trans)
.setColor(getResources().getColor(R.color.app_logo_color))
.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.app_logo))
.setTicker(msg)
.setWhen(System.currentTimeMillis())
.setAutoCancel(true)
.setContentTitle("Propreka")
.setLights(0xffff0000, 100, 2000)
.setPriority(Notification.DEFAULT_SOUND)
.setContentText(msg);
Notification n = builder.getNotification();
n.defaults |= Notification.DEFAULT_ALL;
nm.notify(0, n);
}
So you want to know which (if any) activity is in foreground at the moment. And depending on the class type, want to limit the showing of notifications.
You need to maintain this yourself. Easiest way is to write a new class and have public static functions in it to mark activity as active / inactive
public static Activity mCurrentActivity = null;
public static void SetActivity(Activtiy activity) { mCurrentActivity = activity };
public static void ClearActivity(Activtiy activity)
{
if (mCurrentActivity.equals(activity))
mCurrentActivity = null;
}
public static Activity GetCurrentActivity() { return mCurrentActivity; }
Once you have such an infra, you can call the SetActivity and ClearActivity functions in all of your onResume and onPause overrides respectively.
Finally, in your notification builder class, you will get the instance of current activity and compare the .class to check if your desired activity is the one in focus. If the Current activity returns null, it means your app is not in foreground.
There are better, more efficient and cleaner way to do this. E.g. Dependency Injection with Daggr.
I have followed tutorial in http://developer.android.com/training/notify-user/index.html
It works well. But what I want is : when I click ping, the old service will we stopped, and then create the service again. So if I clicked id multiple time, It will notify me only once.
Problem: If I set time 10, then I click "Ping" button. Then after 5 second, I click it again. It will notify me twice.
What I want : If I set time 10, then I click "Ping" button. Then after 5 second, I click it it will notify only once, 10 secondds after the last time I click the button.
public class MainActivity extends Activity {
private Intent mServiceIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Creates an explicit Intent to start the service that constructs and
// issues the notification.
mServiceIntent = new Intent(getApplicationContext(), PingService.class);
}
/*
* Gets the values the user entered and adds them to the intent that will be
* used to launch the IntentService that runs the timer and issues the
* notification.
*/
public void onPingClick(View v) {
stopCurrentService();
int seconds;
// Gets the reminder text the user entered.
EditText msgText = (EditText) findViewById(R.id.edit_reminder);
String message = msgText.getText().toString();
mServiceIntent.putExtra(CommonConstants.EXTRA_MESSAGE, message);
mServiceIntent.setAction(CommonConstants.ACTION_PING);
Toast.makeText(this, R.string.timer_start, Toast.LENGTH_SHORT).show();
// The number of seconds the timer should run.
EditText editText = (EditText) findViewById(R.id.edit_seconds);
String input = editText.getText().toString();
if (input == null || input.trim().equals("")) {
// If user didn't enter a value, sets to default.
seconds = R.string.seconds_default;
} else {
seconds = Integer.parseInt(input);
}
int milliseconds = (seconds * 1000);
mServiceIntent.putExtra(CommonConstants.EXTRA_TIMER, milliseconds);
// Launches IntentService "PingService" to set timer.
startService(mServiceIntent);
}
private void stopCurrentService() {
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> serviceList = activityManager
.getRunningServices(Integer.MAX_VALUE);
if (serviceList.size() <= 0) { }
int size = serviceList.size();
for (int i = 0; i < size; i++) {
RunningServiceInfo serviceInfo = serviceList.get(i);
ComponentName serviceName = serviceInfo.service;
if (serviceName.getClassName().equals(PingService.class.getName())) {
try {
Intent intentstop = new Intent();
intentstop.setComponent(serviceName);
getApplicationContext().stopService(intentstop);
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
}
}
PingService creates a notification that includes 2 buttons: one to snooze the
notification, and one to dismiss it.
public class PingService extends IntentService {
private NotificationManager mNotificationManager;
private String mMessage;
private int mMillis;
NotificationCompat.Builder builder;
private boolean status;
public PingService() {
// The super call is required. The background thread that IntentService
// starts is labeled with the string argument you pass.
super("com.example.android.pingme");
}
#Override
protected void onHandleIntent(Intent intent) {
// The reminder message the user set.
mMessage = intent.getStringExtra(CommonConstants.EXTRA_MESSAGE);
// The timer duration the user set. The default is 10 seconds.
mMillis = intent.getIntExtra(CommonConstants.EXTRA_TIMER,
CommonConstants.DEFAULT_TIMER_DURATION);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
String action = intent.getAction();
// This section handles the 3 possible actions:
// ping, snooze, and dismiss.
if (action.equals(CommonConstants.ACTION_PING)) {
issueNotification(intent, mMessage);
} else if (action.equals(CommonConstants.ACTION_SNOOZE)) {
nm.cancel(CommonConstants.NOTIFICATION_ID);
Log.d(CommonConstants.DEBUG_TAG, getString(R.string.snoozing));
// Sets a snooze-specific "done snoozing" message.
issueNotification(intent, getString(R.string.done_snoozing));
} else if (action.equals(CommonConstants.ACTION_DISMISS)) {
nm.cancel(CommonConstants.NOTIFICATION_ID);
}
}
private void issueNotification(Intent intent, String msg) {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Sets up the Snooze and Dismiss action buttons that will appear in the
// expanded view of the notification.
Intent dismissIntent = new Intent(this, PingService.class);
dismissIntent.setAction(CommonConstants.ACTION_DISMISS);
PendingIntent piDismiss = PendingIntent.getService(this, 0,
dismissIntent, 0);
Intent snoozeIntent = new Intent(this, PingService.class);
snoozeIntent.setAction(CommonConstants.ACTION_SNOOZE);
PendingIntent piSnooze = PendingIntent.getService(this, 0,
snoozeIntent, 0);
// Constructs the Builder object.
builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_stat_notification)
.setTicker("Ping ! ping ! PIng!")
.setContentTitle(getString(R.string.notification))
.setContentText(getString(R.string.ping))
.setDefaults(Notification.DEFAULT_ALL)
// requires VIBRATE permission
/*
* Sets the big view "big text" style and supplies the text (the
* user's reminder message) that will be displayed in the detail
* area of the expanded notification. These calls are ignored by
* the support library for pre-4.1 devices.
*/
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.addAction(R.drawable.ic_stat_dismiss,
getString(R.string.dismiss), piDismiss)
.addAction(R.drawable.ic_stat_snooze,
getString(R.string.snooze), piSnooze);
/*
* Clicking the notification itself displays ResultActivity, which
* provides UI for snoozing or dismissing the notification. This is
* available through either the normal view or big view.
*/
Intent resultIntent = new Intent(this, ResultActivity.class);
resultIntent.putExtra(CommonConstants.EXTRA_MESSAGE, msg);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
// Because clicking the notification opens a new ("special") activity,
// there's
// no need to create an artificial back stack.
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,
resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
startTimer(mMillis);
}
// Starts the timer according to the number of seconds the user specified.
private void startTimer(int millis) {
Log.d(CommonConstants.DEBUG_TAG, getString(R.string.timer_start));
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Log.d(CommonConstants.DEBUG_TAG, getString(R.string.sleep_error));
}
Log.d(CommonConstants.DEBUG_TAG, getString(R.string.timer_finished));
issueNotification(builder);
}
private void issueNotification(NotificationCompat.Builder builder) {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Including the notification ID allows you to update the notification
// later on.
mNotificationManager.notify(CommonConstants.NOTIFICATION_ID,
builder.build());
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
I have called stopService(), but the old notification shows up again.
What I want is it will notify me once, 10 seconds after the latest click.
You can use handler in order to stop/start your service.
Please look at my code. It's not exactly related to your code but you can get the idea.
Click this link
You can do checking in Run method of Runnable.
I'm coding an android app for my school, and i have a little problem with notifications:
My app checks if the homepage was updated (date of page is newer than date of last view) in background. If the page was updated, the app builds a notifications (till here it works fine) with 2 options: Dismiss or show (also works). "Show" works fine, but my problem is "Dismiss" because it has to update the date in settings and it should quit then, but it's always showing the last opened activity.
I'm having an Activity which manages this with Intent extras:
public class ***********Handler extends Activity {
String EXTRA_ACTION = "de.xorg.*****.ACTION";
String EXTRA_VPDATE = "de.xorg.*****.VPDATE";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ntd);
Intent intent = getIntent();
String todo = intent.getStringExtra(EXTRA_ACTION); //Action from Notification ("D" or "S")
String date = intent.getStringExtra(EXTRA_VPDATE); //New date
if(todo.toLowerCase().contains("d")) {
//update date value
Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
editor.putString("readDate", date);
editor.commit();
// Remove notification
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(0);
// Quit app (1st method) [I'm only using one in real code, but both aren't working]
android.os.Process.killProcess(android.os.Process.myPid());
// Quit app (2nd method)
finish();
} else {
//update date value
Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
editor.putString("readDate", date);
editor.commit();
// Remove notification
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(0);
//Set theme (not important now)
Boolean BeanUI = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("bean", false);
String URL;
if(BeanUI) {
URL = "*****" + PreferenceManager.getDefaultSharedPreferences(this).getString("klasse", "") + "&fc=ffffff&bc=000000";
} else {
URL = "*****" + PreferenceManager.getDefaultSharedPreferences(this).getString("klasse", "");
}
String EXTRA_URL = "de.xorg.*****.MESSAGE";
String EXTRA_NAME = "de.xorg.*****.MESSAGENAME";
Intent intent2 = new Intent(this, InternetViewer.class);
intent2.putExtra(EXTRA_URL, URL);
intent2.putExtra(EXTRA_NAME, ",Vertretungsplan");
startActivity(intent2);
}
}
}
And here's the code which creates the notification:
// I've censored all private values with ***'s
// CheckService.MC = Context of main activity
// CheckService.NM = NotificationManager
public static void PostNotification(String text, String datum) {
Intent intentS = new Intent(CheckService.MC, ***************Handler.class);
Intent intentD = new Intent(CheckService.MC, ***************Handler.class);
String EXTRA_ACTION = "de.xorg.*****.ACTION";
String EXTRA_DATE = "de.xorg.*****.VPDATE";
intentS.putExtra(EXTRA_ACTION, "S");
intentS.putExtra(EXTRA_DATE, datum);
intentD.putExtra(EXTRA_ACTION, "D");
intentD.putExtra(EXTRA_DATE, datum);
PendingIntent pIntentD = PendingIntent.getActivity(CheckService.MC, 0, intentD, 0);
PendingIntent pIntentS = PendingIntent.getActivity(CheckService.MC, 0, intentS, 0);
// Build notification
Notification n = new Notification.Builder(CheckService.MC)
.setContentTitle("Title")
.setContentText(text)
.setSmallIcon(R.drawable.vertretung)
.setContentIntent(pIntentS)
.setAutoCancel(true)
.addAction(R.drawable.anzeigen, "Show", pIntentS)
.addAction(R.drawable.gelesen, "Dismiss", pIntentD).build();
CheckService.NM.notify(0, n);
}
I've tried to do it with »finish();« and with »android.os.Process.killProcess(android.os.Process.myPid());« both aren't working.
Why doesn't that work? Is there a different (better) way to update the setting?
Currently I am working on GCM (Google Cloud message), it allow user to push the message to user device. And I would like achieve the following requirement :
if the user has already enter app , ignore it
if the user has not enter the app , click on notification to enter the app
And the work flow of my app is:
WelcomePage (download json and create data set from it) => MainPage (Display base on the data set)
The code to handle notification
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
String notifyMsg = "";
JSONTokener tokener = new JSONTokener(msg);
if (tokener != null) {
try {
notifyMsg = new JSONObject(tokener).getString("msg");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Intent myintent = new Intent(this, WelcomePageActivity.class);
myintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, myintent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getResources().getString(R.string.notification_title))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(notifyMsg))
.setContentText(notifyMsg)
.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
The problem is if I use WelcomePageActivity class , it will create a new activity if I am at the main page, how can I adjust the code to fit my requirement ?
Thanks
For
1. if the user has already enter app , ignore it:
in the onReceive() , check if your app is running, do not notify.
It can be checked with something like:
ActivityManager activityManager =(ActivityManager)gpsService.this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> serviceList= activityManager.getRunningServices(Integer.MAX_VALUE);
if((serviceList.size() > 0)) {
boolean found = false;
for(int i = 0; i < serviceList.size(); i++) {
RunningServiceInfo serviceInfo = serviceList.get(i);
ComponentName serviceName = serviceInfo.service;
if(serviceName.getClassName().equals("Packagename.ActivityOrServiceName")) {
//Your service or activity is running
break;
}
}
if the user has not enter the app , click on notification to enter the app
from the code above, you'l know if you would like to resume the app or launch - call Splash Screen or in your case WelcomeActivity.
About the workflow of your app, i'd suggest check whether you need to download the data every time or not. Can save it maybe or update/download only when required, and rest of flow works as it is.
In your AndroidManifest.xml, define your WelcomePageActivity with the flag android:launchMode="singleTop". From the definition of this flag:
A new instance of a "singleTop" activity may also be created to handle
a new intent. However, if the target task already has an existing
instance of the activity at the top of its stack, that instance will
receive the new intent (in an onNewIntent() call); a new instance is
not created.
So with this flag, your activity will not be created again, rather it will receive a call in the onNewIntent() function with the Intent you used to create the PendingIntent for the notification. You could override this function, and use the intent to pass the activity new information.
You will not able to receive any notification click event so,
try this code :
Intent myintent = new Intent(this, TestActivity.class);
myintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, myintent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getResources().getString(R.string.notification_title))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(notifyMsg))
.setContentText(notifyMsg)
.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
public class TestActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// check for your app state is running or not
if(appRunning == false) {
// start your WelcomePage activity.
}
}
}
1.Create an object in GcmIntentService
public static final Object CURRENTACTIVIYLOCK = new Object();
//for storing current activity
public static Activity currentActivity;
2.Update this object value in onPause and onResume of MainActivity to recognize Activity is running or not.
#Override
public void onResume() {
super.onResume();
System.out.println("onResume Home page");
synchronized (GcmIntentService.CURRENTACTIVIYLOCK) {
GcmIntentService.currentActivity = this;
}
}
#Override
public void onPause() {
super.onPause();
synchronized (GcmIntentService.CURRENTACTIVIYLOCK) {
GcmIntentService.currentActivity = null;
}
}
3.In GcmIntentService class, check for the current activity in onHandleIntent method.
synchronized (CURRENTACTIVIYLOCK) {
if (currentActivity != null) {
if (currentActivity.getClass() == HomePageActivity.class) {
} else {
sendNotification(extras.getString("message"));
}
} else {
sendNotification(extras.getString("message"));
}
I'm sure this will help you.