I am trying to make an application for my school that includes a background service that will download a student's grades, and assignment history. The service is called every hour by an AlarmManager, and it works, but only as long as the device is powered on. As soon as the device is turned on (from a state of hibernation; the device is not completely shut down), the AlarmManager triggers the service. This is the code of the BroadcastReceiver, which includes the AlarmManager:
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.support.v4.content.WakefulBroadcastReceiver;
public class ServiceAlarmReceiver extends WakefulBroadcastReceiver {
private final String TAG = "com.example.ahsandroidapplication";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Broadcast received");
Intent gradeNotificationServiceIntent = new Intent(context, GradeNotificationService.class);
//context.startService(gradeNotificationServiceIntent);
startWakefulService(context, gradeNotificationServiceIntent);
}
public static void setAlarm(Context context){
System.out.println("Service started");
long alertTime = System.currentTimeMillis() + 1000 * 60 * 60;
Intent alertIntent = new Intent(context, ServiceAlarmReceiver.class);
alertIntent.setAction("com.example.ahsandroidapplication.servicealarmbroadcast");
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
//alarmManager.set(AlarmManager.RTC_WAKEUP, alertTime, PendingIntent.getBroadcast(context, 1, alertIntent,
// PendingIntent.FLAG_UPDATE_CURRENT));
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, alertTime, 1000 * 3600, PendingIntent.getBroadcast(context,
GradeNotificationService.SERVICE_ALARM_BROADCAST_ID, alertIntent,
PendingIntent.FLAG_UPDATE_CURRENT));
}
public static void cancelAlarm(Context context)
{
Intent intent = new Intent(context, ServiceAlarmReceiver.class);
intent.setAction("com.example.ahsandroidapplication.servicealarmbroadcast");
PendingIntent sender = PendingIntent.getBroadcast(context,
GradeNotificationService.SERVICE_ALARM_BROADCAST_ID, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
Because the broadcast is received only when the phone is turned on, I believe the problem lies in the receiver.
There is another problem with the service. It is supposed to send a push notification whenever a new grade is posted, but they are never being sent.
Here is the code for the service class:
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v4.app.NotificationCompat;
public class GradeNotificationService extends IntentService {
private Context context;
public GradeNotificationService() {
super("GradeNotificationService");
// TODO Auto-generated constructor stub
}
public static final int SERVICE_ALARM_BROADCAST_ID = 0;
#Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
System.out.println("Grade notification services started");
context = getApplicationContext();
final Intent completeWakefulIntent = intent;
if(gradesChanged()){
getAssignments();
}
ServiceAlarmReceiver.completeWakefulIntent(completeWakefulIntent);
}
private boolean gradesChanged() {
//Massive blocks of code that will take you forever to read
}
private void getAssignments(){
//Massive blocks of code that will take you forever to read
//It is in this method that sendNotification() is used to send a notification
//(at least that's what it's supposed to be doing)
}
private void sendNotification(String title, String message){
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);
mBuilder.setSmallIcon(R.drawable.ic_launcher);
mBuilder.setContentTitle(title);
mBuilder.setContentText(message);
mBuilder.setDefaults(NotificationCompat.DEFAULT_SOUND);
mBuilder.setAutoCancel(true);
Intent resultIntent = new Intent(context, MainInterface.class);
PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent, 0);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(1, mBuilder.build());
}
private boolean networkIsAvailable() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
// return netInfo != null && netInfo.isConnectedOrConnecting();
NetworkInfo mWifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return netInfo != null && netInfo.isConnectedOrConnecting()
|| mWifi.isConnected();
}
}
Can anyone tell me what I can do to make this service run when the phone is asleep, or why it is not sending any notifications? Any help is appriciated.
Edit:
This is most of the manifest. The target sdk is 21 and the minimum is 11:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:label="#string/app_name"
android:icon="#drawable/ic_launcher">
<service
android:name="com.example.ahsandroidapplication.GradeNotificationService"
android:enabled="true" >
<intent-filter>
<action android:name="com.example.ahsandroidapplication.ServiceAlarmReceiver" />
</intent-filter>
</service>
<receiver android:name=".ServiceAlarmReceiver"
android:enabled="true">
<intent-filter>
<action android:name="com.example.ahsandroidapplication.servicealarmbroadcast"></action>
</intent-filter>
</receiver>
<receiver android:name=".BootReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
<activity
android:name="MainInterface"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="MainLogin"
android:label="#string/app_name">
</activity>
<service android:enabled="true"
android:exported="false"
android:isolatedProcess="false"
android:label="#string/app_name"
android:name="AspenManager" >
</service>
</application>
"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."
http://developer.android.com/reference/android/app/AlarmManager.html
Related
I'm trying to find out how to run a service (Any service, may be foreground or background) when device boots. I've tried implementing broadcast receiver but it seems not to work.
Below is my full code.
1.AndroidManifext.xml - I made sure I included the service and broadcast receiver here. Are there any permissions I may be lacking?
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.testboot">
<!-- Example need below permission. -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.example.testboot.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.example.testboot.BootDeviceReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<service
android:name="com.example.testboot.RunAfterBootService"
android:enabled="true"
android:exported="true"></service>
</application>
</manifest>
2.MainActivity.java - This is the launch class, I made it call the broadcast receiver class. Asides from that, it doesn't have anything else.
package com.example.testboot;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent("com.example.testboot.BootDeviceReceiver");
sendBroadcast(intent);
}
}
3.BootDeviceReceiver.java -This is the class responsible for knowing when device has booted up (Extends Broadcast receiver)
package com.example.testboot;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
public class BootDeviceReceiver extends BroadcastReceiver {
private static final String TAG_BOOT_BROADCAST_RECEIVER = "BOOT_BROADCAST_RECEIVER";
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String message = "BootDeviceReceiver onReceive, action is " + action;
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
Log.d(TAG_BOOT_BROADCAST_RECEIVER, action);
if(Intent.ACTION_BOOT_COMPLETED.equals(action))
{
//startServiceDirectly(context);
startServiceByAlarm(context);
}
}
/* Start RunAfterBootService service directly and invoke the service every 10 seconds. */
private void startServiceDirectly(Context context)
{
try {
while (true) {
String message = "BootDeviceReceiver onReceive start service directly.";
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
Log.d(TAG_BOOT_BROADCAST_RECEIVER, message);
// This intent is used to start background service. The same service will be invoked for each invoke in the loop.
Intent startServiceIntent = new Intent(context, RunAfterBootService.class);
context.startService(startServiceIntent);
// Current thread will sleep one second.
Thread.sleep(10000);
}
}catch(InterruptedException ex)
{
Log.e(TAG_BOOT_BROADCAST_RECEIVER, ex.getMessage(), ex);
}
}
/* Create an repeat Alarm that will invoke the background service for each execution time.
* The interval time can be specified by your self. */
private void startServiceByAlarm(Context context)
{
// Get alarm manager.
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
// Create intent to invoke the background service.
Intent intent = new Intent(context, RunAfterBootService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long startTime = System.currentTimeMillis();
long intervalTime = 60*1000;
String message = "Start service use repeat alarm. ";
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
Log.d(TAG_BOOT_BROADCAST_RECEIVER, message);
// Create repeat alarm.
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalTime, pendingIntent);
}
}
3.RunAfterBootService.java - This is the service class, should be displayed after device completes booting up.
package com.example.testboot;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
public class RunAfterBootService extends Service {
private static final String TAG_BOOT_EXECUTE_SERVICE = "BOOT_BROADCAST_SERVICE";
public RunAfterBootService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG_BOOT_EXECUTE_SERVICE, "RunAfterBootService onCreate() method.");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String message = "RunAfterBootService onStartCommand() method.";
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
Log.d(TAG_BOOT_EXECUTE_SERVICE, "RunAfterBootService onStartCommand() method.");
Intent i = new Intent();
i.setClass(RunAfterBootService.this,MainActivity.class);
startActivity(i);
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
So far, when I restart my device nothing happens at all.
Has your app an icon ? you must open your app one time then you can receive the boot_complete broadcast.
My application should send notifications at the specified time.
I wrote a service that uses AlarmManager, a receiver that restarts it if you close the application. The service is restarted (as can be seen in the logs), but AlarmManager does not work (the receiver does not receive an intent from it) while the application is closed. I also tried to register the receiver in the service code - it still does not work (
AlarmService - foreground service. AlarmSetter - class to set Alarms.
AlarmReceiver - receiver to send notifications (has log: intent received)
Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="net.ozero.drugsreminder"
android:installLocation="internalOnly">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.QUICKBOOT_POWERON" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
>
<activity android:name=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.AddPrescActivity"
android:label="#string/label_add_presc_activity"
android:parentActivityName=".activities.MainActivity"
android:theme="#style/ActionBarTheme"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".activities.AddDrugActivity"
android:label="#string/label_add_drug_activity"
android:parentActivityName=".activities.AddPrescActivity"
android:theme="#style/ActionBarTheme"
android:windowSoftInputMode="stateVisible">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".activities.AlarmActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name=".services.AlarmService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="net.ozero.drugsreminder.services.AlarmService.MarkEvent" />
<action android:name="net.ozero.drugsreminder.services.AlarmService.SetLater" />
</intent-filter>
</service>
<receiver
android:name=".services.AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="net.ozero.drugsreminder.services.AlarmReceiver" />
</intent-filter>
</receiver>
<receiver
android:name=".services.RestartAlarmServiceReceiver"
android:enabled="true"
android:exported="true">
</receiver>
<receiver
android:name=".services.BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
</application>
</manifest>
AlarmService:
package net.ozero.drugsreminder.services;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import net.ozero.drugsreminder.alarm.AlarmSetter;
import net.ozero.drugsreminder.database.DBHelper;
import net.ozero.drugsreminder.datastructure.Event;
import net.ozero.drugsreminder.formatters.AlarmMessageBuilder;
import java.util.List;
import static net.ozero.drugsreminder.App.*;
import static net.ozero.drugsreminder.App.EXTRA_ALARM_ID;
/**TODO alarm repeating (bug) */
public class AlarmService extends Service {
public AlarmService() {
}
public DBHelper mDBHelper;
public AlarmReceiver mAlarmReceiver;
public AlarmManager mAlarmManager;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("AlarmService:", "on start");
// mAlarmReceiver = new AlarmReceiver();
mDBHelper = new DBHelper(this);
//set event is done
if (isMarkAction(intent)) {
markEvent(intent);
}
//set event to alarm later
if (isSetLaterAction(intent)) {
setEventLater(intent);
}
setAlarms();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.i("AlarmService:", "on removed");
sendBroadcast(new Intent(this, RestartAlarmServiceReceiver.class));
Log.i(getClass().getName(), "OnTaskRemoves: broadcast sent");
super.onTaskRemoved(rootIntent);
}
private boolean isMarkAction(Intent intent) {
return (
intent != null
&& intent.getAction() != null
&& intent.getAction().equals(ACTION_MARK_EVENT)
);
}
private boolean isSetLaterAction(Intent intent) {
return (
intent != null
&& intent.getAction() != null
&& intent.getAction().equals(ACTION_SET_LATER)
);
}
private void setEventLater(Intent intent) {
int id = intent.getIntExtra(EXTRA_ALARM_ID, 0);
mDBHelper.setEventLater(id, ALARM_INTERVAL);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
assert notificationManager != null;
notificationManager.cancel(id);
Log.i("AlarmService:", "event time set later : " + id);
}
private void markEvent(Intent intent) {
int id = intent.getIntExtra(EXTRA_ALARM_ID, 0);
mDBHelper.markEvent(id);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
assert notificationManager != null;
notificationManager.cancel(id);
Log.i("AlarmService:", "event is marked, id : " + id);
}
private void setAlarms() {
mDBHelper = new DBHelper(this);
List<Event> events = mDBHelper.getActualEvents();
Log.i("AlarmService:setAlarms:", "actual (not marked) events size:" + String.valueOf(events.size()));
AlarmSetter alarmSetter = new AlarmSetter(this);
AlarmMessageBuilder alarmMessageBuilder = new AlarmMessageBuilder(mDBHelper);
for (Event event : events) {
long timeMillis = event.getReceptionDateTime().getTime();
String message = alarmMessageBuilder.getMessage(event);
int id = event.getId();
alarmSetter.setAlarm(timeMillis, message, id);
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(getClass().getName(), "onDestroy");
}
}
AlarmSetter:
package net.ozero.drugsreminder.alarm;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import net.ozero.drugsreminder.services.AlarmReceiver;
import static net.ozero.drugsreminder.App.EXTRA_ALARM_ID;
import static net.ozero.drugsreminder.App.EXTRA_ALARM_MESSAGE;
public class AlarmSetter {
//one minute timeout
public static final long DEFAULT_ALARM_TIMEOUT = 60*1000L;
private Context mContext;
private AlarmManager mAlarmManager;
public AlarmSetter(Context applicationContext) {
mContext = applicationContext;
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Log.i("AlarmSetter:", "alarm manager:" + mAlarmManager);
}
//main method
public void setAlarm(long timeMillis, String message, int id) {
//creating intent for alarm message
Intent intent = new Intent("net.ozero.drugsreminder.services.AlarmReceiver");
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.putExtra(EXTRA_ALARM_MESSAGE, message);
intent.putExtra(EXTRA_ALARM_ID, id);
//creating pending intent
PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext.getApplicationContext(), id, intent, 0);
//setting alarm
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mAlarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
timeMillis,
pendingIntent
);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mAlarmManager.setExact(
AlarmManager.RTC_WAKEUP,
timeMillis,
pendingIntent
);
} else {
mAlarmManager.set(
AlarmManager.RTC_WAKEUP,
timeMillis,
pendingIntent
);
}
Log.i("AlarmSetter:" , "alarm set");
}
}
AlarmReceiver:
package net.ozero.drugsreminder.services;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import net.ozero.drugsreminder.alarm.NotificationSetter;
import static net.ozero.drugsreminder.App.EXTRA_ALARM_ID;
import static net.ozero.drugsreminder.App.EXTRA_ALARM_MESSAGE;
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("AlarmReceiver:", "notification received");
String message = intent.getStringExtra(EXTRA_ALARM_MESSAGE);
int id = intent.getIntExtra(EXTRA_ALARM_ID, 1);
NotificationSetter notificationSetter = new NotificationSetter(context);
notificationSetter.setNotification(message, id);
}
}
You have to run your service as a real foreground service so that it will survive even if your app has been closed or finished.
This is a very simple sample from http://www.vogella.com/tutorials/AndroidServices/article.html:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
I searched a lot but I couldn't find an answer for my specific problem, so I'm asking my own question.
The Problem:
I'm programming an app where a user can set multiple alarms with different repeating intervals. But when I create an Alarm object the app crashes.
Every time the user clicks a button the Alarm class is called with:
Alarm b = new Alarm(name, intervall, 23, 30, 15, 6, 2016);
This is my Alarm class:
package witty.de.witty;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.IBinder;
import java.util.Calendar;
public class Alarm extends Activity {
public Alarm(String name, int intervall, int stunden, int minuten, int tag, int monat, int jahr) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, jahr);
cal.set(Calendar.MONTH, (monat - 1));
cal.set(Calendar.DAY_OF_MONTH, tag);
cal.set(Calendar.HOUR_OF_DAY, stunden);
cal.set(Calendar.MINUTE, minuten);
cal.set(Calendar.SECOND, 0);
Intent myIntent = new Intent(Alarm.this, AlarmReceiver.class);
final int _id = (int) System.currentTimeMillis();
myIntent.setData(Uri.parse("reminder:" + _id));
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, _id, myIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, cal.getTimeInMillis(), intervall * AlarmManager.INTERVAL_DAY,
pendingIntent);
}
}
And this is my NotificationService class:
package witty.de.witty;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;
import java.util.logging.Logger;
import witty.de.witty.MainActivity;
import witty.de.witty.R;
public class NotificationService extends Service {
private NotificationManager mManager;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Toast mToast = Toast.makeText(
this,
"Reminders added to the calendar successfully for ",
Toast.LENGTH_LONG);
mToast.show();
// Getting Notification Service
mManager = (NotificationManager) this.getApplicationContext()
.getSystemService(this.getApplicationContext().NOTIFICATION_SERVICE);
Intent intent1 = new Intent(this.getApplicationContext(),
MainActivity.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity(
this.getApplicationContext(), 0, intent1,
PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Witty2")
.setContentIntent(pendingNotificationIntent)
.setContentText("Errinerung!!");
mManager.notify(0, mBuilder.build());
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
This is my AlarmReceiver class:
package witty.de.witty;
import android.app.NotificationManager;
import android.content.Context;
import android.support.v4.app.NotificationCompat;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(context, NotificationService.class);
context.startService(myIntent);
}
}
And this is my AndroidManifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="witty.de.witty">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Erstellen"></activity>
<activity android:name=".Impressum"></activity>
<activity android:name=".Startseite"></activity>
<service android:name=".NotificationService"></service>
<receiver android:name=".AlarmReceiver" android:process=":remote"></receiver>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
If you need more code or more information, just ask me.
My solution:
Call the Alarm class with a new intent not as an Object:
Intent intent = new Intent(this, Alarm.class);
startActivity(intent);
This is my first time trying to make an app that starts on boot and runs in the background, and I'm finding all the possible ways of doing it a little confusing. I need the app to do a quick check of a few things every half hour, and sleep in between, so I settled for using AlarmManager and setRepeating.
In this test I've set it up so a boot receiver sets the alarm, which should run a service every 60 seconds (actual app will be 30+ mins between running this). The service triggers a notification, but when I reboot the phone, the notification only shows up once. I clear it and never see it again.
I'll post the relevant code below. Can anyone tell me where I'm going wrong? Thanks!
AlarmStarter.java
public class AlarmStarter extends BroadcastReceiver {
private static final int PERIOD = 60000;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
scheduleAlarms(context);
}
}
static void scheduleAlarms(Context ctxt) {
AlarmManager mgr = (AlarmManager) ctxt.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(ctxt, BackService.class);
PendingIntent pi = PendingIntent.getService(ctxt, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + PERIOD, PERIOD, pi);
}
BackService.java
public class BackService extends Service {
public BackService() {
//showNotification("ticker test", "title test", "content test", "http://google.com");
Log.d("CF", "Starting BackService");
showNotification("ticker test", "title test", "content test", "http://google.com");
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
// Code to execute when the service is first created
}
public void showNotification(String ticker, String title, String content, String url) {
Intent notificationIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
PendingIntent pi = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this).setTicker(ticker)
.setSmallIcon(android.R.drawable.ic_menu_report_image)
.setContentTitle(title)
.setContentText(content)
.setContentIntent(pi)
.setAutoCancel(true)
.build();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testapp.test" >
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver
android:name=".AlarmStarter"
android:enabled="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name=".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>
<service
android:name=".BackService"
android:enabled="true"
android:exported="true" ></service>
</application>
</manifest>
The problem I had here was that the BackService class I was trying to trigger with the alarm, was extending from the Service class. It should have extended from the BroadcastReceiver class, as only BroadcastReceivers can be triggered by the externally sent alarms.
I'm implementing push notification service i my app, I followed the tutorial on Android developers.com, but unfortunately, i did not receive any notifications.
I'm receiving the registration id successfully, but,the device doesn't receive any notifications from the back end, although the back ed service receives a successful response.
p.s : I'm sure from the implementation of the back end service that sends the notification to Google cloud servers.
Could any one help me solving this problem..?, thanks in advance.
Below you can find my implementation.
The Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ettamen.app"
android:versionCode="1"
android:versionName="1.0" >
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<!-- GCM connects to Internet Services. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Creates a custom permission so only this app can receive its messages. -->
<permission
android:name="com.ettamen.app.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.ettamen.app.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Network State Permissions to detect Internet status -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Permission to vibrate -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<application
android:hardwareAccelerated="true"
android:icon="#drawable/icon"
android:label="#string/app_name" >
<activity
android:name="Ettamen"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
android:label="#string/app_name"
android:theme="#android:style/Theme.Black.NoTitleBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.ettamen.app.pushnotifications.CordovaGCMBroadcastReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.ettamen.app.pushnotifications" />
</intent-filter>
</receiver>
<service android:name="com.ettamen.app.pushnotifications.GCMIntentService" >
</service>
<activity android:name=".pushnotifications.PushHandlerActivity" >
</activity>
<service android:name="LocationUpdateService" >
</service>
</application>
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
</manifest>
MyReceiver.java
import com.ettamen.app.R;
import com.google.android.gms.gcm.GoogleCloudMessaging;
/*
* Implementation of GCMBroadcastReceiver that hard-wires the intent service to be
* com.plugin.gcm.GCMIntentService, instead of your_package.GCMIntentService
*/
public class CordovaGCMBroadcastReceiver extends BroadcastReceiver {
static final String TAG = "GCMDemo";
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
Context ctx;
#Override
public void onReceive(Context context, Intent intent) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
ctx = context;
String messageType = gcm.getMessageType(intent);
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error: " + intent.getExtras().toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
.equals(messageType)) {
sendNotification("Deleted messages on server: "
+ intent.getExtras().toString());
} else {
sendNotification("Received: " + intent.getExtras().toString());
}
setResultCode(Activity.RESULT_OK);
}
// Put the GCM message into a notification and post it.
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager) ctx
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
new Intent(ctx, PushHandlerActivity.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
ctx).setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("GCM Notification")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
GCM Intent Service
import android.app.ActivityManager.RunningTaskInfo;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
public class GCMIntentService extends GCMBaseIntentService {
public static final int NOTIFICATION_ID = 237;
private static final String TAG = "GCMIntentService";
public GCMIntentService() {
super("GCMIntentService");
}
#Override
public void onRegistered(Context context, String regId) {
}
#Override
public void onUnregistered(Context context, String regId) {
}
#Override
protected void onMessage(Context context, Intent intent) {
Log.d(TAG, "onMessage - context: " + context);
// Extract the payload from the message
Bundle extras = intent.getExtras();
if (extras != null) {
createNotification(context, extras);
}
}
public void createNotification(Context context, Bundle extras) {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String appName = getAppName(this);
Intent notificationIntent = new Intent(this, PushHandlerActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
notificationIntent.putExtra("pushBundle", extras);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
context).setSmallIcon(context.getApplicationInfo().icon)
.setWhen(System.currentTimeMillis()).setContentTitle(appName)
.setTicker(appName).setContentIntent(contentIntent);
String message = extras.getString("message");
if (message != null) {
mBuilder.setContentText(message);
} else {
mBuilder.setContentText("<missing message content>");
}
String msgcnt = extras.getString("msgcnt");
if (msgcnt != null) {
mBuilder.setNumber(Integer.parseInt(msgcnt));
}
mNotificationManager.notify((String) appName, NOTIFICATION_ID,
mBuilder.build());
tryPlayRingtone();
}
private void tryPlayRingtone() {
try {
Uri notification = RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(),
notification);
r.play();
} catch (Exception e) {
Log.e(TAG, "failed to play notification ringtone");
}
}
public static void cancelNotification(Context context) {
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel((String) getAppName(context),
NOTIFICATION_ID);
}
private static String getAppName(Context context) {
CharSequence appName = context.getPackageManager().getApplicationLabel(
context.getApplicationInfo());
return (String) appName;
}
public boolean isInForeground() {
ActivityManager activityManager = (ActivityManager) getApplicationContext()
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> services = activityManager
.getRunningTasks(Integer.MAX_VALUE);
if (services.get(0).topActivity
.getPackageName()
.toString()
.equalsIgnoreCase(
getApplicationContext().getPackageName().toString()))
return true;
return false;
}
#Override
public void onError(Context context, String errorId) {
Log.e(TAG, "onError - errorId: " + errorId);
}
}
- PushHandlerActivity
package com.ettamen.app.pushnotifications;
import com.ettamen.app.PushNotificationWorker;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
public class PushHandlerActivity extends Activity {
private static String TAG = "PushHandlerActivity";
/*
* this activity will be started if the user touches a notification that we
* own. We send it's data off to the push plugin for processing. If needed,
* we boot up the main activity to kickstart the application.
*
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate");
boolean isPushPluginActive = PushNotificationWorker.isActive();
if (!isPushPluginActive) {
forceMainActivityReload();
}
// processPushBundle(isPushPluginActive);
GCMIntentService.cancelNotification(this);
finish();
}
/**
* Takes the pushBundle extras from the intent, and sends it through to the
* PushPlugin for processing.
*/
private void processPushBundle(boolean isPushPluginActive) {
// Bundle extras = getIntent().getExtras();
//
// if (extras != null) {
//
// Bundle originalExtras = extras.getBundle("pushBundle");
//
// if ( !isPushPluginActive ) {
// originalExtras.putBoolean("coldstart", true);
// }
//
// PushPlugin.sendExtras(originalExtras);
// }
}
/**
* Forces the main activity to re-launch if it's unloaded.
*/
private void forceMainActivityReload() {
PackageManager pm = getPackageManager();
Intent launchIntent = pm
.getLaunchIntentForPackage(getApplicationContext()
.getPackageName());
startActivity(launchIntent);
}
}
- My Registration code in the Main activity:
private void getRegID(CallbackContext ctx) {
new AsyncTask<CallbackContext, Void, String>() {
CallbackContext context;
#Override
protected String doInBackground(CallbackContext... params) {
// TODO Auto-generated method stub
context = params[0];
String regid = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(cordova
.getActivity());
}
regid = gcm.register(Constants.SENDER_ID);
} catch (IOException ex) {
Log.d("Exceptio:", ex.getMessage());
}
String message = "{\"ChannelURI\":\"" + regid + "\"}";
return message;
};
protected void onPostExecute(String result) {
try {
JSONObject jResult = new JSONObject(result);
context.success(jResult);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.execute(ctx);
}
There are package name mismatches throughout your manifest :
The package of the app :
package="com.ettamen.app"
In the permissions, you should use the package of the app, but instead you used :
<permission
android:name="com.ettamen.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.ettamen.permission.C2D_MESSAGE" />
Both should be com.ettamen.app.permission.C2D_MESSAGE.
Finally, the broadcast receiver :
<receiver
android:name="com.ettamen.app.pushnotifications.CordovaGCMBroadcastReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.ettamen.app.pushnotifications" />
</intent-filter>
</receiver>
The category should contain your app package name, so it should be com.ettamen.app.
After a lot of trials, i found out the problem which was that The receiver can be in whatever package you like, as long as the category of its intent filter in the manifest holds the application's main package
Thank you all for your help and support.
When you are building the notificaiton with builder, you should set the intent passed to the onReceive method, not the one you created, here:
mBuilder.setContentIntent(contentIntent);
Complete code:
import com.ettamen.app.R;
import com.google.android.gms.gcm.GoogleCloudMessaging;
/*
* Implementation of GCMBroadcastReceiver that hard-wires the intent service to be
* com.plugin.gcm.GCMIntentService, instead of your_package.GCMIntentService
*/
public class CordovaGCMBroadcastReceiver extends BroadcastReceiver {
static final String TAG = "GCMDemo";
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
Context ctx;
#Override
public void onReceive(Context context, Intent intent) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
ctx = context;
String messageType = gcm.getMessageType(intent);
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error: " + intent.getExtras().toString(), intent);
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
.equals(messageType)) {
sendNotification("Deleted messages on server: "
+ intent.getExtras().toString(), intent);
} else {
sendNotification("Received: " + intent.getExtras().toString(), intent);
}
setResultCode(Activity.RESULT_OK);
}
// Put the GCM message into a notification and post it.
private void sendNotification(String msg, Intent intent) {
mNotificationManager = (NotificationManager) ctx
.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
ctx).setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("GCM Notification")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(intent); // here passing the valid intent
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
It can be applied to the class GCMIntentService too.