I have simple reminder app. My app's problem is that when I restart my phone or any device, the app starts to throw up many notifications. This is the source code of all Java files. This is OnBootReceiver :
public class OnBootReceiver extends BroadcastReceiver {
private static final String TAG = ComponentInfo.class.getCanonicalName();
#Override
public void onReceive(Context context, Intent intent) {
ReminderManager reminderMgr = new ReminderManager(context);
RemindersDbAdapter dbHelper = new RemindersDbAdapter(context);
dbHelper.open();
Cursor cursor = dbHelper.fetchAllReminders();
if(cursor != null) {
cursor.moveToFirst();
int rowIdColumnIndex = cursor.getColumnIndex(RemindersDbAdapter.KEY_ROWID);
int dateTimeColumnIndex = cursor.getColumnIndex(RemindersDbAdapter.KEY_DATE_TIME);
while(cursor.isAfterLast() == false) {
Log.d(TAG, "Adding alarm from boot.");
Log.d(TAG, "Row Id Column Index - " + rowIdColumnIndex);
Log.d(TAG, "Date Time Column Index - " + dateTimeColumnIndex);
Long rowId = cursor.getLong(rowIdColumnIndex);
String dateTime = cursor.getString(dateTimeColumnIndex);
Calendar cal = Calendar.getInstance();
SimpleDateFormat format = new SimpleDateFormat(ReminderEditActivity.DATE_TIME_FORMAT);
try {
java.util.Date date = format.parse(dateTime);
cal.setTime(date);
reminderMgr.setReminder(rowId, cal);
} catch (java.text.ParseException e) {
Log.e("OnBootReceiver", e.getMessage(), e);
}
cursor.moveToNext();
}
cursor.close() ;
}
dbHelper.close();
}
}
And this is WakeReminderIntentService:
public abstract class WakeReminderIntentService extends IntentService {
abstract void doReminderWork(Intent intent);
public static final String LOCK_NAME_STATIC="com.dummies.android.taskreminder.Static";
private static PowerManager.WakeLock lockStatic=null;
public static void acquireStaticLock(Context context) {
getLock(context).acquire();
}
synchronized private static PowerManager.WakeLock getLock(Context context) {
if (lockStatic==null) {
PowerManager mgr=(PowerManager)context.getSystemService(Context.POWER_SERVICE);
lockStatic=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
LOCK_NAME_STATIC);
lockStatic.setReferenceCounted(true);
}
return(lockStatic);
}
public WakeReminderIntentService(String name) {
super(name);
}
#Override
final protected void onHandleIntent(Intent intent) {
try {
doReminderWork(intent);
}
finally {
//getLock(this).release();
}
}
}
Can you help me to cancel notification's after device's restart. In code there is told to schedule notification on specific time, but I am confused why after device's restart I get many notifications from app. Can someone tell me where is the mistake?
Update:
OnBootReceiver:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ComponentInfo;
import android.database.Cursor;
import android.util.Log;
public class OnBootReceiver extends BroadcastReceiver {
private static final String TAG = ComponentInfo.class.getCanonicalName();
#Override
public void onReceive(Context context, Intent intent) {
ReminderManager reminderMgr = new ReminderManager(context);
RemindersDbAdapter dbHelper = new RemindersDbAdapter(context);
dbHelper.open();
Cursor cursor = dbHelper.fetchAllReminders();
if(cursor != null) {
cursor.moveToFirst();
int rowIdColumnIndex = cursor.getColumnIndex(RemindersDbAdapter.KEY_ROWID);
int dateTimeColumnIndex = cursor.getColumnIndex(RemindersDbAdapter.KEY_DATE_TIME);
while(cursor.isAfterLast() == false) {
Log.d(TAG, "Adding alarm from boot.");
Log.d(TAG, "Row Id Column Index - " + rowIdColumnIndex);
Log.d(TAG, "Date Time Column Index - " + dateTimeColumnIndex);
Long rowId = cursor.getLong(rowIdColumnIndex);
String dateTime = cursor.getString(dateTimeColumnIndex);
Calendar cal = Calendar.getInstance();
SimpleDateFormat format = new SimpleDateFormat(ReminderEditActivity.DATE_TIME_FORMAT);
try {
java.util.Date date = format.parse(dateTime);
cal.setTime(date);
reminderMgr.setReminder(rowId, cal);
} catch (java.text.ParseException e) {
Log.e("OnBootReceiver", e.getMessage(), e);
}
cursor.moveToNext();
}
cursor.close() ;
}
dbHelper.close();
}
}
setReminder().method:
public void setReminder(Long taskId, Calendar when) {
Intent i = new Intent(mContext, OnAlarmReceiver.class);
i.putExtra(RemindersDbAdapter.KEY_ROWID, (long)taskId);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, PendingIntent.FLAG_ONE_SHOT);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, when.getTimeInMillis(), pi);
}
Okei I have looked up in your source code and I think you should cancel in your manifest this line :
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
In saveState function in ReminderEditActivity class don't save the time as formatted date. Instead just save calendar.getTimeInMillis().
Example:
private void saveState() {
long id = mDbHelper.createReminder(title, body, mCalendar.getTimeInMillis());
}
Now in your fetchAllReminder query you can add:
Example:
Calendar currentTime = Calendar.getInstance();
return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_TITLE, KEY_BODY, KEY_DATE_TIME}, null, "reminder_date_time > " + currentTime.getTimeInMillis(), null, null, null);
Related
I use Google Calendar Provider for Android to add Events in my Google Calendar:
https://developer.android.com/guide/topics/providers/calendar-provider.html#overview
And this is the example to add Reminder for the Event:
ContentValues values = new ContentValues();
values.put(CalendarContract.Reminders.MINUTES, 15);
values.put(CalendarContract.Reminders.EVENT_ID, reminderEventId);
values.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
getContentResolver().insert(CalendarContract.Reminders.CONTENT_URI, values);
But in my Google Calendar app I can create Reminders without having EVENT_ID. Is it possible to create the same reminders with Google Calendar Provider for Android?
The same like this:
https://gsuiteupdates.googleblog.com/2016/04/launch-of-reminders-for-google-calendar.html
I have see that Google launch reminders for Google Calendar 2016 (This is a different Reminders from Event Reminders) and at the moment I can`t find in Android SDK (API 25) this kind of Google Calendar Reminders (and possibility to add programmatically appointment slots too).
A tricky approach I'm using is creating the remainders, instead of calendar, in the contacts, using Custom Reminder (and the ContactContract provider). So, you can use any label, and the reminder is shown in the specific date.
Cons:
- You have to have the "Birthday" calendar enable
- The remainder is date based (not time)
- They don't repeat the reminder (as the new calendar does)
package es.goodsal.mobile.provider.contact;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.provider.ContactsContract.CommonDataKinds.Event;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import es.goodsal.mobile.app.App;
import es.goodsal.mobile.model.ReminderType;
/**
* Created by jmalbarran on 16/9/17.
*/
public class Reminder implements Comparable<Reminder> {
private static final String TAG = Reminder.class.getSimpleName();
private static final SimpleDateFormat fullPeriodicDateFormat = new SimpleDateFormat("--MM-dd");
private static final SimpleDateFormat periodicDateFormat = new SimpleDateFormat("MM-dd");
private static final SimpleDateFormat nonPeriodicDateFormat = new SimpleDateFormat("yyyy-MM-dd");
private static final String DUE_DATE = Event.DATA4;
private static final String COMMENT = Event.DATA5;
private static final Uri CONTENT_URI = ContactsContract.Data.CONTENT_URI;
private static final String[] PROJECTION = new String[]{
Event._ID, //0
Event.CONTACT_ID, //1
Event.LOOKUP_KEY, //2
Event.START_DATE, //3
Event.TYPE, //4
Event.LABEL, //5 Label for custom event
Reminder.DUE_DATE, // 6
Reminder.COMMENT // 7 Use this field to save Comments
};
static {
periodicDateFormat.setCalendar(Calendar.getInstance()); // Set local time zone
nonPeriodicDateFormat.setCalendar(Calendar.getInstance()); // Set local time zone
}
private long id = -1;
private ConContact contact;
private Date reminderDate;
private Date dueDate;
private ReminderType type;
private String comment;
// region Constructor
public Reminder(ConContact contact, Date reminderDate,
Date dueDate, ReminderType type, String comment) {
this.contact = contact;
this.reminderDate = reminderDate;
this.dueDate = dueDate;
this.type = type;
this.comment = comment;
}
public Reminder(#NonNull String reminderUri) {
this(Uri.parse(reminderUri));
}
public Reminder(#NonNull Uri reminderUri) {
Cursor cursor;
cursor = App.getContentResolverInstance().query(reminderUri,
PROJECTION, null, null, null);
if (cursor == null) {
throw new IllegalArgumentException(reminderUri.toString() + " opportunity not found.");
} else {
cursor.moveToFirst();
setFromCursor(null, cursor);
}
}
private Reminder(#NonNull Cursor cursor) {
this(null, cursor);
}
private Reminder(#Nullable ConContact contact, #NonNull Cursor cursor) {
setFromCursor(contact, cursor);
}
private void setFromCursor(#Nullable ConContact contact, #NonNull Cursor cursor) {
int eventType;
String eventLabel;
Calendar calDueDate, calReminderDate;
Date now;
String strSplitDate[];
String strDueDate;
this.id = cursor.getLong(0);
if (contact != null) {
this.contact = contact;
} else {
this.contact = new ConContact(cursor.getLong(1), cursor.getString(2));
}
// Type
eventType = cursor.getInt(4); //Event.TYPE
eventLabel = cursor.getString(5); //Event.LABEL
switch (eventType) {
case ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY:
type = ReminderType.anniversary;
break;
case ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY:
type = ReminderType.birthday;
break;
case ContactsContract.CommonDataKinds.Event.TYPE_CUSTOM:
type = ReminderType.other;
eventLabel = cursor.getString(5);
for (ReminderType iType : ReminderType.values()) {
if (iType.getLabel().equals(eventLabel)) {
type = iType;
break;
}
}
break;
default:
type = ReminderType.other;
}
// Due / Reminder date
try {
now = new Date();
if (type.isPeriodic()) {
// Periodic Due date
calDueDate = Calendar.getInstance();
calDueDate.setTime(now);
strSplitDate = cursor.getString(6).split("-"); // DATA4
if (strSplitDate != null && strSplitDate.length == 3) {
calDueDate.set(Calendar.MONTH, Integer.parseInt(strSplitDate[1]));
calDueDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(strSplitDate[2]));
if (calDueDate.before(now)) { // Crossed end-of-year boundary
calDueDate.add(Calendar.YEAR, 1); // Next year
}
} else {
Log.e(TAG, "getReminders: Invalid date for periodic reminder due date " +
cursor.getString(6));
}
dueDate = calDueDate.getTime();
// Periodic Reminder date
calReminderDate = Calendar.getInstance();
calReminderDate.setTime(dueDate);
strSplitDate = cursor.getString(3).split("-"); // START_DATE
if (strSplitDate != null && strSplitDate.length == 3) {
calReminderDate.set(Calendar.MONTH, Integer.parseInt(strSplitDate[1]));
calReminderDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(strSplitDate[2]));
if (calReminderDate.after(dueDate)) { // Crossed end-of-year boundary
calDueDate.add(Calendar.YEAR, -11); // Previous year
}
} else {
Log.e(TAG, "getReminders: Invalid date for periodic reminder start date " +
cursor.getString(6));
}
reminderDate = calReminderDate.getTime();
} else {
// Non periodic date
reminderDate = nonPeriodicDateFormat.parse(cursor.getString(3)); // START_DATE
dueDate = nonPeriodicDateFormat.parse(cursor.getString(6)); // DATA4
dueDate = dueDate !=null ? dueDate : reminderDate;
}
} catch (Exception e) { // NullPointer and/or ParseFormat
dueDate = null;
reminderDate = null;
}
// Comment
comment = cursor.getString(7); // DATA5
}
// endregion Constructor
// region Getter/Setter
public Uri getUri() {
Uri uri;
uri = null;
if (id != -1) {
uri = ContentUris.withAppendedId(CONTENT_URI, id);
}
return uri;
}
public ConContact getContact() {
return contact;
}
public Date getReminderDate() {
return reminderDate;
}
public Date getDueDate() {
return dueDate;
}
public ReminderType getReminderType() {
return type;
}
public String getComment() {
return comment;
}
public boolean isPeriodic() {
return type.isPeriodic();
}
public void setContact(ConContact contact) {
this.contact = contact;
}
public void setReminderDate(Date reminderDate) {
this.reminderDate = reminderDate;
}
public void setDueDate(Date dueDate) {
this.dueDate = dueDate;
}
public void setType(ReminderType type) {
this.type = type;
}
public void setComment(String comment) {
this.comment = comment;
}
// endregion Getter/Setter
// region Commands
public boolean save() {
boolean ret;
ContentValues values;
Uri savedUri;
ret = false;
values = new ContentValues();
values.put(ContactsContract.CommonDataKinds.Event.MIMETYPE,
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
//values.put(ContactsContract.CommonDataKinds.Event.CONTACT_ID, contact.getContactId());
values.put(ContactsContract.CommonDataKinds.Event.RAW_CONTACT_ID, contact.getRawContactId());
if (type.isPeriodic()) {
values.put(ContactsContract.CommonDataKinds.Event.START_DATE,
fullPeriodicDateFormat.format(reminderDate));
values.put(ContactsContract.CommonDataKinds.Event.DATA4,
fullPeriodicDateFormat.format(dueDate));
} else {
values.put(ContactsContract.CommonDataKinds.Event.START_DATE,
nonPeriodicDateFormat.format(reminderDate));
values.put(ContactsContract.CommonDataKinds.Event.DATA4,
nonPeriodicDateFormat.format(dueDate));
}
values.put(ContactsContract.CommonDataKinds.Event.TYPE,
Integer.toString(type.getContactEventType()));
values.put(ContactsContract.CommonDataKinds.Event.LABEL, type.getLabel());
values.put(ContactsContract.CommonDataKinds.Event.DATA5, comment);
if (id == -1L) {
// Create new
savedUri = App.getContentResolverInstance().insert(ContactsContract.Data.CONTENT_URI, values);
id = ContentUris.parseId(savedUri);
ret = true;
Log.d(TAG, "save: Inserted uri=" + savedUri + " id=" + id);
} else {
// update existing id
// if (0<App.getContentResolverInstance().update(ContactsContract.Data.CONTENT_URI, values,
// ContactsContract.Data._ID + "='" + Long.toString(id) + "'", null)){
if (0 < App.getContentResolverInstance().update(
ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id),
values,
null,
null)) {
ret = true;
Log.d(TAG, "save: Updated id=" + id);
} else {
Log.e(TAG, "save: Error updating id=" + id);
}
}
contact.resetReminders();
return ret;
}
public boolean delete() {
boolean ret = false;
if (id != -1) {
if (0 < App.getContentResolverInstance().delete(
ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id),
null,
null)) {
Log.d(TAG, "delete: Deleted id=" + id);
ret = true;
} else {
Log.w(TAG, "delete: Not found id=" + id);
}
}
return ret;
}
// endregion Commands
#Override
public int compareTo(#NonNull Reminder o) {
if (reminderDate == null) {
return 1; // null always at end
} else {
if (o.reminderDate == null) {
return -1;
} else {
return reminderDate.compareTo(o.reminderDate);
}
}
}
/**
* Get reminders for all contact, in a specific date (including periodics)
*
* #param date exact to search for (reminder date NOT due date)
* #return List of reminders
*/
public static List<Reminder> getReminders(Date date) {
Cursor cursor;
ArrayList<Reminder> retList;
String where;
String[] selectionArgs;
Date dueDate;
String dateSelection;
String[] strSplitDate;
Calendar calDueDate;
retList = null;
Uri uri = ContactsContract.Data.CONTENT_URI;
String sortOrder = null;
// Execute one query per reminder type
for (ReminderType type : ReminderType.values()) {
dateSelection = type.isPeriodic() ?
"%" + periodicDateFormat.format(date) :
"%" + nonPeriodicDateFormat.format(date);
if (type.getContactEventType() == ContactsContract.CommonDataKinds.Event.TYPE_CUSTOM) {
// Check event label too
where = ContactsContract.CommonDataKinds.Event.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE ? AND " +
ContactsContract.CommonDataKinds.Event.LABEL + "= ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" + type.getContactEventType();
selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
dateSelection,
type.getLabel()
};
} else {
// Non custom reminder. Don't check label
where = ContactsContract.CommonDataKinds.Event.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" + type.getContactEventType();
selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
dateSelection
};
} // where & selection per event type
cursor = App.getContentResolverInstance().query(uri, PROJECTION,
where, selectionArgs, sortOrder);
if (cursor != null) {
retList = new ArrayList<Reminder>();
while (cursor.moveToNext()) {
retList.add(new Reminder(cursor));
}
cursor.close();
} // if cursor
} // for per every type
return retList;
}
/**
* Get reminders for a specific contact, from a date forward
*
* #param contact Contact for search for
* #param date current or future date to search (including periodic)
* #return List of reminders for current or future search
*/
public static List<Reminder> getReminders(ConContact contact, Date date) {
Uri uri;
Cursor cursor;
ArrayList<Reminder> retList = null;
String where;
String[] selectionArgs;
String sortOrder;
int contactEventType;
String label;
Calendar calReminderDate, calDueDate;
String strReminderDate, strDueDate;
ReminderType type;
Date reminderDate;
Date dueDate;
String strDescription;
String[] strSplitDate;
uri = ContactsContract.Data.CONTENT_URI;
sortOrder = null;
// Check event label too
where = ContactsContract.CommonDataKinds.Event.MIMETYPE + " = ? AND " +
ContactsContract.CommonDataKinds.Event.CONTACT_ID + " = ? AND " +
"(" +
ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE '--%' OR " +
ContactsContract.CommonDataKinds.Event.START_DATE + " >= ?" +
")";
selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
Long.toString(contact.getContactId()),
nonPeriodicDateFormat.format(date)
};
sortOrder = ContactsContract.CommonDataKinds.Event.START_DATE;
cursor = App.getContentResolverInstance().query(uri, PROJECTION,
where, selectionArgs, sortOrder);
if (cursor != null) {
retList = new ArrayList<Reminder>();
while (cursor.moveToNext()) {
retList.add(new Reminder(contact, cursor));
}
Collections.sort(retList);
cursor.close();
} // if cursor
// for per every type
return retList;
}
} // end Reminder class
As stated in https://developer.android.com/guide/topics/providers/calendar-provider.html#overview
Reminders are specified in minutes before the event and have a method
that determines how the user will be alerted.
A reminder that doesn't belong to an event will not have a time of reference to go off.
I think for what you are trying to achieve () it would be best for you to look at Androids AlarmManager https://developer.android.com/reference/android/app/AlarmManager.html
Or see what other people are saying about similar things https://stackoverflow.com/a/16549111/6431430
I have been stuck on this problem for a while.
Is there any good example for Broadcast Receiver with multiple database Cursor?
PROBLEM:
I have implemented PagerTabStrip, and also BroadCast receiver and notification for reminder.
So when I click on notification on device screen, it only opens the first cursor, it doesnt open the other too.. I am pretty sure that, I have closed my cursors.
THIS IS JUST OPENS UP THE BLANK ACTIVITY without and STUFF I WANT.
public class ReminderService extends WakeReminderIntentService{
public ReminderService(){
super("ReminderService");
}
#SuppressWarnings("deprecation")
void doReminderWork(Intent intent){
Log.d("ReminderService", "Doing work.");
Long rowId = intent.getExtras().getLong(TaskDatabase.KEY_ROWID);
NotificationManager mgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(this, TaskEdit.class);
notificationIntent.putExtra(TaskDatabase.KEY_ROWID, rowId);
PendingIntent pi = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
/// Rest of the COde.
BROADCASTRECEIVER(this class gets the cursor)
public void onReceive(Context context, Intent intent){
ReminderManager reminderMgr = new ReminderManager(context);
TaskDatabase dbHelper = new TaskDatabase(context);
dbHelper.open();
Cursor cursor = dbHelper.fetchAllGeneralRemindersByDefault();
if(cursor != null){
cursor.moveToFirst();
int rowIdColumnIndex = cursor.getColumnIndex(TaskDatabase.KEY_ROWID);
int dateTimeColumnIndex = cursor.getColumnIndex(TaskDatabase.KEY_DATE_TIME);
while(cursor.isAfterLast() == false){
Log.d(TAG, "Adding alarm from boot.");
Log.d(TAG, "Row Id Column Index - " + rowIdColumnIndex);
Log.d(TAG, "Date Time Column Index - " + dateTimeColumnIndex);
Long rowId = cursor.getLong(rowIdColumnIndex);
String dateTime = cursor.getString(dateTimeColumnIndex);
Calendar cal = Calendar.getInstance();
SimpleDateFormat format = new SimpleDateFormat(TaskEdit.DATE_TIME_FORMAT);
try{
java.util.Date date = format.parse(dateTime);
cal.setTime(date);
reminderMgr.setReminder(rowId, cal);
}catch(java.text.ParseException e){
Log.e("OnBootReceiver", e.getMessage(), e);
}
cursor.moveToNext();
}
With the understanding of your question in place, I am pretty certain there is a fault in fetchAllGeneralRemindersByDefault(). It is returning en empty cursor. If this is because of the code, or the database being empty, I cannot tell.
Suggestion to code refactor:
public void onReceive(Context context, Intent intent){
ReminderManager reminderMgr = new ReminderManager(context);
TaskDatabase dbHelper = new TaskDatabase(context);
dbHelper.open();
// returns an empty cursor at index -1 (that is normal behaviour for cursors)
Cursor cursor = dbHelper.fetchAllGeneralRemindersByDefault();
if(cursor != null && cursor.size() > 0){ // added check
int rowIdColumnIndex = cursor.getColumnIndex(TaskDatabase.KEY_ROWID);
int dateTimeColumnIndex = cursor.getColumnIndex(TaskDatabase.KEY_DATE_TIME);
// when you called moveToNext on the empty cursor
// it corresponds to calling list.get(0) on an empty ArrayList
while(cursor.moveToNext()){
Log.d(TAG, "Adding alarm from boot.");
Log.d(TAG, "Row Id Column Index - " + rowIdColumnIndex);
Log.d(TAG, "Date Time Column Index - " + dateTimeColumnIndex);
Long rowId = cursor.getLong(rowIdColumnIndex);
String dateTime = cursor.getString(dateTimeColumnIndex);
Calendar cal = Calendar.getInstance();
SimpleDateFormat format = new SimpleDateFormat(TaskEdit.DATE_TIME_FORMAT);
try{
java.util.Date date = format.parse(dateTime);
cal.setTime(date);
reminderMgr.setReminder(rowId, cal);
}catch(java.text.ParseException e){
Log.e("OnBootReceiver", e.getMessage(), e);
}
}
} else {
Log.e("OnBootReceiver", "fetchAllGeneralRemindersByDefault() returned empty cursor");
}
}
I am developing an android app.I wan to provide five notifications per day.I will store the notification time in sqlite database.Then I compare this db notification time with the devices time in a repeating loop using service.But the notification will not work properly.Forceclose appeared.I have given the two class files Third,java and MyService below.......I need the help
Third.java
public class third extends Activity {
/** Called when the activity is first created. */
Button btnopen;
Spinner spin1,spin2,spin3,spin4,spin5;
EditText t1,t2,t3,t4,t5;
String fajr,zuhr,asr,magrib,isha;
String[] item={"","2-Times Allahu akbar","3-Beep once"};
example r=new example();
private static final String DATABASE_NAME = "MYPRAYER.db";
private static final String DATABASE_TABLE = "notification";
private static final String DATABASE_CREATE = "create table "+DATABASE_TABLE+"(id integer primary key autoincrement , fajr varchar not null , zuhr varchar not null , asr varchar not null , magrib varchar not null , isha varchar not null );";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page3);
/* Call the service */
Intent i = new Intent();
i.setClassName( "org.prayer.test","org.prayer.test.MyService" );
bindService( i, null, Context.BIND_AUTO_CREATE);
this.startService(i);
/* Populate the spinner */
btnopen=(Button)findViewById(R.id.button1);
t1=(EditText)findViewById(R.id.editText1);
t2=(EditText)findViewById(R.id.editText2);
t3=(EditText)findViewById(R.id.editText3);
t4=(EditText)findViewById(R.id.editText4);
t5=(EditText)findViewById(R.id.editText5);
spin1=(Spinner)findViewById(R.id.spinner1);
spin2=(Spinner)findViewById(R.id.spinner3);
spin3=(Spinner)findViewById(R.id.spinner4);
spin4=(Spinner)findViewById(R.id.spinner6);
spin5=(Spinner)findViewById(R.id.spinner7);
ArrayAdapter<String> a1=new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,item);
a1.setDropDownViewResource(android.R.layout.simple_spinner_item);
spin1.setAdapter(a1);
spin2.setAdapter(a1);
spin3.setAdapter(a1);
spin4.setAdapter(a1);
spin5.setAdapter(a1);
/* Notification time stored on the database */
try
{
SQLiteDatabase myDB;
//myDB = openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
myDB = SQLiteDatabase.openDatabase("/data/data/org.prayer.test/databases/MYPRAYER.db",null,SQLiteDatabase.CREATE_IF_NECESSARY);
//myDB.execSQL(DATABASE_CREATE);
myDB.execSQL(DATABASE_CREATE);
myDB = openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
ContentValues newRow = new ContentValues();
newRow.put("id", "1");
newRow.put("fajr", "0:00 AM");
newRow.put("zuhr", "0:00 AM");
newRow.put("asr", "0:00 AM");
newRow.put("magrib", "0:00 AM");
newRow.put("isha", "0:00 AM");
myDB.insert(DATABASE_TABLE, null, newRow);
myDB.close();
}
catch(SQLiteException ex)
{
//Do nothing
//System.out.println(ex.getMessage());
}
btnopen.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
fajr=t1.getText().toString();
zuhr=t2.getText().toString();
asr=t3.getText().toString();
magrib=t4.getText().toString();
isha=t5.getText().toString();
SQLiteDatabase myDB;
myDB = openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
ContentValues newRow = new ContentValues();
newRow.put("id", "1");
newRow.put("fajr", fajr);
newRow.put("zuhr", zuhr);
newRow.put("asr", asr);
newRow.put("magrib", magrib);
newRow.put("isha", isha);
myDB.update(DATABASE_TABLE, newRow,"id" + "=" + "1",null);
Toast.makeText(getApplicationContext(), "row updated", Toast.LENGTH_SHORT).show();
myDB.close();
}
});
}
}
MyService.java
ppublic class MyService extends Service {
private static final String DATABASE_NAME = "MYPRAYER.db";
private static final String DATABASE_TABLE = "notification";
String tag="TestService";
String a="hello";
String res1,res2,res3,res4,res5;
int hour,minute;
String day3,day4,minute1,hour1;
MediaPlayer mMediaPlayer;
/* Service creation */
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service created...", Toast.LENGTH_LONG).show();
Log.i(tag, "Service created...");
/* Rereive notification times from the databse notificaion */
SQLiteDatabase myDB;
myDB = openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
String[] resultColumns = new String[] {"fajr","zuhr","asr","magrib","isha"};
Cursor allRows = myDB.query(DATABASE_TABLE, resultColumns, null, null, null, null, null, null);
Integer cindex = allRows.getColumnIndex("fajr");
Integer cindex1 = allRows.getColumnIndex("zuhr");
Integer cindex2 = allRows.getColumnIndex("asr");
Integer cindex3 = allRows.getColumnIndex("magrib");
Integer cindex4 = allRows.getColumnIndex("isha");
allRows.moveToFirst();
res1=allRows.getString(cindex);
res2=allRows.getString(cindex1);
res3=allRows.getString(cindex2);
res4=allRows.getString(cindex3);
res5=allRows.getString(cindex4);
myDB.close();
while(!Thread.currentThread().isInterrupted())
{
try
{
Calendar cal = Calendar.getInstance(); // Rereive calender date
hour = cal.get(Calendar.HOUR_OF_DAY); // Take hour from the calender
minute = cal.get(Calendar.MINUTE); // Take minute from the calender
minute1=minute + ""; // Convert minute to dtring
if(minute1.equals("1"))
{
minute1="01";
}
else if(minute1.equals("2"))
{
minute1="02";
}
else if(minute1.equals("3"))
{
minute1="03";
}
else if(minute1.equals("4"))
{
minute1="04";
}
else if(minute1.equals("5"))
{
minute1="05";
}
else if(minute1.equals("6"))
{
minute1="06";
}
else if(minute1.equals("7"))
{
minute1="07";
}
else if(minute1.equals("8"))
{
minute1="08";
}
else if(minute1.equals("9"))
{
minute1="09";
}
/* Converting to 12 hour format */
if ( hour < 12 )
{
hour=hour;
day3=hour + "" + ":" + minute1;
day4=day3 + " " + "AM"; // DAY4 Contains the system time
}
else
{
hour=hour-12;
day3=hour + "" + ":" + minute1;
day4=day3 + " " + "PM";
}
if(day4.equals(res1))
{
Notification("Notification Title","Notification Message");
}
if(day4.equals(res2))
{
Notification("Notification Title","Notification Message");
}
if(day4.equals(res3))
{
Notification("Notification Title","Notification Message");
}
if(day4.equals(res4))
{
Notification("Notification Title","Notification Message");
}
if(day4.equals(res5))
{
Notification("Notification Title","Notification Message");
}
Thread.sleep(1000);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
//System.out.println("New 1 Exception here");
}
catch (Exception e)
{
//Thread.currentThread().interrupt();
System.out.println("nEW Exception here");
}
}
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.i(tag, "Service started...");
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service destroyed...", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void Notification(String notificationTitle, String notificationMessage)
{
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "A New Message!", System.currentTimeMillis());
Intent notificationIntent = new Intent(this,MyService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(MyService.this, notificationTitle, notificationMessage, pendingIntent);
notificationManager.notify(10001, notification);
//HELLO_ID++;
Uri alert = RingtoneManager.getDefaultUri(
RingtoneManager.TYPE_NOTIFICATION);
mMediaPlayer = new MediaPlayer();
try
{
mMediaPlayer.setDataSource(this, alert);
AudioManager audioManager = (AudioManager)getSystemService(
Context.AUDIO_SERVICE);
int volumen = audioManager.getStreamVolume(
AudioManager.STREAM_NOTIFICATION);
if (volumen != 0) {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
mMediaPlayer.setLooping(true);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
}
catch(IOException e)
{
System.out.println("Exception here");
//System.out.println("Exception 1 here");
}
}
}
Lgcat :
07-27 16:24:52.591: E/global(363): Deprecated Thread methods are not supported.
07-27 16:24:52.591: E/global(363): java.lang.UnsupportedOperationException
07-27 16:24:52.591: E/global(363): at java.lang.VMThread.stop(VMThread.java:85)
07-27 16:24:52.591: E/global(363): at java.lang.Thread.stop(Thread.java:1379)
07-27 16:24:52.591: E/global(363): at java.lang.Thread.stop(Thread.java:1344)
07-27 16:24:52.591: E/global(363): at org.prayer.test.splash$1.run(splash.java:71)
07-27 16:24:53.002: D/dalvikvm(363): GC freed 879 objects / 65552 bytes in 108ms
07-27 16:25:00.542: I/TestService(363): Service created...
07-27 16:25:20.752: I/dalvikvm(363): threadid=7: reacting to signal 3
07-27 16:25:20.803: I/dalvikvm(363): Wrote stack trace to '/data/anr/traces.txt'
If your aim is to trigger a notification at fixed times in a day, use AlarmManager to do this, as follows:
When application is started for first time, save those EditText values, etc as you are doing now - then set up AlarmManager to wake up your service at the nearest next notification time.
In the service, post the notification, set the next Alarm, and stopSelf().
This cycle will continue.
As for the force close, paste your logcat. Your code is not very neat, variables not meaningfully named, so its difficult to tell.
I have registered an contentobserver monitoring the call log.
But I cant get the latest call, the furthest I came is getting the latest call the first time, after that it just takes the previous and then the previous..
Also it returns 2 log entries at a time.
The code im using is:
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;
import android.provider.BaseColumns;
import android.provider.CallLog;
import android.util.Log;
class CallMonitor extends ContentObserver {
private PositionDbAdapter mDbHelper;
Cursor cur;
Context CallMon = Position.MAIN_ACTIVITY;
int idColumn;
int numberColumn;
int dateColumn;
int typeColumn;
int durColumn;
public CallMonitor(Handler handler, Context context){
super(handler);
CallMon = context;
}
#Override
public void onChange(boolean selfChange) {
if(cur==null){
cursorInit(CallMon);
}
if (!cur.moveToNext()) {
//do we really want to close the cursor?
//cur.close();
return;
}
String number = cur.getString(numberColumn);
String id = cur.getString(idColumn);
String type = cur.getString(typeColumn);
String date = cur.getString(dateColumn);
String dur = cur.getString(durColumn);
Date dateN = new Date(Long.parseLong(date));
Date date2 = new Date();
Log.d("Position", date2+": "+dateN+":"+id+", "+number+", "+type+", "+dur);
//cur.moveToNext();
}
public void Destroy() {
Log.d("Position", "Destroy Call Monitor");
cur.close();
}
public void cursorInit(Context context){
String[] projection = new String[]{
BaseColumns._ID,
CallLog.Calls.DATE,
CallLog.Calls.NUMBER,
CallLog.Calls.DURATION,
CallLog.Calls.TYPE
};
ContentResolver resolver = context.getContentResolver();
cur = resolver.query(CallLog.Calls.CONTENT_URI, projection, null,null, "date DESC");
//cur.moveToFirst();
numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
dateColumn = cur.getColumnIndex(CallLog.Calls.DATE);
durColumn = cur.getColumnIndex(CallLog.Calls.DURATION);
idColumn = cur.getColumnIndex(CallLog.Calls._ID);
}
}
I've tried various cur.moveToFirst .moveToNext etc...
The closest I came is when it fires the first time, i get the correct callog item, but then i get another one.
Then the second time and third etc.. i get older.
I thought that i i close the cursor then it would start over from the beginning, but when I do this, it throws an error, probably because the cursor is closed when it automatically get the second one, the one i dont want.
So can somebody please help me?
I have done this type of operation but through BroadcastReceiver. may be that will be helpful for you:
public class CallReceiver extends BroadcastReceiver {
//<----------------- Fields------------->
private String phone_no = "";
private int phone_id;
private String incoming_time = "";
private Context context;
#Override
public void onReceive(Context ctx, Intent intent) {
context = ctx;
final Bundle bundle = intent.getExtras();
incomingCalls(bundle);
}
/**
* Check incoming call and match in database
* #param bundle
*/
private void incomingCalls(Bundle bundle) {
if (null == bundle)
return;
Log.i("IncomingCallReceiver", bundle.toString());
final String state = bundle.getString(TelephonyManager.EXTRA_STATE);
Log.i("IncomingCallReceiver", "State: " + state);
phone_no = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)
&& phone_no != null && !phone_no.equalsIgnoreCase("")) {
final DateFormat formatter = new SimpleDateFormat(
"MMM dd yyyy HH:mm");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
incoming_time = formatter.format(calendar.getTime());
Log.i("IncomingCallReceiver", "Incomng Number: " + phone_no);
if (phone_id != 0) {
Log.i("Phone number", phone_no);
Log.i("Phone ID", phone_id+"");
Log.i("Incoming time", incoming_time);
}
}
}
}
if you want call log to be displayed from older to newer entries
ContentResolver resolver = context.getContentResolver();
cur = resolver.query(CallLog.Calls.CONTENT_URI, projection, null,null, "date DESC");
while(cur.moveToNext()){
numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
dateColumn = cur.getColumnIndex(CallLog.Calls.DATE);
durColumn = cur.getColumnIndex(CallLog.Calls.DURATION);
idColumn = cur.getColumnIndex(CallLog.Calls._ID);
//display call log or do ur logic
}
and if you want call logs to be displayed from newer to older(i.e latest entry at first)
ContentResolver resolver = context.getContentResolver();
cur.moveToLast()
cur = resolver.query(CallLog.Calls.CONTENT_URI, projection, null,null, "date DESC");
while(cur.moveToPerivous()){
numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
dateColumn = cur.getColumnIndex(CallLog.Calls.DATE);
durColumn = cur.getColumnIndex(CallLog.Calls.DURATION);
idColumn = cur.getColumnIndex(CallLog.Calls._ID);
//display call log or do ur logic
}
Hey, I'm trying to implement a service on my Android Application. And the Service must do the same task of the Activity. IE, if some change happen on the CallLog.Calls content provider the service must be notified and insert the data in the database even if the application is not running, I mean, a service will be running after the application is started, so if the application is killed, the service will keep running until the OS stop it, right?
So it will be running on background collecting all data that changes on the CallLog.Calls service. But, the service is not running. I star it in onCreate() method of the Activity. And inside the Service I implemented a ContentObserver class that uses the method onChange() in case somethind changes in the CallLog.Calls content provider.
What I don't know is why the Service is not started, and why it doesn't work even if I kill the app on the DDMS perspective.
Here is the code.
The Activity called RatedCalls.java
public class RatedCalls extends ListActivity {
private static final String LOG_TAG = "RATEDCALLSOBSERVER";
private Handler handler = new Handler();
private SQLiteDatabase db;
private CallDataHelper cdh;
StringBuilder sb = new StringBuilder();
OpenHelper openHelper = new OpenHelper(RatedCalls.this);
private Integer contentProviderLastSize;
private Integer contentProviderCurrentSize;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
cdh = new CallDataHelper(this);
db = openHelper.getWritableDatabase();
startService(new Intent(this, RatedCallsService.class));
registerContentObservers();
Log.i("FILLLIST", "calling from onCreate()");
Cursor cursor = getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI, null, null, null,
android.provider.CallLog.Calls.DATE + " DESC ");
contentProviderLastSize = cursor.getCount();
}
class RatedCallsContentObserver extends ContentObserver {
public RatedCallsContentObserver(Handler h) {
super(h);
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
#Override
public void onChange(boolean selfChange) {
Log.d(LOG_TAG, "RatedCallsContentObserver.onChange( " + selfChange
+ ")");
super.onChange(selfChange);
searchInsert();
}
}
private void searchInsert() {
Cursor cursor = getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI, null, null, null,
android.provider.CallLog.Calls.DATE + " DESC ");
Log.i("FILLLIST", "Calling from searchInsert");
startManagingCursor(cursor);
int numberColumnId = cursor
.getColumnIndex(android.provider.CallLog.Calls.NUMBER);
int durationId = cursor
.getColumnIndex(android.provider.CallLog.Calls.DURATION);
int contactNameId = cursor
.getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME);
int numTypeId = cursor
.getColumnIndex(android.provider.CallLog.Calls.CACHED_NUMBER_TYPE);
Date dt = new Date();
int hours = dt.getHours();
int minutes = dt.getMinutes();
int seconds = dt.getSeconds();
String currTime = hours + ":" + minutes + ":" + seconds;
SimpleDateFormat dateFormat = new SimpleDateFormat("M/dd/yyyy");
Date date = new Date();
cursor.moveToFirst();
String contactNumber = cursor.getString(numberColumnId);
String contactName = cursor.getString(contactNameId);
String duration = cursor.getString(durationId);
String numType = cursor.getString(numTypeId);
stopManagingCursor(cursor);
ContentValues values = new ContentValues();
values.put("contact_id", 1);
values.put("contact_name", contactName);
values.put("number_type", numType);
values.put("contact_number", contactNumber);
values.put("duration", duration);
values.put("date", dateFormat.format(date));
values.put("current_time", currTime);
values.put("cont", 1);
db.insert(CallDataHelper.TABLE_NAME, null, values);
}
public void registerContentObservers() {
this.getApplicationContext()
.getContentResolver()
.registerContentObserver(
android.provider.CallLog.Calls.CONTENT_URI, true,
new RatedCallsContentObserver(handler));
}
And this is the Service called RatedCallsService.java
public class RatedCallsService extends Service {
private static final String TAG = "RatedCallsService";
private static final String LOG_TAG = "RatedCallsService";
private Handler handler = new Handler();
private SQLiteDatabase db;
private CallDataHelper cdh;
OpenHelper openHelper = new OpenHelper(RatedCallsService.this);
class RatedCallsContentObserver extends ContentObserver {
public RatedCallsContentObserver(Handler h) {
super(h);
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
#Override
public void onChange(boolean selfChange) {
Log.d(LOG_TAG, "RatedCallsContentObserver.onChange( " + selfChange
+ ")");
super.onChange(selfChange);
searchInsert();
}
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Rated Calls Service Created", Toast.LENGTH_LONG).show();
Log.i(TAG, "onCreate");
registerContentObservers();
}
#Override
public void onDestroy() {
Toast.makeText(this, "Rated Calls Service Stopped", Toast.LENGTH_LONG).show();
Log.i(TAG, "onDestroy");
cdh = new CallDataHelper(this);
db = openHelper.getWritableDatabase();
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "Rated Calls Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
registerContentObservers();
}
private void searchInsert() {
Cursor cursor = getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI, null, null, null,
android.provider.CallLog.Calls.DATE + " DESC ");
Log.i("FILLLIST", "Calling from searchInsert");
int numberColumnId = cursor
.getColumnIndex(android.provider.CallLog.Calls.NUMBER);
int durationId = cursor
.getColumnIndex(android.provider.CallLog.Calls.DURATION);
int contactNameId = cursor
.getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME);
int numTypeId = cursor
.getColumnIndex(android.provider.CallLog.Calls.CACHED_NUMBER_TYPE);
Date dt = new Date();
int hours = dt.getHours();
int minutes = dt.getMinutes();
int seconds = dt.getSeconds();
String currTime = hours + ":" + minutes + ":" + seconds;
SimpleDateFormat dateFormat = new SimpleDateFormat("M/dd/yyyy");
Date date = new Date();
if (cursor.moveToFirst()) {
do {
String contactNumber = cursor.getString(numberColumnId);
String contactName = cursor.getString(contactNameId);
String duration = cursor.getString(durationId);
String numType = cursor.getString(numTypeId);
ContentValues values = new ContentValues();
values.put("contact_id", 1);
values.put("contact_name", contactName);
values.put("number_type", numType);
values.put("contact_number", contactNumber);
values.put("duration", duration);
values.put("date", dateFormat.format(date));
values.put("current_time", currTime);
values.put("cont", 1);
db.insert(CallDataHelper.TABLE_NAME, null, values);
} while (cursor.moveToNext());
cursor.close();
}
}
public void registerContentObservers() {
this.getApplicationContext()
.getContentResolver()
.registerContentObserver(
android.provider.CallLog.Calls.CONTENT_URI, true,
new RatedCallsContentObserver(handler));
}
}
Just see if you have added this Service in your manifest file.......
Thanks.......
When declaring the service in your manifest, try using the full package location of your service class in your manifest.
eg. <service android:name="com.company.project.package.MyService">
My service wasn't starting and that worked for me.
You might want to check out the service lifecycle documentation. If you call Context.startService() the service should start and stay running until someone tells it to stop.
From your code sample, it looks like you are doing that. What makes you think that the service isn't starting?
I'm not sure what you expect to happen when you kill the app... That sounds like a good reason for it not to work.
Hi instead of using a service and a content observer i would observe the phone state. Observing the phone state can trigger your update service.
You need the
android.permission.READ_PHONE_STATE
permission. which isn't a big affair.
The code for the broadcast receiver is
public class CallStateWatcher extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED))
{
String extra = intent.getStringExtra(android.telephony.TelephonyManager.EXTRA_STATE);
if (extra.equals(android.telephony.TelephonyManager.EXTRA_STATE_OFFHOOK))
{
// do something
}
if (extra.equals(android.telephony.TelephonyManager.EXTRA_STATE_IDLE))
{
// do something
}
}
}
}
You have to define that receiver
<receiver
android:name=".core.watcher.CallStateWatcher">
<intent-filter>
<action
android:name="android.intent.action.PHONE_STATE"></action>
</intent-filter>
</receiver>