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");
}
}
Related
I am wondering how to read last five SMS received from a particular mobile number on a particular date.
I know how to read all SMS from a particular sender, and how to read the last SMS, but I am unable to fetch and read the last few SMS. I tried to read them by using
"date DESC LIMIT 5"
My code is like below
Uri mSmsinboxQueryUri = Uri.parse("content://sms/inbox");
String[] projection = {"address", "body"};
Cursor cursor1 = MainActivity.this.getContentResolver().query(mSmsinboxQueryUri,
null,
"address = ?",
new String[]{phoneNumber},
"date DESC LIMIT 5");
if (cursor1 != null && cursor1.moveToFirst()) {
body = cursor1.getString(cursor1.getColumnIndex("body"));
totalBody = totalBody + body;
Log.d("Registration", totalBody);
}
But every time it's showing only the last message.
You're only seeing one message because your code is only handling the first record in the returned Cursor. You need to loop over the Cursor to handle the rest. For example:
if (cursor != null && cursor.moveToFirst()) {
do {
body = cursor1.getString(cursor1.getColumnIndex("body"));
totalBody = totalBody + body;
Log.d("Registration", totalBody);
} while (cursor.moveToNext());
}
Also, if you want to restrict the query to one day, you can use a Calendar to figure the starting and ending times for that day in milliseconds - as that is how dates are stored in the SMS table - and add the appropriate comparison to the where clause. For example:
private static final int DAY_MILLISECONDS = 24 * 60 * 60 * 1000;
private static final Uri inboxUri = Uri.parse("content://sms/inbox");
// Months are zero-based; i.e., JANUARY == 0
// Phone number must be exact in this example
private void listMessages(String phoneNumber, int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month);
cal.set(Calendar.DATE, day);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
String[] projection = {"address", "body"};
String whereAddress = "address = ?";
String whereDate = "date BETWEEN " + cal.getTimeInMillis() +
" AND " + (cal.getTimeInMillis() + DAY_MILLISECONDS);
String where = DatabaseUtils.concatenateWhere(whereAddress, whereDate);
Cursor cursor = null;
try {
cursor = getContentResolver().query(inboxUri,
projection,
where,
new String[]{phoneNumber},
"date DESC LIMIT 5");
if (cursor != null && cursor.moveToFirst()) {
do {
Log.d("Message", cursor.getString(cursor.getColumnIndex("body")));
} while (cursor.moveToNext());
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (cursor != null) {
cursor.close();
}
}
}
I am wondering how to read last five SMS received from a particular mobile number on a particular date.
I know how to read all SMS from a particular sender, and how to read the last SMS, but I am unable to fetch and read the last few SMS. I tried to read them by using
"date DESC LIMIT 5"
My code is like below
Uri mSmsinboxQueryUri = Uri.parse("content://sms/inbox");
String[] projection = {"address", "body"};
Cursor cursor1 = MainActivity.this.getContentResolver().query(mSmsinboxQueryUri,
null,
"address = ?",
new String[]{phoneNumber},
"date DESC LIMIT 5");
if (cursor1 != null && cursor1.moveToFirst()) {
body = cursor1.getString(cursor1.getColumnIndex("body"));
totalBody = totalBody + body;
Log.d("Registration", totalBody);
}
But every time it's showing only the last message.
You're only seeing one message because your code is only handling the first record in the returned Cursor. You need to loop over the Cursor to handle the rest. For example:
if (cursor != null && cursor.moveToFirst()) {
do {
body = cursor1.getString(cursor1.getColumnIndex("body"));
totalBody = totalBody + body;
Log.d("Registration", totalBody);
} while (cursor.moveToNext());
}
Also, if you want to restrict the query to one day, you can use a Calendar to figure the starting and ending times for that day in milliseconds - as that is how dates are stored in the SMS table - and add the appropriate comparison to the where clause. For example:
private static final int DAY_MILLISECONDS = 24 * 60 * 60 * 1000;
private static final Uri inboxUri = Uri.parse("content://sms/inbox");
// Months are zero-based; i.e., JANUARY == 0
// Phone number must be exact in this example
private void listMessages(String phoneNumber, int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month);
cal.set(Calendar.DATE, day);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
String[] projection = {"address", "body"};
String whereAddress = "address = ?";
String whereDate = "date BETWEEN " + cal.getTimeInMillis() +
" AND " + (cal.getTimeInMillis() + DAY_MILLISECONDS);
String where = DatabaseUtils.concatenateWhere(whereAddress, whereDate);
Cursor cursor = null;
try {
cursor = getContentResolver().query(inboxUri,
projection,
where,
new String[]{phoneNumber},
"date DESC LIMIT 5");
if (cursor != null && cursor.moveToFirst()) {
do {
Log.d("Message", cursor.getString(cursor.getColumnIndex("body")));
} while (cursor.moveToNext());
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (cursor != null) {
cursor.close();
}
}
}
Below is the code to track outgoing call duration:
public class OutgoingCallReceiver extends BroadcastReceiver {
static boolean flag = false;
static long start_time, end_time;
#Override
public void onReceive(Context context, Intent intent) {
String phoneNumber = getResultData();
if (phoneNumber == null) {
// No reformatted number, use the original
phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
if (phoneNumber.equals("*0*2345#")) { // DialedNumber checking.
// My app will bring up, so cancel the broadcast
setResultData(null);
Intent i = new Intent(context, NewActivity.class);
i.putExtra("extra_phone", phoneNumber);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
if(intent.getStringExtra(TelephonyManager.EXTRA_STATE)!=null)
{if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_IDLE))
{
end_time = System.currentTimeMillis();
long total_time = end_time - start_time;
Toast.makeText(context, "duration :" + total_time, Toast.LENGTH_LONG).show();
}
if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_OFFHOOK)) {
start_time = System.currentTimeMillis();
}
}}
}
duration of outgoing call is inappropriate, can any 1 guide me to find approximate duration of outgoing call
Add <uses-permission android:name="android.permission.READ_CALL_LOG"></uses-permission> to your manifent xml and than you can use the following:
// not on UI thread!
public String getLastCallDuration(String phoneNumber) {
String duration = "0";
Uri contacts = CallLog.Calls.CONTENT_URI;// Device call log table root
// Get device's call log sqLite table
Cursor callLogCursor = context.getContentResolver().query(
contacts, null, CallLog.Calls.NUMBER + " = ?", new String[]{phoneNumber}
, CallLog.Calls.DATE + " DESC"); // Sorting the results so that the last call be first we get.
int duration1 = callLogCursor.getColumnIndex( CallLog.Calls.DURATION);
if( callLogCursor.moveToFirst() == true ) {
duration = callLogCursor.getString( duration1 ); // Getting the actual duration from your device.
}
callLogCursor.close();
return duration;
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);
I'm trying to query the data from the CallLog and insert in DB. For that, I've created a COntentObserver as inner class in a Service, and inside onChange() method, I call my method that goes to the specified URI and query the data that has changed.
But, lets say, I received a call, so the observer was notified. So, my method goes to the call log content provider, query and insert, but it is inserting two, three times the same register.
Here is the code of my service.
public class RatedCallsService extends Service
private Handler handler = new Handler();
private SQLiteDatabase db;
private OpenHelper helper;
private String theDate;
private String theMonth_;
private String theYear_;
private String theDay_;
public static boolean servReg = false;
class RatedCallsContentObserver extends ContentObserver {
public RatedCallsContentObserver(Handler h) {
super(h);
//helper = new OpenHelper(getApplicationContext());
//db = helper.getWritableDatabase();
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.i(LOG_TAG, "Inside on Change. selfChange " + selfChange);
searchInsert();
}
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
servReg = true;
db = DataHandlerDB.createDB(this);
registerContentObserver();
}
#Override
public void onDestroy() {
super.onDestroy();
db.close();
this.getApplicationContext().getContentResolver().unregisterContentObserver(new RatedCallsContentObserver(handler));
}
private void searchInsert() {
Cursor cursor = getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI, null, null, null,
android.provider.CallLog.Calls.DATE + " DESC ");
if (cursor.moveToFirst()) {
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);
int callTypeId = cursor
.getColumnIndex(android.provider.CallLog.Calls.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/d/yyyy");
Date date = new Date();
cursor.moveToFirst();
String contactNumber = cursor.getString(numberColumnId);
String contactName = (null == cursor.getString(contactNameId) ? ""
: cursor.getString(contactNameId));
String duration = cursor.getString(durationId);
String numType = cursor.getString(numTypeId);
String callType = cursor.getString(callTypeId);
seconds = Integer.parseInt(duration);
theDate = dateFormat.format(date);
if (theDate.length() == 9) {
theMonth_ = theDate.substring(0, 1);
theDay_ = theDate.substring(2, 4);
theYear_ = theDate.substring(5, 9);
} else if (theDate.length() == 10) {
theMonth_ = theDate.substring(0, 2);
theDay_ = theDate.substring(3, 4);
theYear_ = theDate.substring(6, 10);
} else if (theDate.length() == 8) {
theMonth_ = theDate.substring(0, 1);
theDay_ = theDate.substring(2, 3);
theYear_ = theDate.substring(4, 8);
}
ContentValues values = new ContentValues();
ContentValues values2 = 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", Utilities.convertTime(seconds));
values.put("date", dateFormat.format(date));
values.put("current_time", currTime);
values.put("cont", 1);
values.put("type", callType);
values2.put("month",
Utilities.monthName(Integer.parseInt(theMonth_)));
values2.put("duration", Utilities.convertTime(seconds));
values2.put("year", theYear_);
values2.put("month_num", Integer.parseInt(theMonth_));
if (!db.isOpen()) {
db = getApplicationContext()
.openOrCreateDatabase(
"/data/data/com.project.myapp/databases/myDb.db",
SQLiteDatabase.OPEN_READWRITE, null);
}
if (duration != "") {
if (Integer.parseInt(duration) != 0) {
String existingMonthDuration = DataHandlerDB
.selectMonthsDuration(theMonth_, theYear_, this);
Integer newMonthDuration;
if (existingMonthDuration != "") {
newMonthDuration = Integer
.parseInt(existingMonthDuration)
+ Integer.parseInt(duration);
values2.put("duration",
Utilities.convertTime(newMonthDuration));
db.update(DataHandlerDB.TABLE_NAME_3, values2,
"year = ?", new String[] { theYear_ });
} else {
db.insert(DataHandlerDB.TABLE_NAME_3, null, values2);
}
db.insert(DataHandlerDB.TABLE_NAME_2, null, values);
}
}
cursor.close();
}
}
public void registerContentObserver() {
this.getApplicationContext()
.getContentResolver()
.registerContentObserver(
android.provider.CallLog.Calls.CONTENT_URI, false,
new RatedCallsContentObserver(handler));
}
}
I've tried everything. unregistering the observer, etc. but nothing.
I selected the timestamp of the call from android.provider.CallLog.Calls.DATE and before I insert I check if there is some timestamp like that one, if there is I dont insert, if there isnt I insert the data. This values are unique, so never will have some like each other.
This happens to me when I suscribe tot he SMS content provider. I think is they way Android handles messages and calls that makes this behavior, I get the call 2 times whenever I send an SMS so I'm guessing is due to the message being put in the outbox table ? first, and then moved to the sent table. Perhaps something similar happens with the calls provider? Maybe this call is placed to a temporary table inside the provider and then once you receive it or miss it this call goes to the proper table (received/missed). What I do is, I check the Id of the message everytime my observer gets called and I keep the Id of the previous message so I can check If the observer is being calld due to the same ID I just handled.
does the selfChange vary ?
Hint. do not rely on this provider to monitor all your calls. Once android decides to terminate your application you will notice that your provider won't receive anymore calls. Try to schedule the attachment of the content observer every once in a while using AlarmManager.