How to show pop up notification on reminder app? - java

I am working on an reminder type java application using javafx which will remind me about tasks showing pop up on desktop about the task.But i don't know how to do it.Can anyone help me?

The Reminder Notification Mechanism
This assumes using JavaFX 8. The reminder has date and time fields. The app displays an alert dialog (javafx.scene.control.Alert control) whenever a reminder is due.
The notification mechanism is implemented using the Timer and TimerTask API of java.util package. Timer is a facility for threads to schedule tasks for future execution in a background thread. Tasks may be scheduled for one-time execution, or for repeated execution at regular intervals. The task is defined by extending a TimerTask. This is an abstract class which implements Runnable; the run() method has code for the action of this task.
There are two tasks defined for reminder notification. The first one is run once at the start of the app; this checks for all the overdue reminders and shows them in reminder alerts. The next task is scheduled to run at a regular interval, every minute (or whatever is the desired time interval) for the duration of the app.
The following code snippet shows the initialization of the timer and timer's task at the start of the app:
Timer timer = new Timer();
RemindersTask tasks = new RemindersTask();
timer.scheduleAtFixedRate(tasks, zeroDelay, periodOneMinute);
The Reminders Task
The class RemindersTask.java extends the TimerTask and overrides the run() abstract method. The run method has code to check for due or overdue reminders and display the reminder alert.
In the following code snippet the getDueRems() method retrieves all the due reminders based on the supplied predicate (of type java.util.function.Predicate). Initially, the predicate value is set as: Predicate<Reminder> predicate = ReminderPredicates.OVER_DUE; - this notifies all the due reminders until the start of the app - all overdue reminders. After the first run of the task, the predicate is reset to ReminderPredicates.DUE_NOW and is run at a regular interval set at the start of the scheduling the timer.
The following code snippet shows the run method for the timer task:
public void run() {
List<Reminder> dueRems = getDueRems();
showNotifications(dueRems); // shows the multiple notifications in an alert dialog
predicate = ReminderPredicates.DUE_NOW;
}
private List<Reminder> getDueRems() {
ObservableList<Reminder> rems = dataClass.getAllReminders();
return rems.stream()
.filter(predicate)
.collect(Collectors.toList());
}
The Reminder Predicates
A java.util.function.Predicate<T> is a functional interface and represents a predicate (a boolean-valued function) of one argument (T is the input type).
Here are some example predicate definitions (defined in ReminderPredicates class as constants), and others may be defined based on the requirements:
Predicate<Reminder> TODAYS = r -> r.getDate().isEqual(LocalDate.now());
Predicate<Reminder> COMPLETED = r -> (r.getCompleted() == true);
Predicate<Reminder> DUE_NOW = TODAYS.and(COMPLETED.negate());

Related

RxJava. How do I make the Observable timer run in the background?

I need to make sure that after pressing one button, the other is not available for 15 minutes. To do this, I use a method like this:
disposableTimer = Observable.timer(15,TimeUnit.MINUTES)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(aLong -> {
buttonSimpleAct.setEnabled(true);
});
This works well when the program is active, but I need this timer to work even when the program is closed.
That is, if the first button was pressed, the application was closed and returned after 15 minutes, the second button should already be active.
Are there any ways to make the Observable work in the background, or alternatives to this?
What I'd do is save (in a persistent manner) the timestamp for when the button should be re-enabled and restart the timer with the remaining time when the app comes back.
// when the first button is clicked:
long reenableAfter = System.currentTimeMillis() + 15 * 60 * 1000L;
save(reenableAfter);
disposableTimer = Observable.timer(15 ,TimeUnit.MINUTES, AndroidSchedulers.mainThread())
.subscribe(aLong -> buttonSimpleAct.setEnabled(true));
// when the app starts
long reenableAfter = load();
disposableTimer = Observable.timer(reenableAfter - System.currentTimeMillis(),
TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.subscribe(aLong -> buttonSimpleAct.setEnabled(true));

Using a JavaFX Alert dialog freezes a JavaFX task [duplicate]

I am trying to set up a background service that would perform bulk loading of transaction data from a csv file. This background service would be initiated from a menu item action mapped to a method in the controller/presenter class.
Ever so often, some data turns up in the csv file for which no master data can be found in the database, this would normally cause the upload to choke and fail.
On such occasions, I would like to be able to have the background service pause its processing and invoke a dialog from a presenter class to take in user input. The user input would be used to add a master row in the database, after which the background service should resume from where it had left off (not from the beginning of the csv file, but from the row which caused the error).
Is this possible to achieve in JavaFX, perhaps with the javafx.concurrent API? How would I go about doing this?
Solution
When your background process encounters a situation where it requires a user to be prompted for input, use FutureTask executed in Platform.runLater to showAndWait the dialog prompt on the JavaFX application thread. In the background process use futureTask.get to pause the background process until the user has input the necessary values which will allow the process to continue.
Sample Code Snippet
Here is the essence of code for this approach which can be placed inside the call method of your background process:
String nextText = readLineFromSource();
if ("MISSING".equals(nextText)) {
updateMessage("Prompting for missing text");
FutureTask<String> futureTask = new FutureTask(
new MissingTextPrompt()
);
Platform.runLater(futureTask);
nextText = futureTask.get();
}
...
class MissingTextPrompt implements Callable<String> {
private TextField textField;
#Override public String call() throws Exception {
final Stage dialog = new Stage();
dialog.setScene(createDialogScene());
dialog.showAndWait();
return textField.getText();
}
...
}
Sample Application
I created a small, complete sample application to demonstrate this approach.
The output of the sample application is:
Sample Output Explanation
Lines read without missing values are just plain brown.
Lines with a prompt value entered have a pale green background.
Fourteen lines have been read, the background task has already paused once at the 6th line which was missing a value. The user was prompted for the missing value (to which the user entered xyzzy), then the process continued until line 14 which is also missing and the background task is again paused and another prompt dialog is being displayed.

Is it possible to register a receiver in a test case?

I want to test inside a unit test whether or not an alarm programmed using the AlarmManager is fired, and if so, if it is fired within the correct period.
Here is the receiver class to be tested.
I've created it inside my test project.
(NOTE: it's not registered in the manifest)
public class MockBroadcastReceiver extends BroadcastReceiver {
private static int numTimesCalled = 0;
MockBroadcastReceiver(){
numTimesCalled = 0;
}
#Override
public void onReceive(Context context, Intent intent) {
numTimesCalled++;
}
public static int getNumTimesCalled() {
return numTimesCalled;
}
public static void setNumTimesCalled(int numTimesCalled) {
MockBroadcastReceiver.numTimesCalled = numTimesCalled;
}
}
And here's the unit test. The programReceiver method actually belongs to a class in the main project, but I've included it inside the test so that you don't need to read so much code.
public class ATest extends AndroidTestCase {
MockBroadcastReceiver mockReceiver;
#Override
protected void setUp() throws Exception {
mockReceiver = new MockBroadcastReceiver();
getContext().registerReceiver(mockReceiver, new IntentFilter());
}
#Override
protected void tearDown() {
getContext().unregisterReceiver(mockReceiver);
mockReceiver = null;
}
public void test(){
//We're going to program twice and check that only the last
//programmed alarm should remain active.
final Object flag = new Object();
MockBroadcastReceiver.setNumTimesCalled(0);
new Thread (){
#Override
public void run(){
programReceiver(getContext(), MockBroadcastReceiver.class, 60000, 60000);
SystemClock.sleep(20000);
programReceiver(getContext(), MockBroadcastReceiver.class, 60000, 60000);
SystemClock.sleep(90000);
synchronized(flag){
flag.notifyAll();
}
}
}.start();
synchronized(flag){
try {
flag.wait();
} catch (InterruptedException e) {
}
}
assertEquals(1, MockBroadcastReceiver.getNumTimesCalled()); //should have been called at least once, but its 0.
}
private static void programReceiver(Context context, Class<? extends BroadcastReceiver> receiverClass, long initialDelay, long period){
Intent intent = new Intent(context, receiverClass);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent); //Cancel any previous alarm
alarmManager.setInexactRepeating (
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + initialDelay,
period,
pendingIntent
);
}
}
When I execute the test method, the receiver should have been registered dynamically in the setUp. Then I program the same alarm twice. My intent was to test that only the last alarm remained active, but I'm having trouble getting the receiver called at all. The test fails as it is expected to be called once (or at least a number of times >= 1), but the counter in the mock receiver is 0. I've set a break point in the onReceive method and it is never hit. I've also added logging and nothing shows in the logcat. So I'm 100% sure the receiver is not being called. I've also tried increasing the sleep time in the thread, because setInexactRepeating fires very inexactly, but I can wait for ages and it is still not called.
I've also tried registering it in the test project's manifest instead of programmatically and the results are the same.
Why is the receiver not being called?
UPDATE
I can confirm the AlarmManager is not the issue. Alarms are correctly registered according to adb dumpsys alarm.
I'm now trying to get the receiver to run by calling sendBroadcast, but I'm in a dead end. The receiver just won't get called. I tried the main app context, the test case context, even ActivityInstrumentationTestCase2. Tried also adding WakeLocks and nothing. There's just no way of getting it called. I think this might be caused by some flags in the intent or intent filter (android seems to be really picky with flags).
In the android source-code there is a alarmManagerTest that executes alarmManager.setInexactRepeating with a broadcastreceiver.
The main difference is that the working android test has a delay of 15 minutes while your test uses 1 minute delay.
The Android documentation for AlarmManager says:
public void setInexactRepeating (int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
...
intervalMillis interval in milliseconds between subsequent repeats of the alarm. Prior to API 19, if this is one of INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_HALF_DAY, or INTERVAL_DAY then the alarm will be phase-aligned with other alarms to reduce the number of wakeups. Otherwise, the alarm will be set as though the application had called setRepeating(int, long, long, PendingIntent). As of API 19, all repeating alarms will be inexact and subject to batching with other alarms regardless of their stated repeat interval.
I am not shure if this means that only multibles of 15 minutes are allowed.
On my Android 2.2 handset the inexact timer only works if it is a multible of 15 minutes.
I'm not sure why your test is not working as expected. A couple of suggestions spring to mind:
Most of the doco I've seen, eg. [1], suggests that Object.wait() should always be called within a loop based on a condition that does not hold. Your code does not do this. Perhaps you could try re-working it so that it does.
For completeness, perhaps you should output something for the InterruptedException that can be thrown by flag.wait() just in case.
[1] https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--
So the answer is yes, it is possible, BUT receivers will only work with implicit (action-based) Intents and IntentFilters.
Explicit intents (class based, with no filters) don't work with dynamically registered receivers. For explicit intents to work, you need to register the receiver in the manifest, and not dynamically as I was trying to do.
This is one of the darkest and least documented features of Android. In my experience with intents, you can never be sure. And it's also very difficult to diagnose, as there's no warning printed in the logcat that could help understand the problem. Kudos to #d2vid's answer here:
https://stackoverflow.com/a/19482865
So to fix my code I'd have to add the receiver element inside the application tag in the manifest. As the receiver is a mock receiver class created inside the test project, I'd have to edit the test project manifest, not the main project one. But on the other hand, in Eclipse test projects, receiver tags added to the manifest don't seem to work. Android Studio looks better suited for manifest merging, but this is a legacy project started in Eclipse and we are not porting it.
In conclusion: explicit intent testing is broken in Eclipse for those receivers that don't exist in the main project. The class I needed to test uses only explicit intents so my test can't be written in Eclipse.

Platform.runLater

I have and app that connects to a socket connection and that connections sends me a lot of info.. lets say 300 orders per second (maybe more).. I have a class (it is like a listener, that reacts to some event and that event has the order) that receives that order.. creates an object and then adds it to an ObservableList (which is the source of a tableView).. that way my GUI shows that order. But here comes the problem, if that order already exists on the observableList.. i can't add it ..and i must update it (wich i do).. but some times.. with some orders this condition doesn't work and the order its added again.
Im gonna show you how it's work with some code.
public class ReceivedOrderListener
{
ev = Event; //Supose that this is the event with the order
if(!Repository.ordersIdMap.containsKey(ev.orderID))
{
Platform.runLater(new Runnable()
{
#Override public void run()
{
Repository.ordersCollection.add(ev.orderVo);
}
}
});
Repository.ordersIdMap.put(ev.orderID, ev.orderVo);
}
Ok now.. this is a resume of my code. The ev is my event with all the info of the order, the orderID is the key that i use to see if the order already exists or not (and yeah is unique). The "Repository" is a singleton class, the "ordersCollection" is a ObservableList, the "ordersIdMap" is a HashMap
If ReceivedOrderListener is executed by multiple threads, then it looks like "check-then-act" race condition.
-> ORDER1 comes to the listener
T1 checks ordersIdMap.containsKey(ORDER1) it returs false
T1 proceeds to do Platform.runLater to add the order
-> ORDER1 comes to the listener again
-> T2 checks ordersIdMap.containsKey(ORDER1) it returs false again
now T1 proceeds to do ordersIdMap.put(ORDER1)
-> T2 proceeds to do Platform.runLater to add the order again

How can I schedule a particular thread in Blackberry

I want to auto-schedule a thread with a particular time interval. I also need to execute this in the background continously without hangs to the device.
I have tried this with Application Manager Class but it's for application scheduling and I need to schedule thread within the application.
I would use TimerTask:
public class MyScreen extends MainScreen {
private Timer mTimer;
public MyScreen() {
mTimer = new Timer();
//start after 1 second, repeat every 5 second
mTimer.schedule(mTimerTask, 0, 5000);
}
TimerTask mTimerTask = new TimerTask() {
public void run() {
// some processing here
}
};
}
see BlackBerry API Hidden Gems (Part Two)
use UiApplication.getUiApplication().invokeLater()
it accepts a delay and repeat parameters and will perform exactly what you need.
EDIT
I know this post is old but this is by far the best option to schedule repeating events and I would like to add that to stop the scheduled event the following is required:
//Start repeating "runnable" thread every 10 seconds and save the event ID
int eventId = UiApplication.getUiApplication().invokeLater(runnable, 10000, true);
//Cancel the repetition by the saved ID
UiApplication.getUiApplication().cancelInvokeLater(eventId);
Assuming you want it to run a thread on device startup:
Create a second project and list it as an alternate entry point.
In your UiApplication or Application main(), check the argument passed to the project. Do your periodic stuff there via Thread.sleep and don't call enterEventDispatcher.
search for "autostart":
http://docs.blackberry.com/en/developers/deliverables/1076/development.pdf
Or if you want to do something once a user "starts" it, then look into creating a new thread to do your timing stuff. Override your screen's onClose() and use Application.getActivation().deactivate() to throw the screen into the background.
Or there's a other ways to do something like this like invokeLater, etc. Maybe eventlisteners may do what you need, but you didn't give a lot of details.
As long as the application is running - just create the thread and after each bit of work call Thread.sleep for as long as you need it to stay dormant.
If you need it to wake up at a particular time, rather than just sleep for a particular time, then you can do something like the following:
Date wakeUpAt = ...; // Get this however
Date now = new Date();
long millisToSleepFor = wakeUpAt.getTime() - now.getTime();
Thread.sleep(millisToSleepFor);

Categories