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>
Related
I am trying to track phone call states and log. I need phone numbers, name(if it is a saved contact) and time of the call and duration. The problem is that getContentResolver() method cannot be called, its commented in code.
public class PhoneStateBroadcastReciever extends BroadcastReceiver {
Context m_context;
String m_number = null;
String m_startTime = null;
String m_endTime = null;
SharedPreferences m_sharedPrefs;
Editor editor;
static String PREFS_NUMBER;
static String PREFS_START_TIME;
static String PREFS_END_TIME;
#Override
public void onReceive(Context context, Intent intent) {
m_sharedPrefs = m_context.getSharedPreferences("MyPrefs", 0);
editor = m_sharedPrefs.edit();
Bundle bundle = intent.getExtras();
if (bundle == null)
return;
String state = bundle.getString(TelephonyManager.EXTRA_STATE);
if ((state != null) &&
(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING))) {
Log.i("TAG", "incoming call");
Uri contactUri = intent.getData();
String[] projection = { Phone.DISPLAY_NAME };
//i cannot use getContentResolver()
Cursor cursor = getContentResolver()..query(contactUri, projection, null,
null, null);
int columnName = cursor.getColumnIndex(Phone.DISPLAY_NAME);
String contactName = cursor.getString(columnName);
m_number = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
editor.putString(PREFS_NUMBER, m_number);
editor.commit();
} else if(state == null) {
Log.i("TAG", "outgoing call");
Uri contactUri = intent.getData();
String[] projection = { Phone.DISPLAY_NAME };
//i cannot use getContentResolver()
Cursor cursor = getContentResolver()..query(contactUri, projection, null,
null, null);
int columnName = cursor.getColumnIndex(Phone.DISPLAY_NAME);
String contactName = cursor.getString(columnName);
m_number = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
editor.putString(PREFS_NUMBER, m_number);
editor.commit();
} else if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
Log.i("TAG", "off hook");
Time dtstart = new Time(Time.getCurrentTimezone());
dtstart.setToNow();
m_startTime = dtstart.format("%k:%M:%S");
editor.putString(PREFS_START_TIME, m_startTime);
editor.commit();
} else if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)) {
Log.i("TAG", "on idle");
Time dtend = new Time(Time.getCurrentTimezone());
dtend.setToNow();
m_endTime = dtend.format("%k:%M:%S");
editor.putString(PREFS_END_TIME, m_endTime);
editor.commit();
}
}
this is the service class:
public class TrackerService extends Service {
PhoneStateBroadcastReciever receiver;
#Override
public void onCreate() {
receiver = new PhoneStateBroadcastReciever();
IntentFilter filter = new IntentFilter();
filter.addAction(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED);
registerReceiver(receiver, filter);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "starting service", Toast.LENGTH_SHORT).show();
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onDestroy() {
unregisterReceiver(receiver);
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
Use the Context to invoke the contentResolver(). Something like that:
context.getContentResolver()....
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 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'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.
I'm trying to implement a ContentObserver for CallLog.Calls content provider. I mean, If I make a call, or receive a call, etc, the observer must notify me that the CallLog.Calls content provider has changed. But the onchange method only returns false, even with the observers registered, and notified. Maybe I'm doing something wrong.
This is my code. It's an Activity.
package com.psyhclo;
public class RatedCalls extends ListActivity {
private static final String LOG_TAG = "RatedCallsObserver";
private Handler handler = new Handler();
private RatedCallsContentObserver callsObserver = null;
private SQLiteDatabase db;
private CallDataHelper dh = null;
StringBuilder sb = new StringBuilder();
OpenHelper openHelper = new OpenHelper(RatedCalls.this);
class RatedCallsContentObserver extends ContentObserver {
public RatedCallsContentObserver(Handler h) {
super(h);
}
public void onChange(boolean selfChange) {
Log.d(LOG_TAG, "RatedCallsContentObserver.onChange( " + selfChange
+ ")");
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerContentObservers();
fillList();
}
#Override
public void onStart() {
super.onStart();
registerContentObservers();
}
#Override
public void onStop() {
super.onStop();
unregisterContentObservers();
}
private void fillList() {
Cursor cursor = getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI, null, null, null,
android.provider.CallLog.Calls.DATE + " DESC ");
cursor.setNotificationUri(getBaseContext().getContentResolver(),
android.provider.CallLog.Calls.CONTENT_URI);
dh = new CallDataHelper(this);
db = openHelper.getWritableDatabase();
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 dateId = cursor.getColumnIndex(android.provider.CallLog.Calls.DATE);
int numTypeId = cursor
.getColumnIndex(android.provider.CallLog.Calls.CACHED_NUMBER_TYPE);
// int contactIdColumnId =
// cursor.getColumnIndex(android.provider.ContactsContract.RawContacts.CONTACT_ID);
Date dt = new Date();
int hours = dt.getHours();
int minutes = dt.getMinutes();
int seconds = dt.getSeconds();
String currTime = hours + ":" + minutes + ":" + seconds;
ArrayList<String> callList = new ArrayList<String>();
if (cursor.moveToFirst()) {
do {
String contactNumber = cursor.getString(numberColumnId);
String contactName = cursor.getString(contactNameId);
String duration = cursor.getString(durationId);
String callDate = DateFormat.getDateInstance().format(dateId);
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", callDate);
values.put("current_time", currTime);
values.put("cont", 1);
getBaseContext().getContentResolver().notifyChange(
android.provider.CallLog.Calls.CONTENT_URI, null);
this.db.insert(CallDataHelper.TABLE_NAME, null, values);
Toast.makeText(getBaseContext(), "Inserted!", Toast.LENGTH_LONG);
callList.add("Contact Number: " + contactNumber
+ "\nContact Name: " + contactName + "\nDuration: "
+ duration + "\nDate: " + callDate);
} while (cursor.moveToNext());
}
setListAdapter(new ArrayAdapter<String>(this, R.layout.listitem,
callList));
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(getApplicationContext(),
((TextView) view).getText(), Toast.LENGTH_SHORT).show();
}
});
}
private void registerContentObservers() {
ContentResolver cr = getContentResolver();
callsObserver = new RatedCallsContentObserver(handler);
cr.registerContentObserver(android.provider.CallLog.Calls.CONTENT_URI,
true, callsObserver);
}
private void unregisterContentObservers() {
ContentResolver cr = getContentResolver();
if (callsObserver != null) { // just paranoia
cr.unregisterContentObserver(callsObserver);
callsObserver = null;
}
}
}
This is the answer for this question.
Android onChange() method only returns false