This periodic job stops executing after exiting the app. Works perfectly fine if the app is still running. I'm using the UsageStatsManager to gather information every 15 minutes. I tried just sending a notification every 15 minutes and it didn't work.
Here's the Scheduler code:
public class JobServiceDashboard extends android.app.job.JobService {
private static final String TAG = "JobServiceDashboard";
private static final int NOTIFICATION_ID = 141;
private boolean jobCancelled = false;
private int totalTime = 0;
private int timeLimit;
private NotificationCompat.Builder builder;
.
.
.
#Override
public boolean onStartJob(final JobParameters jobParameters) {
Log.d(TAG, "Job Started");
timeLimit = jobParameters.getExtras().getInt("limit");
Log.d(TAG, "time limit " + timeLimit);
new Thread(new Runnable() {
#Override
public void run() {
totalTime = 0;
if (jobCancelled) {
jobFinished(jobParameters, false);
}
Calendar cal = Calendar.getInstance();
cal.setTime(Calendar.getInstance().getTime());
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
long startTime = cal.getTimeInMillis();
long endTime = System.currentTimeMillis();
UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService("usagestats");
List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, startTime, endTime);
for (UsageStats us : queryUsageStats) {
totalTime += (int) us.getTotalTimeInForeground() / 60000;
}
if (totalTime > timeLimit) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext());
notificationManager.notify(NOTIFICATION_ID, builder.build());
Log.d(TAG, "Notification Sent");
jobCancelled = true;
}
Log.d(TAG, "total time: " + totalTime);
Log.d(TAG, "time limit: " + timeLimit);
}
}).start();
jobFinished(jobParameters, false);
return true;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
jobCancelled = true;
Log.d(TAG, "Job cancelled");
return false;
}
}
Related
In android studio in the MainActivity in the onCreate i did:
timerValueRecord = (TextView) findViewById(R.id.timerValueRecord);
In strings.xml i added:
<string name="timerValRecord">Recording Time: 00:00:00</string>
In activity_main.xml i added:
<TextView
android:id="#+id/timerValueRecord"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="20sp"
android:textColor="#000000"
android:layout_marginTop="315dp"
android:text="#string/timerValRecord" />
In the activity_main designer it looks like:
In the MainActivity i have a touch event:
#Override
public boolean onTouchEvent(MotionEvent event)
{
float eventX = event.getX();
float eventY = event.getY();
float lastdownx = 0;
float lastdowny = 0;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
lastdownx = eventX;
lastdowny = eventY;
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
byte[] response = null;
if (connectedtoipsuccess == true)
{
if (is_start == true)
{
response = Get(iptouse + "start");
is_start = false;
} else
{
textforthespeacch = "Recording stopped and preparing the file to be shared on youtube";
MainActivity.this.initTTS();
response = Get(iptouse + "stop");
is_start = true;
startuploadstatusthread = true;
servercheckCounter = 0;
}
if (response != null)
{
try
{
a = new String(response, "UTF-8");
MainActivity.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
if (a.equals("Recording started"))
{
status1.setText("Recording");
}
if (a.equals("Recording stopped and preparing the file to be shared on youtube"))
{
status1.setText("Recording Stopped");
}
}
});
textforthespeacch = a;
MainActivity.this.initTTS();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
Logger.getLogger("MainActivity(inside thread)").info(a);
}
}
}
});
t.start();
return true;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
return true;
}
What i want to do is when in the touch event it's true after this line:
if (is_start == true)
Start the timer and display on the timerValueRecord the time running including milliseconds seconds and minutes until the user touch again and then it's getting to the stop part and then to stop the timer.
The problem is how to build the timer at all and how to stop and start it.
You can try this below Code:
public class ShowTimer {
private long startTime = 0L;
private Handler customHandler = new Handler();
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
public void StartTimer() {
startTime = SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
}
public void StopTimer() {
timeSwapBuff += timeInMilliseconds;
customHandler.removeCallbacks(updateTimerThread);
}
private Runnable updateTimerThread = new Runnable() {
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (timeInMilliseconds / 1000);
int mins = secs / 60;
secs = secs % 60;
int hours = mins / 60;
mins = mins % 60;
//int milliseconds = (int) (updatedTime % 1000);
//+ ":" + String.format("%03d", milliseconds)
String timer = "" + String.format("%02d", hours) + ":" + String.format("%02d", mins) + ":" + String.format("%02d", secs);
//set yout textview to the String timer here
customHandler.postDelayed(this, 1000);
}
};
You can use StartTimer() and StopTimer() function where you want to start or stop the timer:
try this way
public class AndroidTimerTaskExample extends Activity {
Timer timer;
TimerTask timerTask;
//we are going to use a handler to be able to run in our TimerTask
final Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
//onResume we start our timer so it can start when the app comes from the background
startTimer();
}
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
//schedule the timer, after the first 5000ms the TimerTask will run every 10000ms
timer.schedule(timerTask, 5000, 10000); //
}
public void stoptimertask(View v) {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
//use a handler to run a toast that shows the current timestamp
handler.post(new Runnable() {
public void run() {
//get the current timeStamp
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
final String strDate = simpleDateFormat.format(calendar.getTime());
//show the toast
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(getApplicationContext(), strDate, duration);
toast.show();
}
});
}
};
}
}
Check out my app on Google Play:
Code has been updated to use suggestions given by answer, however, still running into some problems...
I am using a BroadCast Receiver within a service to get metadata from Spotify (an external application). However, Spotify is unique in the fact that it sends the following intent-actions:
metadatachanged which contains the song's artist, track, length, etc.
playbackstatechanged which contains a boolean value for "playing" and an integer value for the current position in the song.
However, I have been running into some problems. I have written the following code:
public class BackgroundService extends Service {
AudioManager am;
int positionInMs;
double eps = 5000;
String trackId = null;
String lastTrackId = null;
int lastPlayTime = 0;
int addSeconds = 0;
int trackLengthInSec = 0;
boolean playing = false;
boolean timerStarted = false;
void startTimer(){
timerStarted = true;
new Timer(true).scheduleAtFixedRate(
new TimerTask() {
#Override
public void run() {
if(playing) {
if(lastTrackId == null) {
lastTrackId = trackId;
}else if (!lastTrackId.equals(trackId)) {
addSeconds = 1;
playing = true;
lastPlayTime = positionInMs;
// Track changed. Reset counter.
}else{
addSeconds++; // Increment counter.
}
checkMuteStatus(trackLengthInSec, lastPlayTime + addSeconds * 1000 // multiply by 1000 as we're counting in seconds
);
}
Log.e("-------:", "Last Play Time: " + String.valueOf(lastPlayTime));
Log.e("-------:", "Track Length: " + String.valueOf(trackLengthInSec));
Log.e("-------:", "Current Position: " + String.valueOf(lastPlayTime + addSeconds * 1000));
}
},
1000, // Wait a second before first run
1000 // Runs every second
);
}
#Override
public void onCreate() {
super.onCreate();
am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
IntentFilter filter;
filter = new IntentFilter();
filter.addAction("com.spotify.music.playbackstatechanged");
filter.addAction("com.spotify.music.metadatachanged");
filter.addAction("com.spotify.music.queuechanged");
Notification notification = new Notification();
startForeground(1, notification);
registerReceiver(receiver, filter);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) throws NullPointerException {
long timeSentInMs = intent.getLongExtra("timeSent", 0L);
String action = intent.getAction();
if (action.equals(BroadcastTypes.METADATA_CHANGED)) {
trackId = intent.getStringExtra("id");
String artistName = intent.getStringExtra("artist");
String albumName = intent.getStringExtra("album");
String trackName = intent.getStringExtra("track");
trackLengthInSec = intent.getIntExtra("length", 0);
Log.e("STATUS:", trackName);
Log.e("STATUS:", artistName);
Log.e("STATUS:", albumName);
Log.e("STATUS:", "TRACK LENGTH: " + String.valueOf(trackLengthInSec));
Log.e("STATUS:", trackId);
Log.e("STATUS:", "POSITION: " + String.valueOf(positionInMs));
if(!timerStarted) {
startTimer();
}
//---------------------- IF PAUSED OR SONG CHANGED---------------------
} else if (action.equals(BroadcastTypes.PLAYBACK_STATE_CHANGED)) {
playing = intent.getBooleanExtra("playing", false);
positionInMs = intent.getIntExtra("playbackPosition", 0);
lastPlayTime = positionInMs;
addSeconds = 0; // Reset counter as we've now got the current position.
if(!timerStarted) {
startTimer();
}
}
}
};
void checkMuteStatus(double trackLength, double currentTime) {
if (Math.abs(trackLength - currentTime) < eps) {
mute(am);
Log.e("STATUS:", "MUTED");
addSeconds = 0;
lastPlayTime = 0;
} else {
unMute(am);
Log.e("STATUS:", "NOT MUTED");
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.e("STATUS:", "In onDestroy");
unregisterReceiver(receiver);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
static final class BroadcastTypes {
static final String SPOTIFY_PACKAGE = "com.spotify.music";
static final String PLAYBACK_STATE_CHANGED = SPOTIFY_PACKAGE + ".playbackstatechanged";
static final String METADATA_CHANGED = SPOTIFY_PACKAGE + ".metadatachanged";
}
public void mute(AudioManager audioManager){
audioManager.setStreamMute(audioManager.STREAM_SYSTEM, true);
audioManager.setStreamMute(AudioManager.STREAM_NOTIFICATION, true);
audioManager.setStreamMute(AudioManager.STREAM_ALARM, true);
audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
audioManager.setStreamMute(AudioManager.STREAM_RING, true);
}
public void unMute(AudioManager audioManager){
audioManager.setStreamMute(audioManager.STREAM_SYSTEM,false);
audioManager.setStreamMute(AudioManager.STREAM_NOTIFICATION, false);
audioManager.setStreamMute(AudioManager.STREAM_ALARM, false);
audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false);
audioManager.setStreamMute(AudioManager.STREAM_RING, false);
}
}
Which all works perfectly in getting the data, etc.
Essentially I am attempting to mute a user's phone when the length of the song subtracted from the current playback time in the song is less than a certain number. This basically allows me to have the device muted when an ad is playing, and unmuted when a new song is started. The only problem I consistently come across is that I can only access the current position in the song when the play state is changed. This essentially means that in order for my app to check whether it should mute the device, Spotify must first be paused so that the current playback time is updated.
So my question is, how can I keep my current playback time up-to-date so that my muting functionality is able to work? Is there a way I can implement a "timer" of sorts which kicks in after I receive a value for the current playback time and then increments the time until next update?
You could start a timer that executes every second when a song is played and use it to keep track of the elapsed seconds since.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) throws NullPointerException {
long timeSentInMs = intent.getLongExtra("timeSent", 0L);
String action = intent.getAction();
if (action.equals(BroadcastTypes.METADATA_CHANGED)) {
trackId = intent.getStringExtra("id");
String artistName = intent.getStringExtra("artist");
String albumName = intent.getStringExtra("album");
String trackName = intent.getStringExtra("track");
trackLengthInSec = intent.getIntExtra("length", 0);
Log.e("STATUS:", trackName);
Log.e("STATUS:", artistName);
Log.e("STATUS:", albumName);
Log.e("STATUS:", "TRACK LENGTH: " + String.valueOf(trackLengthInSec));
Log.e("STATUS:", trackId);
Log.e("STATUS:", "POSITION: " + String.valueOf(positionInMs));
// the new track id is always updated just before the next song is played
// so we can safely assume that the ad has finished playing and it's time to unmute
unMute(am);
// reset & resume the timer
lastPlayTime = 0;
addSeconds = 0;
currentlyAdPlaying = false;
if(!timerStarted)
startTimer();
//---------------------- IF PAUSED OR SONG CHANGED---------------------
} else if (action.equals(BroadcastTypes.PLAYBACK_STATE_CHANGED)) {
playing = intent.getBooleanExtra("playing", false);
positionInMs = intent.getIntExtra("playbackPosition", 0);
// this is just needed to correct an eventually existing offset from the real time.
lastPlayTime = positionInMs;
addSeconds = 0; // Reset counter as we've now got the current position.
checkMuteStatus(trackLengthInSec, positionInMs);
}
}
};
String trackId = null;
String lastTrackId = null;
int lastPlayTime = 0;
int addSeconds = 0;
int trackLengthInSec = 0;
boolean playing = false;
boolean timerStarted = false;
boolean currentlyAdPlaying = true;
void startTimer(){
timerStarted = true;
new Timer(true).scheduleAtFixedRate(
new TimerTask() {
#Override
public void run() {
if(playing && !currentlyAdPlaying) {
if(lastTrackId == null)
lastTrackId = trackId;
if(lastTrackId != trackId){
lastTrackId = trackId;
addSeconds = 1; // Track changed. Reset counter.
} else {
addSeconds++; // Increment counter.
}
checkMuteStatus(
trackLengthInSec,
lastPlayTime + addSeconds * 1000
);
}
}
},
1000, // Wait a second before first run
1000 // Runs every second
);
}
void checkMuteStatus(double trackLength, double currentTime) {
// trackLength is in seconds, but currentTime in MS.
// So we should be changing trackLength to MS as well, right?
trackLength *= 1000;
if (Math.abs(trackLength - currentTime) < eps) {
mute(am);
Log.e("STATUS:", "MUTED");
// pause the timer, for an ad is playing.
currentlyAdPlaying = true;
} else {
unMute(am);
Log.e("STATUS:", "NOT MUTED");
}
}
Basically the timer runs every second (starting when an ad has finished playing) and then increments a counter as long as the song isn't paused. On reaching the end of the song the timer is suspended as an ad will be played next. Once the ad has finished playing, the timer is reset and resumed again.
With this method you might be off by half a second or so, consider decreasing the timer interval if necessary to get a higher resolution (don't forget to adjust the multiplier though).
Edit:
The code above won't notice the user changing the track mid-song, as no broadcasts are sent on that occasion. A workaround might be to add a muting button using notifications (eg. in combination with FLAG_NO_CLEAR and FLAG_ONGOING_EVENT).
I'm Making an app which has 5 different notifications at different times every day. it works perfectly but after beta testing some users are complaining that some alarm fire again at wrong times I haven't faced this problem before and I don't know how to trace the problem so I can fix it. This is how I create the alarm:
Manager Class:(which has all the functions of the alarm)
public static Integer DEFAULT_SILENT_DURATION = 20 * 60 * 1000;
public static Integer DEFAULT_SILENT_START= 2 * 60 * 1000;
public Manager(Context applicationContext) {
this.context = applicationContext;
}
public static void acquireScreen(Context context) {
PowerManager pm = (PowerManager) context.getApplicationContext()
.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm
.newWakeLock(
(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
| PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP),
"TAG");
wakeLock.acquire();
Log.v("Check Manager acquireScreen","YES");
}
public static void releaseScreen(Context context) {
KeyguardManager keyguardManager = (KeyguardManager) context
.getApplicationContext().getSystemService(
Context.KEYGUARD_SERVICE);
KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("TAG");
keyguardLock.disableKeyguard();
Log.v("Check Manager releaseScreen","YES");
}
public static void initPrayerAlarm(Service service,
Class<PrayerReceiver> receiver) {
Manager.prayerService = service; // we may need it ?
Manager.prayerIntet = new Intent(service, receiver);
Manager.prayerPendingIntent = PendingIntent
.getBroadcast(service, 1234432, Manager.prayerIntet,
PendingIntent.FLAG_UPDATE_CURRENT);
Manager.prayerAlarmManager = (AlarmManager) service
.getSystemService(Context.ALARM_SERVICE);
Manager.prayerAlarmManager.set(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + 1000, Manager.prayerPendingIntent);
Log.v("Check Manager initPrayerAlarm",""+System.currentTimeMillis() + 1000);
}
public static void updatePrayerAlarm(long newTimeInterval) {
Manager.prayerAlarmManager.set(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + newTimeInterval,
Manager.prayerPendingIntent);
Log.v("Check Manager updatePrayerAlarm",""+System.currentTimeMillis() + newTimeInterval);
}
public void restartPrayerService(Activity activty) {
Intent intent = new Intent(activty, PrayerService.class);
context.startService(intent);
Log.v("Check Manager restartPrayerService","YES");
}
In my MainActivity I call Manager restartPrayerService function
In PrayerService I call as below:
Manager.initPrayerState(this);
Manager.initPrayerAlarm(this, PrayerReceiver.class);
and then register the receiver.
PrayerReceiver:
public class PrayerReceiver extends BroadcastReceiver {
static PrayerState prayerState;
private AudioManager am;
private Context context;
private SharedPreferences pref;
private Editor editor;
private int silentDuration;
private int silentStart ;
private int delayMilliSeconds = 1000 * 60; // one minute by default.
private Object obj;
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
pref = PreferenceManager.getDefaultSharedPreferences(this.context);
Manager m = new Manager(context);
Preference p = m.getPreference();
this.silentDuration = p.getSilentDuration();
this.silentStart = p.getSilentStart();
editor = pref.edit();
try {
prayerState = Manager.getPrayerState();
am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
switch (prayerState.getCurrentState()) {
case PrayerState.WAITING_AZAN:
{
Log.v("Check PrayerReceiver PrayerState","WAITING_AZAN");
onWaitingAzan();
}
break;
case PrayerState.DOING_AZAN:
{
Log.v("Check PrayerReceiver PrayerState","DOING_AZAN");
onDoingAzan();
}
break;
case PrayerState.WAITING_PRAYER:
{
Log.v("Check PrayerReceiver PrayerState","WAITING_PRAYER");
onWaitingPrayer();
}
break;
}
} catch (Exception e) {
// TODO Auto-generated catch block
Log.v("Check PrayerReceiver PrayerState","ERROR");
}
}
public int getDelayMilliSeconds() {
return delayMilliSeconds;
}
public void setDelayMilliSeconds(int delayMilliSeconds) {
this.delayMilliSeconds = delayMilliSeconds;
}
private void onWaitingAzan() {
try {
boolean isRingerModeChangedToSilent = pref.getBoolean(
"isRingerModeChangedToSilent", false);
if (isRingerModeChangedToSilent == true) {
am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
editor.putBoolean("isRingerModeChangedToSilent", false);
editor.commit();
}
// What is the remaining time until the next prayer ?
Date date = new Date();
int dd = date.getDate();
int mm = date.getMonth() + 1;
int yy = date.getYear() + 1900;
int h = date.getHours();
int m = date.getMinutes();
int s = date.getSeconds();
int nearestPrayerTime = Manager.computeNearestPrayerTime(context,
h, m, s, yy, mm, dd);
int deffTime = TimeHelper.different((h * 3600 + m * 60 + s),
nearestPrayerTime);
deffTime = deffTime * 1000; // to milliseconds
// ok , come back after X seconds to do the Azan
prayerState.setNextState(PrayerState.DOING_AZAN);
Manager.updatePrayerAlarm(deffTime);
} catch (Exception e) {
Log.v("Check PrayerReceiver onWaitingAzan","ERROR");
}
}
private void onDoingAzan() {
prayerState.setNextState(PrayerState.WAITING_PRAYER);
int delay = this.silentStart;
if(delay < 2000*60)
delay =2000*60; // two minutes - at lease
Log.v("Check PrayerReceiver onDoingAzan","delay "+delay);
Manager.playAzanNotification(context);
Manager.updatePrayerAlarm(delay);
}
private void onWaitingPrayer() {
Manager manager = new Manager(this.context);
Preference preference = manager.getPreference();
AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
if(am.getRingerMode() == AudioManager.RINGER_MODE_NORMAL && preference.isAutoSilentDisabled()==false ){
am.setRingerMode(AudioManager.RINGER_MODE_SILENT);
editor.putBoolean("isRingerModeChangedToSilent", true);
editor.commit();
}
this.delayMilliSeconds = silentDuration;
prayerState.setNextState(PrayerState.WAITING_AZAN);
Manager.updatePrayerAlarm(delayMilliSeconds);
}
Can some one please help me,exactly what am I doing wrong?
Manager.prayerAlarmManager.set is not set exact on the specified time on api 19 and above. That is probably why "some" users complain.
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
On api 19 and above you need setExact to schedule at a specific time
You will need something like this:
if(android.os.Build.VERSION.SDK_INT >= 19) {
// setExact
}
else {
//set
}
I am trying to run a simple clock in my activity, the purpose of the project is to create a secondary thread to run our clock on and update our main UI thread using a handler. I thought I had it working but I guess I was looking at something wrong. Either way, here is my code
public class MainActivity extends Activity implements Runnable{
/** VARIABLES **/
private LinearLayout currView;
private TextView clock;
private Typeface icelandFace;
private Calendar cal;
// clock time values
private int clockMins;
private int clockHour;
private int timeOfDay; // am/pm
private String currTimeString;
// for alarm clock
boolean startAlarm = false;
private long alarmStartTime = -1;
private final int DESIRED_ALARM_DURATION = 5;
// clock thread handler, to communicate between our main ui and our secondary ui
// - note to self - rather unclear on the explanation for the suppression for the handler
private Handler handler = new Handler();
// runnable variable for the secondary thread to actually run on
private final Runnable clockRunnable = new Runnable(){
public void run(){
updateUI();
}
};
/** OVERRIDDEN CLASS METHODS **/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
currView = (LinearLayout) findViewById(R.id.main_activity);
clock = (TextView) findViewById(R.id.clock_view);
clock.setTextSize(clock.getTextSize() * 2);
icelandFace = Typeface.createFromAsset(getAssets(), "font/Iceland-Regular.ttf");
clock.setTypeface(icelandFace);
cal = Calendar.getInstance();
// Create New Thread (to run our clock on)
Thread clockThread = new Thread(){
public void run() {
keepTime();
clockMins = cal.get(Calendar.MINUTE);
clockHour = cal.get(Calendar.HOUR);
timeOfDay = cal.get(Calendar.AM_PM);
// Implement the handler for the thread
// NOTE: recall, Message contains data and is passed to our handler
//Message message = handler.obtainMessage();
Bundle bundle = new Bundle();
// start with hours
String timeString = clockHour + ":";
// add minutes
if(clockMins < 10){
timeString = timeString + "0" + clockMins + " ";
}
else{
timeString = timeString + clockMins + " ";
}
// set time of day
if(timeOfDay == 0){
timeString = timeString + "am";
}
else{
timeString = timeString + "pm";
}
// Optional bundle stuff
//bundle.putString("time_string", timeString);
//message.setData(bundle);
Log.d("Runnable", "Tracking time # " + timeString);
currTimeString = timeString;
handler.post(clockRunnable);
}
private void keepTime(){
clockMins = cal.get(Calendar.MINUTE);
clockHour = cal.get(Calendar.HOUR);
timeOfDay = cal.get(Calendar.AM_PM);
checkAlarm(clockHour, clockMins, timeOfDay);
}
private void checkAlarm(int hour, int min, int timeOfDay){
SharedPreferences alarmPref = getSharedPreferences("alarm_preferences", MODE_PRIVATE);
int alarmHour = alarmPref.getInt("alarm_hour", -1);
int alarmMin = alarmPref.getInt("alarm_min", -1);
int alarmTimeOfDay = alarmPref.getInt("alarm_time_of_day", 0);
boolean alarmOn = alarmPref.getBoolean("alarm_on", true);
if(hour == alarmHour && min == alarmMin && timeOfDay == alarmTimeOfDay && alarmOn == true
&& alarmStartTime != -1){
startAlarm = true;
}
return;
}
};
clockThread.start();
}
//TODO: Setup the alarm via the menu that inflates here
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.alarm, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case R.id.alarm_settings:
startActivity(new Intent(this, AlarmPopup.class));
Toast.makeText(this, "Open Up Alarm Dialog", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void run()
{
while (clockRunnable != null)
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e) { };
handler.post(clockRunnable);
}
}
/** PRIVATE METHODS FOR SIMPLIFICATION **/
private void updateUI(){
if(startAlarm == true){
//AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmStartTime = cal.get(Calendar.SECOND);
currView.setBackgroundColor(Color.RED);
}
else if((cal.get(Calendar.SECOND) - alarmStartTime) > DESIRED_ALARM_DURATION){
alarmStartTime = -1;
startAlarm = false;
currView.setBackgroundColor(Color.WHITE);
}
clock.setText(currTimeString);
}
Obviously I am missing something as far as grasping what is going on, but I can't tell what. Create a background thread, run your processes, pass it through the handler to control the variables, and send those variables through your UI update. I used http://developer.android.com/guide/faq/commontasks.html to gain that understanding.
Instead of making the activity implement Runnable, try this:
TimerTask task = new TimerTask() {
#Override
public void run() {
handler.post(clockRunnable);
}
};
Timer timer = new Timer();
timer.schedule(task, 0, 1000);
Even though I would use a different approach registering a BroadcastReceiver to receive tick actions from the system (every second).
Regards.
I want to implement a schedule function in my android project. So I Googled for an Alarm manager program but I can`t Resolve Problem.
I want set alarm with custom time that users Determine. I wrote 2 class for service and BroadcastReciver. But alarm is inccorect for example i set 2 min for alarm.but app Arbitrary is work .eg 2 min or 3 or 5 or 1min....
mainActivity:
SharedPreferences preferences1 = getSharedPreferences("min", 0);
String min1 = preferences1.getString("minute", "");
if (min1.length() <= 0) {
s = 120000;
} else {
s = Long.parseLong(min1);
s = s * 60000;
}
t = new Timer();
// Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// Called each time when 1000 milliseconds (1 second)
// (the period parameter)
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 10);
Intent intent = new Intent(CategoryListActivity.this,
Service_class.class);
PendingIntent pintent = PendingIntent.getService(
CategoryListActivity.this, 0, intent, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(), s, pintent);
Log.e("Timer", t.toString());
}
},
// Set how long before to start calling the TimerTask (in
// milliseconds)
0,
// Set the amount of time between each execution (in
// milliseconds)
s);
service_class.java :
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
dbflash = new DatabaseFlashCard(getApplicationContext());
db = dbflash.getReadableDatabase();
SharedPreferences preferences_notify = getSharedPreferences("notify", 0);
Calendar c = Calendar.getInstance();
String time_one = preferences_notify.getString("time_first", "");
String time_two = preferences_notify.getString("time_second", "");
int hour = c.get(Calendar.HOUR_OF_DAY);
if (time_one.length() <= 0) {
time_one = "21";
}
if (time_two.length() <= 0) {
time_two = "5";
}
int timeFirst = Integer.parseInt(time_one);
int timeSecond = Integer.parseInt(time_two);
if (hour < timeFirst && hour > timeSecond) {
// nothing
} else {
// notify and alert
preferences_language = getSharedPreferences("language_sql", 0);
editor_language = preferences_language.edit();
String language = preferences_language.getString("language", "");
String sql="SELECT * FROM " + dbflash.TABLE
+ " where hide='0' ORDER BY RANDOM() LIMIT 1";
if(language.length()>0)
{
if(language.equalsIgnoreCase("0"))
{
sql="SELECT * FROM " + dbflash.TABLE
+ " where hide='0' ORDER BY RANDOM() LIMIT 1";
}
else
{
sql="SELECT * FROM " + dbflash.TABLE
+ " where ids="+language+" and hide='0' ORDER BY RANDOM() LIMIT 1";
}
Cursor cursors = db.rawQuery(sql, null);
for (int i = 0; i < cursors.getCount(); i++) {
cursors.moveToNext();
ID = cursors.getString(cursors.getColumnIndex("ID"));
farsi = cursors.getString(cursors.getColumnIndex("farsi"));
english = cursors.getString(cursors.getColumnIndex("english"));
question = cursors
.getString(cursors.getColumnIndex("question"));
count = cursors.getString(cursors.getColumnIndex("count"));
}
preferences_status = getSharedPreferences("notify_status", 0);
String status = preferences_status.getString("status", "");
SharedPreferences.Editor editor_status;
editor_status = preferences_status.edit();
if (status.length() <= 0) {
status="1";
editor_status.putString("status", "1");
editor_status.commit();
Log.e("Notification Status ", "Enable Now..for First");
} else if(status.equalsIgnoreCase("0")) {
Log.e("Notification Status ", "disable");
}
else
{
Log.e("Notification Status ", "enable");
if (english==null || english=="") {
} else {
SharedPreferences preferences = getSharedPreferences("music", 0);
String address=preferences.getString("address", "");
if(address.length()<=0)
{
mp = MediaPlayer.create(getApplicationContext(), R.raw.ring);
mp.start();
}
else
{
mp = MediaPlayer.create(getApplicationContext(),Uri.parse(address));
mp.start();
}
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent contentIntent = new Intent(this,
QuestionActivity.class);
contentIntent.putExtra("ID", ID);
contentIntent.putExtra("english", english);
contentIntent.putExtra("farsi", farsi);
contentIntent.putExtra("count", count);
contentIntent.putExtra("question", question);
Notification notification = new Notification(
R.drawable.icon, "یاد آوری",
System.currentTimeMillis());
notification.setLatestEventInfo(this, english, "",
PendingIntent.getActivity(this.getBaseContext(), 0,
contentIntent,
PendingIntent.FLAG_CANCEL_CURRENT));
notification.flags = Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(SIMPLE_NOTFICATION_ID,
notification);
}
}
}
}
return START_STICKY;
}
and Myreceiver
public class Myreceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Intent serviceLauncher = new Intent(context, Service_class.class);
context.startService(serviceLauncher);
}
Android Manifest :
<service android:name=".Service_class" />
<receiver
android:name="com.pttat.flashcard.services.Myreceiver"
android:process=":remote" />
how to change my code for Resolve my Problem?
Do I need to change calling alarm manager in Oncreate?
thanks