app crashes when alarm triggers if app is closed - android

Get Exception :
Caused by: android.database.sqlite.SQLiteException: no such table:
TABLE_USER_RITUALS (code 1): , while compiling: Select * from
TABLE_USER_RITUALS where USER_NAME = 'vxfbb' and RITUAL_NAME =
'Morning Routine'
But the database is exists as the code works fine if the app is opened in background, it got crashed when app is removed from the background
Broadcast Receiver Class:
public class AlarmReceiver extends BroadcastReceiver
{
String h_id, habit, habit_desc, habit_time;
//public static Ringtone ringtone;
#Override
public void onReceive(Context mContext, Intent arg1)
{
String selectedRitual = arg1.getExtras().getString(AppsConstant.SELECTED_RITUAL);
String userName = arg1.getExtras().getString(AppsConstant.user_name);
// Enable {#code SampleBootReceiver} to automatically restart the alarm when the
// device is rebooted.
ComponentName receiver = new ComponentName(mContext, SampleBootReceiver.class);
PackageManager pm = mContext.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,PackageManager.DONT_KILL_APP);
//get data from database
GetData getData = new GetData();
UserRitualModel userReminderSetting = getData.getRitualsDetails(userName, selectedRitual);
int isfullScreen = userReminderSetting.getNotificationStyle();
int ringInSilent = userReminderSetting.getRingInSilent();
if(ringInSilent ==TableAttributes.ON)
{
final AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM);
audioManager.setStreamVolume(AudioManager.STREAM_ALARM, maxVolume,AudioManager.FLAG_ALLOW_RINGER_MODES);
}
Intent i;
if(isfullScreen==TableAttributes.ON)
{
i = new Intent(mContext, ReminderFullScreen.class);
}
else
{
i = new Intent(mContext, Reminder.class);
}
// i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra(AppsConstant.SELECTED_RITUAL, selectedRitual);
i.putExtra(AppsConstant.user_name, userName);
mContext.getApplicationContext().startActivity(i);
}
}

I have got the answer :
You will need the context,for calling the database which you have as part of the BroadcastReceiver onReceive method signature and that's it.
for refrence :
how can i access database from broadcast receiver in android?

Related

Stop Service from PendingIntent after Notifcation is opened

I want the service to perform a stopForeground and a stopSelf after the notification is clicked followed by the running of pendingIntent.
I have tried using a BroadcastReceiver which is never called as I checked during debugging. I have added it to manifest as well.
Intent intentHide = new Intent(this, StopServiceReceiver.class);
PendingIntent hide = PendingIntent.getBroadcast(this, (int) System.currentTimeMillis(), intentHide, PendingIntent.FLAG_CANCEL_CURRENT);
Added it to the builder
builder.setContentIntent(hide);
And the Broadcast Rec is done separately -
public class StopServiceReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 333;
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, TimerService.class);
context.stopService(service);
}
}
Manifest -
<receiver
android:name=".StopServiceReceiver"
android:enabled="true"
android:process=":remote" />
This is not working. The notification and the service both are alive.
Questions - Should I use addContent instead of setContentIntent ? If yes, then what should the parameters be ?
Is there anything I went wrong with? What could possibly be wrong with such kind of implementation? Thank you.
I had the same problem in the notification.
This code is working perfectly.
void creatnotifiaction()
{
public static final String STOP = "com.example.android";
public static final int REQUEST_CODE = 333;
filter = new IntentFilter();
filter.addAction(STOP);
Intent intentHide = new Intent(STOP);
PendingIntent hide = PendingIntent.getBroadcast(this,REQUEST_CODE,intentHide,PendingIntent.FLAG_CANCEL_CURRENT);
registerReceiver(broadcastReceiver, filter);
}
There no need to separate broadcast receiver use in same class.
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#SuppressLint("ResourceAsColor")
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d("notification", "Received intent with action " + action);
switch (action) {
case STOP:
//your code to stop notifications or service.
break;
}
});
Let me know if that work for you.
Thanks...Happy coding.

How to stop alarm from executing after PendingIntent has been received - Android

Before closing this issue or marking as duplicate based on the title, it is different from the regular "cancel alarm using AlarmManager and PendingIntent" questions.
I am capable of creating and cancelling pending intents, as long as they are set for a time in the future and haven't gone off yet. I'm testing this using the following terminal command to view the PendingIntents before creating an alarm as well as after:
adb shell dumpsys alarm
Here is my code for scheduling alarms in my custom Alarm class:
/**
* Schedules a PendingIntent for the alarm.
* #param context Activity context
*/
public void scheduleAlarm(Context context) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyBroadcastReceiver.class);
Gson g = new Gson();
String s = g.toJson(this);
intent.putExtra("alarm", s);
String id = this.getId().replaceAll("[^0-9]+", "");
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, Integer.parseInt(id), intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, this.getHour());
calendar.set(Calendar.MINUTE, this.getMinute());
long calendarTime = calendar.getTimeInMillis();
am.setExact(AlarmManager.RTC_WAKEUP, calendarTime, alarmIntent);
}
Not surprisingly, before creating an alarm, there was no pending intent regarding my app's alarms in the terminal output. After creating the alarm, there was 1 pending intent related to my app in the terminal output, as seen below:
+Batch{b28a2db num=1 start=619295497 end=619385497}: + RTC #0: Alarm{24e4178 tag
alarm:com.google.android.location.internal.action.ULR_BAROMETER_READ_ALARM type 1 when 1501206840000 com.google.android.gms} +
tag=alarm:com.google.android.location.internal.action.ULR_BAROMETER_READ_ALARM + type=1 whenElapsed=+1m59s428ms when=2017-07-27 21:54:00 + window=+1m30s0ms repeatInterval=120000 count=0 flags=0x0 +
operation=PendingIntent{cb99ddd: PendingIntentRecord{f0fbd52
com.google.android.gms startService}}
Note I don't have access to my home computer right now so I can't post exactly what it will be for my app, so I just grabbed the PendingIntent for a different app but it is the same structure.
I cancelled the alarm before it went off using the code found below, reran the adb command from before and the pending intent was no longer in the terminal output so everything worked great.
Here is my code for cancelling alarms:
/**
* Cancels the PendingIntent for the alarm.
* #param context
*/
public void cancelAlarm(Context context) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyBroadcastReceiver.class);
intent.putExtra("alarm", this);
String id = this.getId().replaceAll("[^0-9]+", "");
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, Integer.parseInt(id), intent, 0);
alarmIntent.cancel();
am.cancel(alarmIntent);
}
Now, if the PendingIntent was reached (BroadcastReceiver runs its onReceive() code and opens a custom activity), I get the following entry in the terminal output when I rerun that adb command:
u0a149:com.my.app +172ms running, 0 wakeups:
+172ms 0 wakes 3 alarms, last -5d8h25m0s423ms:
alarm:com.google.firebase.INSTANCE_ID_EVENT
but I can no longer see the PendingIntent, as expected. Whether I run the cancelAlarm() code or not, this entry will always stay here.
The result of this is that whenever I open the app after the PendingIntent has "gone off" and my BroadcastReceiver class runs it's code, the app acts as if the alarm is continually going off so it does this repeatedly, but like I said there's no PendingIntent entry in the adb output. I want to know how to shut this alarm off or "dismiss" it if you will.
Here is my BroadcastReceiver class:
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String alarm = intent.getStringExtra("alarm");
Intent myIntent = new Intent();
Toast.makeText(context, "Alarm is 1: " + alarm, Toast.LENGTH_SHORT).show();
myIntent.setClassName("com.my.package.name", "com.my.package.name.AlarmReceivedActivity");
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
myIntent.putExtra("alarm", alarm);
context.startActivity(myIntent);
}
}
and here's my AlarmReceivedActivity:
public class AlarmReceivedActivity extends AppCompatActivity {
private Alarm alarmReceived;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm_received);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
TextView tvTime = (TextView) findViewById(R.id.tv_time);
String lTime = "11:05";
tvTime.setText(lTime);
Intent intent = getIntent();
String s = intent.getStringExtra("alarm");
Toast.makeText(getApplicationContext(), "Alarm is: " + s, Toast.LENGTH_SHORT).show();
Gson g = new Gson();
alarmReceived = g.fromJson(s, Alarm.class);
Uri ringtoneUri = Uri.parse(alarmReceived.getRingtone());
Toast.makeText(getApplicationContext(), "Ringtone is: " + alarmReceived.getRingtone(), Toast.LENGTH_SHORT).show();
try {
MediaPlayer mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(this, ringtoneUri);
final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mMediaPlayer.setLooping(false);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Failed to play ringtone", Toast.LENGTH_SHORT).show();
}
}
public void dismissButtonClick(View view) {
Context context = getApplicationContext();
alarmReceived.cancelAlarm(context);
alarmReceived.setIsSet(false);
writeAlarmToSharedPrefs(alarmReceived, context);
alarmReceived.cancelAlarm(context);
System.exit(0);
}
private void writeAlarmToSharedPrefs(Alarm alarmReceived, Context context) {
String alarm = getAlarmObjectAsJson(alarmReceived);
SharedPreferences sPrefs = getApplicationContext().getSharedPreferences("Sleepin", MODE_PRIVATE);
SharedPreferences.Editor pe = sPrefs.edit();
pe.putString(alarmReceived.getId(), alarm);
pe.apply();
}
private String getAlarmObjectAsJson(Alarm a) {
Gson g = new Gson();
return g.toJson(a);
}
public void snoozeButtonClick(View view) {
}
}
So I have a couple questions:
1) Since the PendingIntent has been reached, what is this entry in the adb command output referred to as? A "ReachedPendingIntent" (obviously not called this but I hope you get where I'm going with this).
2) How do I stop my app from running the BroadcastReceiver code? My workaround right now is to clear the app's data and cache. After I do this, the second entry from the adb command doesn't appear and the BroadcastReceiver stops running it's code.

How to pass the extras to intent when the application gets launched using Alarm Manager?

In the application which i'm developing, i'm having an alarm manager which will launch the application in particular time. During this process, i'm passing a string as the part of intents as shown below.
Intent LaunchIntent = context.getPackageManager().getLaunchIntentForPackage("Application Package Name");
String strName = "Preferences";
LaunchIntent.putExtra("STRING_NAME", strName);
context.startActivity(LaunchIntent);
It is opening the application. But in the when i do intent.getStringExtra("STRING_NAME"), in the onCreate() method of the Homescreen, the passed string value is not coming.
In this class i'm initializing the alarm manager for every 40 seconds as shown below in the onCreate method:
private static void SetScheduleSync(Context context) {
Intent downloader = new Intent(context, ScheduleSyncManager.class);
PendingIntent recurringDownload = PendingIntent.getBroadcast(context, 1000, downloader, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
int interval = 10000*4;
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, recurringDownload);
}
Inside the ScheduleSyncManager.class, i have written code to open up the application by passing the extras as the pert of intent. When the application opens up, i checking whether is there any extra data in the particular intent.
Here is the ScheduleManagerDeclaration:
public class ScheduleSyncManager extends WakefulBroadcastReceiver {
public Boolean IsCustomizingPresent = false;
String strName = "Preferences";
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Sync in the background has Started", Toast.LENGTH_SHORT).show();
performScheduleSync(context, intent);
}
public void performScheduleSync(Context context, Intent intent) {
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage("com.sap.rex.ui");
launchIntent.putExtra("STRING_NAME", strName);
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(launchIntent);
}
And i'm calling the ScheduleManager from function SetScheduleSync() in Oncreate() method as i posted the code below.
Please help me with this. Is it possible to do like this?
Thanks.
Try the following:
LaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
P.S. It's a common practice to make the first letters of the instances lower case., i.e., not LaunchIntent but launchIntent.

Improve BroadcastReceiver + AlarmManager

I am experiencing some lag/black screen in my application since I start using AlarmManager + BroadcastReceiver. I have 2 BroadcastReceivers, one to when the phone gets restarted and another that AlarmManager call in the given period of time to send data to the server.
This is the code for BootReceiver to start the alarmManager once the cellphone is rebooted (it is working so far):
private final String BOOT_COMPLETED_ACTION = "android.intent.action.BOOT_COMPLETED";
#Override
public void onReceive(Context context, Intent intent) {
// when the boot is completed, restart the alarm manager
if(intent.getAction().equals(BOOT_COMPLETED_ACTION)){
SharedPreferences mPrefs = context.getSharedPreferences("GPS_TRACKING", Context.MODE_PRIVATE);
if (mPrefs.getBoolean("hasGeolocation", false) &&
!mPrefs.getBoolean("isThreadOn", false)){
EngineerTracker tracker = new EngineerTracker(context);
try {
tracker.startEngineerTrackingLocation();
} catch (ApplicationException e) {
e.printStackTrace();
}
}
}
}
The method to start and stop the alarm manager is this:
public void startEngineerTrackingLocation() throws ApplicationException{
PendingIntent pendingIntent = null;
AlarmManager manager = null;
ProjectGeospatialConfig geospatialConfig;
// check if the intent is running, if it is not, start it
if (PendingIntent.getBroadcast(context, 0,
new Intent(context, EngineerGeospatialTrackingReceiver.class),
PendingIntent.FLAG_NO_CREATE) == null){
// fetch the geospatial configuration, it may come null, so verify before using
geospatialConfig = getFirstFoundGeospatialConfiguration();
// if not null and use gps
if (geospatialConfig != null && geospatialConfig.isUseGps()){
// session information
SessionInformationDTO sessionInformation = dao.getObjectForKey(SqlLiteStorageKey.USER_INFORMATION);
Integer currentResourceId = sessionInformation.getSecurityHandler().getCurrentUser().getId();
// Retrieve a PendingIntent that will perform a broadcast and add resource id as extra
Intent alarmIntent = new Intent(context, EngineerGeospatialTrackingReceiver.class);
alarmIntent.putExtra("resourceId", currentResourceId.toString());
// set pending intent
if (pendingIntent == null){
pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
}
// set manager
if (manager == null){
manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
// set interval between alarms
int interval = (geospatialConfig.getGpsTrackingInterval() *1000) * 60;
// set alarm repetition
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
interval, pendingIntent);
// set variables for gps tracking
SharedPreferences mPrefs = getApplicationContext().getSharedPreferences("GPS_TRACKING", Context.MODE_PRIVATE);
Editor editor = mPrefs.edit();
// these variables will be measured once db is set
editor.putBoolean("hasExecuted", false);
editor.commit();
}
}
}
both are also working so far, the flag is meant to know when the service has been executed once and will not attempt again at the basic activity (template for all activitied)
The broadcast that is invoked in the alarm manager to send the information in the defined interval is this:
public class EngineerGeospatialTrackingReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String resourceId = intent.getStringExtra("id");
sendLocation(context, resourceId);
}
private void sendLocation(final Context context, final String resourceId){
new RemoteRequestTask<Void>(null, false, null) {
#Override
public Void executeTask() throws ApplicationException {
// working code
}
#Override
public void completed(Void refreshed) {
}
#Override
public void onException(final ApplicationException ex) {
}
}.start();
}}
Both receivers were added to the AndroidManifest. Beside the slowness, i also get a black screen when transitioning from an activity to another.
Use Traceview to determine where you are spending your time, and consider enabling StrictMode to point out where you are doing unfortunate things on the main application thread.
You want onReceive() to be very quick, ideally under 1ms, as. However, it looks like you might be doing database I/O in there (e.g., references to dao), which means that work should be handled off the main application thread, perhaps by an IntentService that you start from onReceive().

Android BroadcastReceiver and starting an intent

public class SessionManager extends BroadcastReceiver{
Date timeOff;
Date timeOn;
#Override
public void onReceive(Context context, Intent intent) {
if( "android.intent.action.SCREEN_OFF".equals(intent.getAction())) {
Log.i("MobileViaNetReceiver", "Screen off - start time to end session");
timeOff = Calendar.getInstance().getTime();
}
if( "android.intent.action.ACTION_SHUTDOWN".equals(intent.getAction())) {
// DO WHATEVER YOU NEED TO DO HERE
Log.i("MobileViaNetReceiver", "Shut down - log off user");
DbAdapter_User db = new DbAdapter_User(context);
db.open();
db.handleLogout();
db.close();
}
if( "android.intent.action.SCREEN_ON".equals(intent.getAction())) {
timeOn = Calendar.getInstance().getTime();
long diffInMs = timeOn.getTime()-timeOff.getTime();
// convert it to Minutes
long diffInMins = TimeUnit.MILLISECONDS.toMinutes(diffInMs);
if ((int) (diffInMins) > 15) {
//log out user
Log.i("MobileViaNetReceiver", "User inactive for 15 minutes - logout user");
DbAdapter_User db = new DbAdapter_User(context);
db.open(); // ******* HERE *************
db.handleLogout();
db.close();
} else {
Log.i("MobileViaNetReceiver", "User still active");
}
}
}
When the screen is turned ON I am checking if the user has turned scrren off for more than 15 mins, if yes, logout him. And go to LonIn screen.
I want to start an intent when I call that handleLogout() (marked * HERE **)
Can I do that when class extends BroadcastReceiver ? If no, what else can I do ?
You need to remember intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Blessings and happiness to the Google engineer who wrote the followint error message "E/AndroidRuntime( 2339): java.lang.RuntimeException: Unable to start receiver android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?"
public class AgeingAutoStartBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent(context,MyMainClass.class);
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent1);
);
}
}
Thanks to everyone who writes helpful messages here
Yes, you can do that. You just use the context that was passed into your onRecieve function when you're creating your Intent. Once you have the Intent, make this call:
Context.startActivity(yourIntent);
You certainly can. Try
Intent yourIntent = new Intent(context, YourActivity.class);
startActivity(yourIntent);
If you want to do it in your handleLogout method, pass in the Context.
private method handleLogout(Context context) {
...
}

Categories

Resources