I have a reminder app I'm developing and everything works like its supposed to except the time the user is notified. I use a Time Picker to choose the time, but do not know how to add the user-set time to the pending intent. I have researched the android docs as well as other sites with similar searches, but to no avail. Any ideas?
MainActivity.java
public class MainActivity extends Activity{
int mHour;
int mMinute;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void setAlarm(View view) {
TimePicker picker = (TimePicker)findViewById(R.id.timePicker1);
EditText text = (EditText)findViewById(R.id.editText1);
Toast toast = Toast (text, picker);
toast.show();
Intent intent = new Intent(this, AlarmBoadcastReceiver.class);
PendingIntent pendingintent = PendingIntent.getBroadcast(this.getApplicationContext(), 1234, intent, 0);
Calendar AlarmCal = Calendar.getInstance();
AlarmCal.setTimeInMillis(System.currentTimeMillis());
AlarmCal.set(Calendar.HOUR_OF_DAY, mHour);
AlarmCal.set(Calendar.MINUTE, mMinute);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, /*No Idea what to put here*/, pendingintent);
OnTimeSetListener mTimeSetListener = new OnTimeSetListener() {
#Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// TODO Auto-generated method stub
mHour = hourOfDay;
mMinute = minute;
}
};
}
private Toast Toast(EditText text, TimePicker picker) {
return Toast.makeText(this, "Reminder set for " + picker.getCurrentHour().toString() + ":"
+ picker.getCurrentMinute() + " with message " + "'" + text.getText().toString() + "'",
Toast.LENGTH_LONG);
}
public void exitApp(View view) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
AlarmBoadcastReceiver.java
public class AlarmBoadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(2000);
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.reminder"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.VIBRATE" >
</uses-permission>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.reminder.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="AlarmBoadcastReceiver" >
</receiver>
</application>
</manifest>
With what is posted above the phone vibrates every time the Set Time button is pressed, not when the Time Picker time is set for. Thanks for any help!
The first thing you should note, is that the AlarmManager has two modes for firing off an Alarm at a set time.
The set() will fire off the Alarm at the given time. You will note as of API 19, Alarms defined using the set() method may be batched and therefore may not be fired at the exact time:
Note: Beginning in API 19, the trigger time passed to this method is
treated as inexact: the alarm will not be delivered before this time,
but may be deferred and delivered some time later.
http://developer.android.com/reference/android/app/AlarmManager.html#set(int, long, android.app.PendingIntent)
The setExact() method was added as of API 19 and guarantees that the Alarm will be fired off at the exact given time.
The times passed in are defined as per the first parameter of the set() or setExact() methods. You have chosen RTC_WAKEUP, you need to define the wakeup time in milliseconds UTC time (as given by the System.currentTimeMillis() method).
See: http://developer.android.com/reference/android/app/AlarmManager.html#RTC_WAKEUP
The easiest way of getting this time is by calling:
AlarmCal.getTimeInMillis()
Just a small note, if the given time is in the past, then the Alarm will instantly fire. This is why your Alarm was being triggered the moment you set it.
Additional note from the documentation:
Registered alarms are retained while the device is asleep (and can
optionally wake the device up if they go off during that time), but
will be cleared if it is turned off and rebooted.
Related
My app requires that a notification be sent twice a day. For testing purposes, I have shortened this time to 1 hour. This, of course, must be done in the background/when app is closed, so I have already tried AlarmManager and that did not work. I have therefore switched to WorkManager. someone suggested that I use periodicWork to accomplish my task but here is the issue:
WorkManager only executes all periodic work when the app is open
Another weird thing: If I leave the app alone for 3 hours, I will get way more than three notifications when I open the app.
I know for a fact that WorkManager is not executing because I have instantiated a Date Object whenever doWork() is called, and that timestamp from the date object is printed to the notification. This printed time will ALWAYS show as the time I have opened the app, meaning all of the queued work requests were executed at once when I opened the app.
Here is what is used to set the alarm. Note that cancelAlarm() does not cancel the alarm, but rather resets a shared preference I used for debugging
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_enter);
ToggleButton toggle = findViewById(R.id.toggleButton);
toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
setAlarm();
} else {
cancelAlarm();
}
}
});
}
private void setAlarm() {
Constraints constraints = Constraints.NONE;
PeriodicWorkRequest testRequest = new PeriodicWorkRequest.Builder(ReminderWorker.class, 1, TimeUnit.HOURS)
.setConstraints(constraints)
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork("ReminderWork", ExistingPeriodicWorkPolicy.KEEP, testRequest);
}
private void cancelAlarm() {
SharedPreferences savedSharedPreferences = getApplicationContext().getSharedPreferences("USER_PREFERENCES", Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = savedSharedPreferences.edit();
editor.putInt("Test", 0);
editor.commit();
}
Here is the actual ReminderWorker class, I put a SHaredPreference variable to check the amount of times the worker fired, and a Date objectto check the time fired. These are printed in the notification.
public class ReminderWorker extends Worker {
int i;
public final String CHANNEL_ID = "MainChannel";
public ReminderWorker(#NonNull Context context, #NonNull WorkerParameters params) {
super(context, params);
}
#NonNull
#Override
public Result doWork() {
Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
SharedPreferences savedSharedPreferences = getApplicationContext().getSharedPreferences("USER_PREFERENCES", Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = savedSharedPreferences.edit();
i = savedSharedPreferences.getInt("Test", 0) + 1;
editor.putInt("Test", i);
editor.commit();
createNotificationChannel();
buildNotification(cal);
return Result.success();
}
private void createNotificationChannel() {
String name = "Birthday Notifications";
String description = "Reminds you when your friends birthday approaches";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getApplicationContext().getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
private void buildNotification(Calendar cal) {
Context context = getApplicationContext();
Intent openTap = new Intent(context, EnterActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, openTap, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
builder.setSmallIcon(R.drawable.pix_cake);
builder.setContentTitle("TestNotification");
builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText("TestText" + i + " Time: " + cal.get(Calendar.HOUR) + ":" + cal.get(Calendar.MINUTE)));
builder.setPriority(NotificationCompat.PRIORITY_MAX);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(i, builder.build());
//notificationManager.cancelAll();
}
}
In case it is needed, here is my AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myfirstapp">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SET_ALARM" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:icon="#mipmap/main_icon"
android:label="#string/app_name"
android:roundIcon="#mipmap/main_icon_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".ListOfDaysActivity" />
<activity android:name=".MainActivity" />
<activity android:name=".EnterActivity"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
No errors thrown, just not the result expected. I need a notification to show up roughly every hour but that simply isn't happening.Any way around this?
Do you remove the application from task manager? Which device are you using for testing? There are some devices that force close the app and WorkManager tasks are rescheduled once you open the app again.
This answer might help you understand what is going on - https://stackoverflow.com/a/52605503/1313699
I have certain dates which once attained lose their relevance and new dates for these fields in the DB should be calculated, I know I can leverage the AlarmManager class for this, however I have a few concerns regarding this:
1) Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
So do I need to code for both cases separately or if I target kitkat, will that work for older versions too? Also as my code execution is time critical, say after 12AM in the midnight of some date my Data loses relevance, how to overcome shifting of alarms.
2)Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
2.1) Set the RECEIVE_BOOT_COMPLETED permission in your application's manifest. This allows your app to receive the ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting (this only works if the app has already been launched by the user at least once)
2.1.1) If I have set an alarm at 12, the service related to this alarm fires at 12, Now when I reboot the device, the time "at 12" has already passed, the alarm will be fired again immediately and the service will be called again?
At reboot what mechanism do I need to implement in-order to stick to my code execution policy at certain time? How do I set the alarm if the user does not launch my app?
The third thing is that if my app is uninstalled I want to clear all alarms set by my code, how do I listen to when the app is uninstalled?
Also I want to know, my app is very time critical, the values in my DB get obsolete by 12 am each night, while I am updating the app, what would be the result if a user chooses to use my app at 12 while I use a service to update it and its running in the background?
EDIT: What I have tried so far:
I have a Database in which records get stale past midnight, say sharp at 12:00. I invoked an Alarm Manager(In a test project as I like to isolate the problem code) to fire a service. I also acquire a PARTIAL_WAKE_LOCK on the device so that my huge database manipulation is done properly. I have also implemented a thread to do my time consuming task. Following is my MainActivity Class which I invoke at 12 to initiate the alarm(Random time for test purpose):
public class MainActivity extends Activity {
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
BroadcastReceiver br;
TextView t;
int sum;
public void setSum(int s){
sum = s;
// t = (TextView)findViewById(R.id.textView1);
// t.setText(sum);
System.out.println("In Set Sum"+s);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setup();
t = (TextView)findViewById(R.id.textView1);
ComponentName receiver = new ComponentName(getApplicationContext(), SampleBootReceiver.class);
PackageManager pm = getApplicationContext().getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 17);
calendar.set(Calendar.MINUTE, 05); // Particular minute
calendar.set(Calendar.SECOND, 0);
alarmMgr = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
1000*60*60*24, alarmIntent);
}
public void setup() {
br = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent i) {
Toast.makeText(c, "Rise and Shine!", Toast.LENGTH_LONG).show();
//Invoke the service here Put the wake lock and initiate bind service
t.setText("Hello Alarm set");
startService(new Intent(MainActivity.this, MyService.class));
stopService(new Intent(MainActivity.this, MyService.class));
}
};
registerReceiver(br, new IntentFilter("com.testrtc") );
alarmIntent = PendingIntent.getBroadcast( this, 0, new Intent("com.testrtc"),0 );
alarmMgr = (AlarmManager)(this.getSystemService( Context.ALARM_SERVICE ));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
This is my SampleBootReceiver Class inorder to check for reboots and set Alarms again after reboot, I am not sure if it works as intended. I could find no means to test if this is working properly but I do receive the Toast message about completion of boot.
public class SampleBootReceiver extends BroadcastReceiver {
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
BroadcastReceiver br;
TextView t;
MainActivity main;
#Override
public void onReceive(Context context, Intent intent) {
main= new MainActivity();
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
Toast.makeText(context, "Hello from Bootloader", 10000).show();
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 15);
calendar.set(Calendar.MINUTE, 50); // Particular minute
calendar.set(Calendar.SECOND, 0);
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
1000*60*60*24, alarmIntent);
context.getApplicationContext().registerReceiver(br, new IntentFilter("com.testrtc") );
alarmIntent = PendingIntent.getBroadcast( context.getApplicationContext(), 0, new Intent("com.testrtc"),
0 );
alarmMgr = (AlarmManager)(context.getApplicationContext().getSystemService( Context.ALARM_SERVICE ));
}
}
}
The following is my service Class, unsure about the return I am doing here in the onStartCommand method:
public class MyService extends Service {
int a = 2;
int b = 2;
int c = a+b;
public MainActivity main = new MainActivity();
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
Toast.makeText(this, "The new Service was Created", Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent i, int flags , int startId){
WakeLock wakeLock = null;
try{
PowerManager mgr = (PowerManager)getApplicationContext().getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
Toast.makeText(this, " Service Started", Toast.LENGTH_LONG).show();
new Thread(new Runnable() {
public void run(){
//Will be substituted with a time consuming long task.
main.setSum(c);
}
}).start();
}catch(Exception e){
System.out.println(e);
}finally{
wakeLock.release();
}
return 1;
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
}
Also in the above, I want to know if the thread I am starting will interfare with how I am acquiring the wake lock. Also if I can use an async task and release the wakelock in onPostExecute?
Finally here is my Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testrtc"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.testrtc.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".SampleBootReceiver"
android:enabled="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" >
</action>
</intent-filter>
</receiver>
<service
android:name="com.testrtc.MyService"
android:enabled="true"
android:exported="true" >
</service>
</application>
</manifest>
THis is my log Cat after reboot, there are many log messages however I find these related to the app, they contain th epackage name:
01-22 15:18:35.652: V/ActivityManager(419): getTasks: max=1, flags=0, receiver=null
01-22 15:18:35.652: V/ActivityManager(419): com.xxx.xxx/.MainActivity: task=TaskRecord{425c58f0 #5 A com.xxx.xxx U 0}
01-22 15:18:35.653: V/ActivityManager(419): We have pending thumbnails: null
More Questions: Where should I set up the Alarm, if I do it in the onCreate of my Splash screen it will be called each time the app starts, maybe overwriting the older values.
Second I want to acquire a lock on the DB when my service is running, if in this time the user tries to open my app what do I do? (As data is getting updated I dont have anything to show).
Third in the above code I am still finding problems to register an alarm after reboot.
1) To handle alarm at exact times you have 2 options:
a) Set minimum SDK level at 18 and not 19. This will make your app work on kitkat at the exact time
b) Use the setExact() method to tell Kitkat to keep your alarm at the exact time specified
Source: http://developer.android.com/about/versions/android-4.4.html
2) The boot completed notification is the best way to go. You can set up a Broadcast receiver to get the notification on a reboot. You can store alarms in a Database and retrieve on reboot.
2.1) It is horrible programming practice to do something the user did not want you to do, i.e. set an alarm even though user has not opened the app.
3) As long as you don't create files on the SD card, all application data is removed upon uninstall of the app
4) You should lock/unlock data when writing or reading from it to solve your 12AM problem. If the data is locked, it would not get affected until the user has committed the transaction. If you are using SQLite you can get more information on this from: http://www.sqlite.org/lockingv3.html
I think, you can write a Service something similar to the below one (This will do your task for every 5 minutes) and start the Service from the BroadcastReceiver which listens to BOOT_COMPLETED state.
public class YourService extends IntentService {
public YourService() {
super("YourService");
}
public YourService(String name) {
super(name);
}
private static Timer timer = new Timer();
private class mainTask extends TimerTask {
public void run() {
// TASK WHATEVER YOU WANT TO DO
}
}
public void onDestroy() {
super.onDestroy();
}
#Override
protected void onHandleIntent(Intent intent) {
timer.scheduleAtFixedRate(new mainTask(), 0, 300000); // 5 minutes
}
}
(This is my first SE question ever, but I've relied heavily on this site for it's fantastic community as I've bumbled around learning Java and Android!)
I'm creating an Android widget that (for the time being) has only one button that functions as a two-sided dice. Eventually this widget will support all major RPG dice sizes (d6, d8, d20, etc), but for now I'm just trying to get the intent/receiver system working.
Currently nothing happens when I hit the d2 button in my widget. So far as I can tell by debugging my custom intent is fired, but the onReceive in my IntentReceiver never catches it. Any assistance you can provide would be much appreciated!
Here is my WidgetProvider:
public class MyWidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
remoteViews.setOnClickPendingIntent(R.id.btnReset, buildButtonPendingIntent(context));
Log.e(null, "Setup remote views & Onclick");
Toast.makeText(context, "Test", Toast.LENGTH_SHORT).show();
pushWidgetUpdate(context, remoteViews);
}
public static PendingIntent buildButtonPendingIntent(Context context) {
Intent intent = new Intent();
intent.setAction("ca.sulli.rpgdicewidget.intent.action.D2");
Log.e(null, "Setting new ButtonPendingIntent");
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
Log.e(null, "Updating widget!");
ComponentName myWidget = new ComponentName(context, MyWidgetProvider.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(myWidget, remoteViews);
}
}
And here is my receiver:
public class MyWidgetIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.e(null,"Checking intent by receiver");
if(intent.getAction().equals("ca.sulli.rpgdicewidget.intent.action.D2")){
Log.e(null,"Correct intent received!");
updateWidgetPictureAndButtonListener(context);
}
}
private void updateWidgetPictureAndButtonListener(Context context) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
Log.e(null,"Updating text since the intent was received!");
remoteViews.setTextViewText(R.id.txtResult, "Intent Received! ");
remoteViews.setOnClickPendingIntent(R.id.btnD2, MyWidgetProvider.buildButtonPendingIntent(context));
MyWidgetProvider.pushWidgetUpdate(context.getApplicationContext(), remoteViews);
}
}
And for completions' sake, my manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ca.sulli.rpgdicewidget"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name="MyWidgetProvider" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="ca.sulli.rpgdicewidget.intent.action.D2" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
</receiver>
</application>
</manifest>
And the appwidget-provider:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="200dp" android:minHeight="70dp" android:initialLayout="#layout/main" android:updatePeriodMillis="30000">
</appwidget-provider>
Many thanks for any help provided, and many thanks for the help this community has already provided for me by answering so many other questions!
I cannot see anywhere in your code where you are using the PendingIntent that you have created, you can use the alarmmanager to schedule a message, presumably immediately, using code like this:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (i * 1000), pendingIntent);
Broadcast messages are quite complex though, so you may want to weigh up if you want to use them, you could consider using a regular intent and context.sendBroadcast instead
Well in my app I am trying the following functionality. I want depending on the date and the time, the user to receiver some notifications.
For example:
September 9, 19.13 receive notification with message1
September 10, 07.30, with message 2,
same day, but 11.50, with message 3 and so on...
I used an alarm and a push bar notification but it worked only for the first one. So I serached for that and is is stated that I must use a repeating alarm manager.
Before I post my code I want to clarify some things:
1) I am thinking it that it should work like that:
i must check every 1-2 min, what time is it, fetch my next "time" from an array that events are stored, and set ana alarm for that, right? Then given that this bynch of code will run every 1-2 minutes, i will check again, fetch the next event,set alarm for that time and so on.
Am I correct?
So to begin with, i am trying to implement a repeating alarm manager which every 1 min will display me a Toast message (If I do this and replacing the toast message with get_next_event() and set_next_notification() will do the job I think. - These function are working fine in my project with only one alarm being set).
But problem is that when I am starting my service I see nothing.
here is my code:
Alarm.java
public class Alarm extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Starting Alarm Manager", Toast.LENGTH_LONG).show(); // For example
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
// Put here YOUR code.
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example
wl.release();
}
public void SetAlarm(Context context)
{
Toast.makeText(context, "Setting Alarm Manager", Toast.LENGTH_LONG).show(); // For example
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 , pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
YourService.java
public class YourService extends Service
{
Alarm alarm = new Alarm();
public void onCreate()
{
super.onCreate();
Toast.makeText(YourService.this, "Service Created", Toast.LENGTH_LONG).show(); // For example
}
public void onStart(Context context,Intent intent, int startId)
{
Toast.makeText(YourService.this, "Setting from Service", Toast.LENGTH_LONG).show(); // For example
alarm.SetAlarm(context);
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
DemoActivity.java
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
buttonStart = (Button) findViewById(R.id.buttonStart);
buttonStop = (Button) findViewById(R.id.buttonStop);
buttonStart.setOnClickListener(this);
buttonStop.setOnClickListener(this);
}
public void onClick(View src) {
switch (src.getId()) {
case R.id.buttonStart:
Toast.makeText(ServicesDemo.this, "Button Pressed", Toast.LENGTH_LONG).show(); // For example
Log.d(TAG, "onClick: starting srvice");
startService(new Intent(this, YourService.class));
break;
case R.id.buttonStop:
Log.d(TAG, "onClick: stopping srvice");
stopService(new Intent(this, YourService.class));
break;
}
}
So i press the button, I see that "button is pressed" , i see that "service created" but then none of the toasts that alarm started are being shown. And of course, I see nothing every 1 min.
here is my manifest.
<application android:icon="#drawable/ic_launcher" android:label="#string/app_name">
<activity android:name=".ServicesDemo" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:enabled="true" android:name=".YourService" />
<receiver android:process=":remote" android:name="Alarm"></receiver>
</application>
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
</manifest>
So what do I need to change in my code or in the manifest?
I suggest you to use AlarmManager for this: http://developer.android.com/reference/android/app/AlarmManager.html .
I have a receiver that works well, but I can't seem to show a proper UI, although the toast appears correctly. As far as I can tell, this is caused by Android requiring the class to extend Activity, however, the class already extends BroadcastReceiver, so I can't do this.
So, I tried to do an Intent, but this failed too. There are no errors, but the screen doesn't show. Source code is below.
Broadcast (Method in AndyRoidAlarm)
public void setAlarm(){
Intent intent = new Intent(AndyRoidAlarm.this, Reciever.class);
PendingIntent sender = PendingIntent.getBroadcast(AndyRoidAlarm.this,
0, intent, 0);
// We want the alarm to go off 30 seconds from now.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
// Tell the user about what we did.
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(AndyRoidAlarm.this, "Alarm Scheduled for 30secs", Toast.LENGTH_LONG);
mToast.show();
}
Reciever
public class Reciever extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Alarm Received", Toast.LENGTH_LONG).show();
Intent i = new Intent();
i.setClass(context, AlarmRing.class);
}
}
Reciever V2
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Alarm Received", Toast.LENGTH_LONG).show();
Intent foo = new Intent(context, AlarmRing.class);
//foo.putExtra("id", "id");//example, if you wish to pass custom variables
context.startActivity(foo);
}
AlarmRing
public class AlarmRing extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm);
MediaPlayer mp = MediaPlayer.create(getBaseContext(), R.raw.sweetchild);
mp.start();
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.comaad.andyroidalarm"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".AndyRoidAlarm"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.comaad.andyroidalarm.Reciever" android:enabled="true">
<intent-filter>
<action android:name="com.comaad.andyroidalarm.Reciever"></action>
</intent-filter>
</receiver>
<activity android:name=".AlarmRing"></activity>
</application>
</manifest>
}
In a BroadcastReceiver onReceive() method, if you need a Context (e.g., to create an Intent), use the Context that is passed to you as a parameter of onReceive(). You even have this code in your onReceive() -- you're just not doing anything with the resulting Intent (e.g., calling startActivity()).
Intent foo = new Intent(this, AlarmRing.class);
foo.putExtra("id", id);//example, if you wish to pass custom variables
this.startActivity(foo);
Edit
Check out this example to use BroadcastReciever within an Activity. http://almondmendoza.com/2009/01/04/getting-battery-information-on-android/