EditText in BroadcastReceiver Android - java

I am trying to create custom notifications. I have two EditText attributes in my XML file. I'm unable to understand how to pass the value of EditText from ReminderFragment.java to AlertReceiver.java or rather, can I declare EditText in AlertReceiver itself?
ReminderFragment.java
Declaration
eText = (EditText) findViewById(R.id.edittext);
findViewById(R.id.btnSetReminder).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String str = eText.getText().toString();
//how to return the string to createNotification method in AlertReceiver.java
setAlarm();
}
});
Method called when Button Set Reminder is clicked
public void setAlarm() {
calcal = new GregorianCalendar();
calcal.set(pYear, pMonth, pDay, pHour, pMinute);
Intent alertIntent = new Intent(ReminderFragment.this, AlertReceiver.class);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calcal.getTimeInMillis(),
PendingIntent.getBroadcast(ReminderFragment.this, 1, alertIntent, PendingIntent.FLAG_UPDATE_CURRENT));
}
and AlertReceiver.java
public class AlertReceiver extends BroadcastReceiver {
public AlertReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
createNotification(context, "Good morning",
"You have a meeting with Mr. C today!", "Alert");
//this is where the custom text must appear
}
public void createNotification(Context context, String s, String s1, String alert) {
PendingIntent notificIntent = PendingIntent.getActivity(context, 0,
new Intent(context, ReminderFragment.class), 0);
NotificationCompat.Builder nBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.icon)
.setContentTitle(s)
.setTicker(alert)
.setContentText(s1);
nBuilder.setContentIntent(notificIntent);
nBuilder.setDefaults(NotificationCompat.DEFAULT_SOUND);
nBuilder.setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, nBuilder.build());
}
}

I will tell you how a broadcast receiver works.
Assuming you have registered it properly in manifest, you send a 'broadcast' message (duh), much like a cellular tower.
And your receiver is supposed to 'catch' that broadcast message. The way you pass data in that broadcast message is by passing extras.
The general way to put an additional message is by putting 'extras'
you can do that by adding:
alertIntent.putExtra("key", "value");
there are many different data types to choose from for key and value, like strings, arrays , booleans , etc

You can put an extra (or multiple) in your Intent:
in setAlarm() simply add
alertIntent.putExtra(<key>, <string>);
replace <key> with any string you like, e.g. "text" or just "key" and <string> with the string you want to send to the AlarmReceiver.
In AlarmReceiver you can then get the string in onReceive using
String text = intent.getExtras().getString(<key>);
<key> of course has to be the exact same you used in putExtra(), otherwise it won't work.
You can even put multiple Extras with multiple different keys if you like.

Related

Show alert instead of scheduled notification if the app is currently opened

I have an app that schedules a bunch of notifications (user has to answer questionnaires) locally using AlarmManager. The notification should show at certain points in the future.
I schedule the notifications like this:
private void scheduleNotification(Notification notification, int delay, int scheduleId, int notificationId) {
Intent notificationIntent = new Intent(context, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, notificationId);
notificationIntent.putExtra(NotificationPublisher.INTENT, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, scheduleId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, delay);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
The intent is received by a BroadcastReceiver that calls notify on the notification attached to the intent.
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification-id";
public static String INTENT = "notification";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra(INTENT)) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
Notification notification = intent.getParcelableExtra(INTENT);
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
notificationManager.notify(id, notification);
}
}
}
This works fine so far. The problem that I'm facing is that I only want to show the notification if the app is currently not open/shown. If it's open I want to show an AlertDialog instead.
I know that it might be a better idea to put only the plain content of the notification into the intent and only build it when it should be displayed and I want to refactor that later on.
My main problem is, how do I determine in the onReceive of my broadcast receiver if the app is currently showing to decide if a notification or an alert should be displayed?
Or is there an entirely different approach that might work better (for example using WorkManager)?
I think you can handle it on your BroadcastReceiver
public void onReceive(Context context, Intent intent) {
if (isForeground(context))
// AlertDialog
else
// Notification
}
public boolean isForeground(Context mContext) {
ActivityManager activityManager = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.AppTask> tasks = activityManager.getAppTasks();
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).getTaskInfo().topActivity;
return topActivity.getPackageName().equals(mContext.getPackageName());
}
return true;
}

How Do I getText().toString() a TextView Using RemoteViews?

I'm developing a widget for the first time, and remoteviews is a bit confusing compared to building an app.
I understand this part...
RemoteViews views = new Remoteviews(context.getPackageName(), R.layout.my_widget_layout);
views.setTextViewText(R.id.myTV, "Hello World");
Now the next is a bit complex for me. I want the button that I have on the widget to pass the TextView text and display it on a toast.
Here's what I started...
Intent myIntent = new Intent(context, myReceiver.class);
PendingIntent myPendingIntent = PendingIntent.getBroadcast(context, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.myButton, myPendingIntent);
My Class (This is where I need help!)
public static class myReceiver extends BroadcastReceiver{
Override
public void onReceive(Context context, Intent intent){
Toast.makeText(context, (HELP! I need to getText().toString() from the R.id.myTV), Toast.LENGTH_SHORT).show();
}
}
Thanks! Much appreciated!
You can add the text you want to display to the intent via putStringExtra method and then extract the extra string like this:
#Override
public void onReceive(Context context, Intent intent) {
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
if (intent.getAction().equals(check-your-desired-action-here)) {
String textThatYouWantToDisplay = intent.getStringExtra("name-of-the-desired-item");
Toast.makeText(context,textThatYouWantToDisplay , Toast.LENGTH_SHORT).show();
}
super.onReceive(context, intent);
}
for more info:
this sample widget app from google
Build an app widget android document
Intent getStringExtra method

Getting Android Alarms Info

Iv'e created several Alarms using an Intent and BroadcastReciever and placed them in an Array of Intents.
For each Intent Iv'e placed a String as in Intent.PutExtra("info", string); to be shown later as a Toast when Alarm is activated,
and gave each a different requestCode.
But when adding multiple Alarms, the Toast shows EVERY other Alarms' info as well.
MainActivity:
Intent newAlarmIntent = new Intent(this,AlarmReceiver.class);
newAlarmIntent.putExtra("info",editText.getText().toString());
alarmsArray[alarmCounter]=newAlarmIntent;
alarm.AlarmListSortAndSetNext(gameArrayList, alarmArray, this,alarmCounter,alarmsArray[alarmCounter]);
Alarm Class:
public void CreateNew (Context context, Long alarmTimeAsLong, int counter, Intent intent)
{
PendingIntent pendingIntent;
pendingIntent = PendingIntent.getBroadcast(context, counter, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager manager;
manager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
manager.set(AlarmManager.RTC_WAKEUP, (alarmTimeAsLong),pendingIntent);
Toast.makeText(context, "Alarm Set", Toast.LENGTH_SHORT).show();
}
public void AlarmListSortAndSetNext (ArrayList<Game> gameArrayList,Long[] alarmArray,Context context,int alarmCounter, Intent intent)
{
Long SystemTimeAsLong = System.currentTimeMillis();
//Sorting Long Array for NEXT ALARM
for (int i=0;i<10;i++)
{if(i<gameArrayList.size()){
alarmArray[i] = gameArrayList.get(i).getDateAndTimeAsLong();
}
else alarmArray[i]= 0L;
}
Arrays.sort(alarmArray);
//Setting next ALARM by Long Size
for(int i=0;i<10;i++)
{
if (alarmArray[i]>SystemTimeAsLong){
CreateNew(context,alarmArray[i],alarmCounter,intent);
alarmCounter++;}
}}
AlarmReceiver:
public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "TAG");
wakeLock.acquire();
String gameInfo= intent.getStringExtra("info");
Toast.makeText(context, gameInfo, Toast.LENGTH_SHORT).show();
MediaPlayer mp = MediaPlayer.create(context, R.raw.bipbip);
mp.start();
wakeLock.release();}}
QUESTION: How can I make each Intent to have it's on "info"/PutExtra, or any other way to tell which one has been activate?
* Found the issue *
I had left the AlarmListSortAndSetNext method which initially was supposed to manage the Next Alarm. I no longer have to use this method since I have created multiple Intents. Something in the looping probably created multiple putExtra();
Thank you.

Android context choice

I don't understand which context I should use in
(mApplicationContext or context parameter from onRecieve method). Please, could you give me some explanation what context parameter I should use and why (I read about memory leaks, documentation for this methods)
final PendingIntent pendingIntent = PendingIntent.getActivity(**mApplicationContext**, <smth>);
Notification.Builder notificationBuilder = new Notification.Builder( **mApplicationContext**).<smth>;
NotificationManager notificationManager = (NotificationManager) **mApplicationContext**.getSystemService(Context.NOTIFICATION_SERVICE);
// Constructor
public DownloaderTask(MainActivity parentActivity) {
super();
mParentActivity = parentActivity;
mApplicationContext = parentActivity.getApplicationContext();
}
mApplicationContext.sendOrderedBroadcast(new Intent(
MainActivity.DATA_REFRESHED_ACTION), null,
new BroadcastReceiver() {
final String failMsg = "Download has failed. Please retry Later.";
final String successMsg = "Download completed successfully.";
#Override
public void onReceive(Context context, Intent intent) {
if (getResultCode() != Activity.RESULT_OK) {
final PendingIntent pendingIntent = PendingIntent
.getActivity(mApplicationContext, <smth>);
RemoteViews mContentView = new RemoteViews(
mApplicationContext.getPackageName(),
R.layout.custom_notification);
if(success){
mContentView.setTextViewText(R.id.text,
successMsg);
} else {
mContentView.setTextViewText(R.id.text, failMsg);
}
Notification.Builder notificationBuilder = new Notification.Builder(
mApplicationContext).<smth>;
notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) mApplicationContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(MY_NOTIFICATION_ID, notificationBuilder.build());
log("Notification Area Notification sent");
}
}
}, null, 0, null, null);
}
Always use the most specific context that you have. Use "this" in activities, and the context that is provided to you through methods.
Leave the application context to those cases where you can't have access to an activity context.
speaking generally, if you are in an activity, 'this' is your context ( remember to import android.content.Context; ), you can also pass the context to your fragments.
There are other times when it's a good idea to getApplicationContext, like in services launching alarms and such, but you'd do well to think of the activity you are working with as the context and you'll find out about the other exceptions as you go along.
keeping to this pattern, it is always informative when you think you have access to a context but you realize you don't; consider what exactly you are trying to do with that object, and what part of the program it "belongs" to.
So, inferring what constructed this object, another activity did DownloaderTask(this) or DownloaderTask(this.context) or DownloaderTask(getApplicationContext); I'd do it the first of those ways and just form the constructor here with public void DownloaderTask(Context context) =]

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

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

Categories

Resources