I have a counter with a circular progress bar. When the counter starts, the progress bar is also starting from counter value, but when it's running in the background and again open app... the circular progress bar starts from 0, but the counter runs correctly as per value. In this case I need the progress bar not to start from 0.
here is my code:
public class MainActivity extends AppCompatActivity {
public int counter;
Button button;
public boolean isrunningtime = false;
TextView textView;
private ProgressBar progressBar;
long millisUntilFinished = 0;
SharedPreferences sharedPreferences;
SharedPreferences.Editor editor;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
sharedPreferences = getSharedPreferences("my", MODE_PRIVATE);
editor = sharedPreferences.edit();
progressBar = findViewById(R.id.progressBar);
startService(new Intent(this, BroadcastService.class));
Log.i("Tag", "Started service");
}
private BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateGUI(intent); // or whatever method used to update your GUI fields
}
};
#Override
public void onResume() {
super.onResume();
registerReceiver(br, new IntentFilter(BroadcastService.COUNTDOWN_BR));
Log.i("Tag", "Registered broacast receiver");
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(br);
}
#Override
public void onStop() {
try {
unregisterReceiver(br);
} catch (Exception e) {
// Receiver was probably already stopped in onPause()
}
super.onStop();
}
#Override
public void onDestroy() {
stopService(new Intent(this, BroadcastService.class));
Log.i("Tag", "Stopped service");
super.onDestroy();
}
private void updateGUI(Intent intent) {
if (intent.getExtras() != null) {
millisUntilFinished = intent.getLongExtra("countdown", 0);
Log.i("Tag", "Countdown seconds remaining: " + millisUntilFinished / 1000);
progressBar.setProgress((int) (millisUntilFinished / 1000));
Log.i("progress", "" + (int) (millisUntilFinished / 1000));
textView.setText("" + millisUntilFinished / 1000);
}
}
}
put the unregisterReceiver(br) only in onDestroy() instead of onStop() and onPause()
Remove unregisterReceiver(br); from onStop() and onPause(), And Move registerReceiver(br, new IntentFilter(BroadcastService.COUNTDOWN_BR)); from onResume() to onCreate()
Related
I am Trying to Implement a service where when I a select a time, the timer starts and runs in the background. the thing is working fine. but when I select another time, the timer overlaps on one another. I want my app to work in such a way that different services should run for different time. also, when I kill the app and reopen it, I get the remaining time in all the services.
however my data is coming from a web service and this web service contains a field with time. when I click the time, the above concept should start.
I have implemented my code as,
BroadCastService.java
public class BroadCastService extends Service {
private long totalTimeCountInMilliseconds;
private long timeBlinkInMilliseconds;
private CountDownTimer countDownTimer;
private boolean blink;
String getTime;
public static final String COUNTDOWN_BR = "project.uop.assignment8";
Intent bi = new Intent(COUNTDOWN_BR);
public BroadCastService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//return super.onStartCommand(intent, flags, startId);
getTime = intent.getStringExtra("time");
setTimer();
startTimer();
Log.i("madhura","madhura");
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
}
private void setTimer() {
int time = 0;
//if (getTime.equals("")) {
time = Integer.parseInt(getTime);
// } else
/* Toast.makeText(BroadCastService.this, "Please Enter Minutes...",
Toast.LENGTH_LONG).show();*/
totalTimeCountInMilliseconds = 60 * time * 1000;
timeBlinkInMilliseconds = 30 * 1000;
}
private void startTimer() {
countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 500) {
#Override
public void onTick(long leftTimeInMilliseconds) {
long seconds = leftTimeInMilliseconds / 1000;
if (leftTimeInMilliseconds < timeBlinkInMilliseconds) {
if (blink) {
// mTextField.setVisibility(View.VISIBLE);
// if blink is true, textview will be visible
} else {
// mTextField.setVisibility(View.INVISIBLE);
}
blink = !blink;
}
String a = String.format("%02d", seconds / 60) + ":" + String.format("%02d", seconds % 60);
bi.putExtra("countdown", a);
sendBroadcast(bi);
}
#Override
public void onFinish() {
Toast.makeText(BroadCastService.this, "Finished", Toast.LENGTH_SHORT).show();
}
}.start();
}
}
and my TimerActivity.class
public class TimerActivity extends AppCompatActivity {
TextView mTextField;
TextView hotel;
private long totalTimeCountInMilliseconds;
private long timeBlinkInMilliseconds;
private CountDownTimer countDownTimer;
private boolean blink;
String getTime;
SessionManager sessionManager;
Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
InitializeToolbar();
Intent in = getIntent();
getTime = in.getStringExtra("time");
Intent intent = new Intent(this,BroadCastService.class);
intent.putExtra("time",getTime);
this.startService(intent);
sessionManager = new SessionManager(this);
hotel = findViewById(R.id.textView);
hotel.setText(sessionManager.getUserName());
Log.i("started", "Started service");
mTextField = findViewById(R.id.timer);
}
public void InitializeToolbar(){
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setTitle("Order Notification");
}
private BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateGUI(intent); // or whatever method used to update your GUI fields
}
};
#Override
public void onResume() {
super.onResume();
registerReceiver(br, new IntentFilter(BroadCastService.COUNTDOWN_BR));
Log.i("efgh", "Registered broacast receiver");
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(br);
Log.i("abcd", "Unregistered broadcast receiver");
}
#Override
public void onStop() {
try {
unregisterReceiver(br);
} catch (Exception e) {
// Receiver was probably already stopped in onPause()
}
super.onStop();
}
#Override
public void onDestroy() {
stopService(new Intent(this, BroadCastService.class));
Log.i("Stopped", "Stopped service");
super.onDestroy();
}
private void updateGUI(Intent intent) {
if (intent.getExtras() != null) {
String millisUntilFinished = intent.getStringExtra("countdown");
mTextField.setText(millisUntilFinished);
}
}
}
thanks in advance.
Use Handler and #Overide its method Handler#handleMessage(Message msg)
See this: https://gist.github.com/mjohnsullivan/403149218ecb480e7759
I am trying to make a basic music player with bound services. The problem is MP plays less time that track duration is. I compared the times when MP finished and saw what happens but can not figure out why. Can anyone help?
Here is my logcat when MP finished.
#Override
public void onCompletion(MediaPlayer mp) {
Toast.makeText(this, "Media Completed", Toast.LENGTH_SHORT).show();
Log.i("TEST", "TOTAL DUR: " + mp.getDuration() + " CURRENT DUR: " + mp.getCurrentPosition() + "");
}
I/TEST: TOTAL DUR: 193131 CURRENT DUR: 186932
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener, SeekBar.OnSeekBarChangeListener{
private String msg = "Android : ";
private TextView tvTime;
private Button btnPlay, btnPause, btnRestart;
private LocalService mService;
private boolean mBound = false;
// ----- seekbar variables -----------
private SeekBar seekBar;
private int seekMax;
private boolean mBroadcastIsRegistered;
// ---- broadcast action and intent for fromuser seekbar
public static final String BROADCAST_SEEKBAR_FROMUSER = "ysfcyln.musicplayerdemo.send_seekbar_fromUser";
Intent mIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvTime = (TextView) findViewById(R.id.textView);
seekBar = (SeekBar) findViewById(R.id.seekBar);
btnPlay = (Button) findViewById(R.id.btn_play);
btnPause = (Button) findViewById(R.id.btn_pause);
btnRestart = (Button) findViewById(R.id.btn_restart);
seekBar.setOnSeekBarChangeListener(this);
btnPlay.setOnClickListener(this);
btnPause.setOnClickListener(this);
btnRestart.setOnClickListener(this);
Log.d(msg, "The onCreate() event");
Intent intent = new Intent(this, LocalService.class);
startService(intent);
// set up seekbar intent for broadcasting new position to service
mIntent = new Intent(BROADCAST_SEEKBAR_FROMUSER);
}
/** Called when the activity is about to become visible. */
#Override
protected void onStart() {
super.onStart();
Log.d(msg, "The onStart() event");
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
/** Called when the activity has become visible. */
#Override
protected void onResume() {
// ---- register broadcast -----
goRegisterBroadcast();
super.onResume();
Log.d(msg, "The onResume() event");
}
/** Called when another activity is taking focus. */
#Override
protected void onPause() {
// ---- unregister broadcast ----
unRegisterBroadcast();
super.onPause();
Log.d(msg, "The onPause() event");
}
/** Called when the activity is no longer visible. */
#Override
protected void onStop() {
super.onStop();
Log.d(msg, "The onStop() event");
}
/** Called just before the activity is destroyed. */
#Override
public void onDestroy() {
super.onDestroy();
Log.d(msg, "The onDestroy() event");
Log.d("mbound value", mBound + "");
if (mBound) {
Intent intent=new Intent(this,LocalService.class);
stopService(intent);
unbindService(mConnection);
mBound = false;
}
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_play:
//do something
if (mBound)
mService.playSong2("http://www.mfiles.co.uk/mp3-downloads/edvard-grieg-peer-gynt1-morning-mood-piano.mp3");
break;
case R.id.btn_pause:
//do something
if (mBound)
mService.pauseSong();
break;
case R.id.btn_restart:
//do something
if (mBound)
mService.restartSong();
break;
default:
break;
}
}
/** Defines callbacks for service binding, passed to bindService() */
public ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
#Override
public void onBackPressed(){
// this moves to activity to the back of the stack, effectively pausing it
moveTaskToBack(true);
}
// ---- updating position of seekbar from service
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}
};
private void updateUI(Intent intent){
String counter = intent.getStringExtra("counter");
String mediamax = intent.getStringExtra("mediamax");
int seekProgress = Integer.parseInt(counter);
seekMax = Integer.parseInt(mediamax);
seekBar.setMax(seekMax);
seekBar.setProgress(seekProgress);
final int HOUR = 60*60*1000;
final int MINUTE = 60*1000;
final int SECOND = 1000;
int durationInMillis = seekMax;
int curVolume = seekProgress;
int durationHour = durationInMillis/HOUR;
int durationMint = (durationInMillis%HOUR)/MINUTE;
int durationSec = (durationInMillis%MINUTE)/SECOND;
int currentHour = curVolume/HOUR;
int currentMint = (curVolume%HOUR)/MINUTE;
int currentSec = (curVolume%MINUTE)/SECOND;
if(durationHour > 0){
tvTime.setText(" 1 = "+String.format("%02d:%02d:%02d/%02d:%02d:%02d",
currentHour,currentMint,currentSec, durationHour,durationMint,durationSec));
}else{
tvTime.setText(" 1 = "+String.format("%02d:%02d/%02d:%02d",
currentMint,currentSec, durationMint,durationSec));
}
}
// --- unregister receiver for seekbar ---
private void unRegisterBroadcast(){
if(mBroadcastIsRegistered){
try {
unregisterReceiver(broadcastReceiver);
mBroadcastIsRegistered = false;
} catch (Exception e){
e.printStackTrace();
}
}
}
// --- register receiver for seekbar ---
private void goRegisterBroadcast(){
registerReceiver(broadcastReceiver, new IntentFilter(mService.BROADCAST_ACTION));
mBroadcastIsRegistered = true;
}
// Override methods for seekbar on change listener
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser){
int seekPos = seekBar.getProgress();
mIntent.putExtra("seekpos", seekPos);
sendBroadcast(mIntent);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
LocalService.java
public class LocalService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener{
private MediaPlayer player;
public LocalService() {
}
// Returns the MyService instance
public class LocalBinder extends Binder {
public LocalService getService(){
return LocalService.this;
}
}
private IBinder mBinder = new LocalBinder();
// ---- SeekBar Variables --------------
int mediaPosition;
int mediaMax;
private final Handler handler = new Handler();
public static final String BROADCAST_ACTION = "ysfcyln.musicplayerdemo.seekprogress";
Intent seekIntent;
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
//throw new UnsupportedOperationException("Not yet implemented");
Log.i("Service Demo", "In onBind");
return mBinder;
}
/** Called when the service is being created. */
#Override
public void onCreate() {
super.onCreate();
Log.i("Service Demo", "Service Created");
player = new MediaPlayer();
initMusicPlayer();
// ----- Setup intent for seekbar -----------
seekIntent = new Intent(BROADCAST_ACTION);
// --- register for fromuser seekbar ----
registerReceiver(broadcastReceiver, new IntentFilter(MainActivity.BROADCAST_SEEKBAR_FROMUSER));
}
/** The service is starting, due to a call to startService() */
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//return super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
/** Called when The service is no longer used and is being destroyed */
#Override
public void onDestroy() {
// stop the seekbar handler from sending updates to UI
handler.removeCallbacks(sendUpdatesToUI);
// unregister receiver to user input from seekbar
unregisterReceiver(broadcastReceiver);
super.onDestroy();
Log.i("Service Demo", "Service Destroyed");
}
/** Called when all clients have unbound with unbindService() */
#Override
public boolean onUnbind(Intent intent) {
Log.i("Service Demo", "In onUnbind");
player.stop();
player.reset();
player.release();
return super.onUnbind(intent);
}
/** Called when a client is binding to the service with bindService()*/
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
// to initialize the media class
public void initMusicPlayer(){
player.setWakeMode(getApplicationContext(),
PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
}
#Override
public void onPrepared(MediaPlayer mp) {
//start playback
mp.start();
// ---- set up seekbar handler ----
setUpHandler();
}
// -------- Send seekbar info to Activity ------
private void setUpHandler(){
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000); // 1 Second
}
private Runnable sendUpdatesToUI = new Runnable() {
#Override
public void run() {
LogMediaPosition();
handler.postDelayed(this,1000); // 1 Second
}
};
private void LogMediaPosition(){
if(player.isPlaying()){
mediaPosition = player.getCurrentPosition();
mediaMax = player.getDuration();
seekIntent.putExtra("counter", String.valueOf(mediaPosition));
seekIntent.putExtra("mediamax", String.valueOf(mediaMax));
sendBroadcast(seekIntent);
}
}
// ---------- Receive seekbar position if it has been changed by the user in the activity ----
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateSeekPos(intent);
}
};
private void updateSeekPos(Intent intent){
int seekPos = intent.getIntExtra("seekpos", 0);
if(player.isPlaying()){
handler.removeCallbacks(sendUpdatesToUI);
player.seekTo(seekPos);
setUpHandler();
}
}
public void playSong(){
//play a song
player.reset();
String songUrl = "http://www.mfiles.co.uk/mp3-downloads/edvard-grieg-peer-gynt1-morning-mood-piano.mp3";
try{
player.setDataSource(getApplicationContext(), Uri.parse(songUrl));
}
catch(Exception e){
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.prepareAsync();
}
public void pauseSong(){
if(player.isPlaying()){
player.pause();
} else {
player.start();
}
}
public void restartSong(){
if(player.isPlaying()){
player.stop();
player.release();
} else {
player.release();
}
}
// With input
public void playSong2(String songUrl){
//play a song
player.reset();
try{
player.setDataSource(getApplicationContext(), Uri.parse(songUrl));
}
catch(Exception e){
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.prepareAsync();
}
#Override
public void onCompletion(MediaPlayer mp) {
Toast.makeText(this, "Media Completed", Toast.LENGTH_SHORT).show();
Log.i("TEST", "TOTAL DUR: " + mp.getDuration() + "CURRENT DUR: " + mp.getCurrentPosition() + "");
}
}
I tested it with two device, Samsung Galaxy A7 and Samsung Galaxy S4. Song Duration is 3:13, A7 finished it 3:12 and S4 finished it 3:06
i would developing a feature in my app that when click on button on my activity launch a service that start,pause and resume a Chronometer.
But I have a problem how start and stop in my background service.
I created my Activity
public class StartWorkActivity extends ActivityGeneralToolbar {
protected final void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState, R.layout.activity_start_work);
Chronometer chronometer = (Chronometer) findViewById(R.id.chronometer);
}
#Override
protected void onStop() {
super.onStop();
}
public void startWork(View v){
Intent msgIntent = new Intent(StartWorkActivity.this, WorkTimerService.class);
msgIntent.setAction("START_TIMER");
getBaseContext().startService(msgIntent);
}
public void pauseWork(View v){
Intent msgIntent = new Intent(StartWorkActivity.this, WorkTimerService.class);
msgIntent.setAction("PAUSE_TIMER");
}
public void resumeWork(View v){
//call service
Intent msgIntent = new Intent(StartWorkActivity.this, WorkTimerService.class);
msgIntent.setAction("RESUME_TIMER");
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
}
}
And my WorkTimerService
public class WorkTimerService extends IntentService {
long timeWhenStopped = 0;
Chronometer chronometer;
public WorkTimerService() {
super("SystemService");
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
protected void onHandleIntent(Intent intent) {
if(intent.getAction() == "START_TIMER"){
startWork();
}
if(intent.getAction() == "PAUSE_TIMER"){
pauseWork();
}if(intent.getAction() == "RESUME_TIMER"){
resumeWork();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags,startId);
return START_STICKY;
}
public void pauseWork(){
timeWhenStopped = chronometer.getBase() - SystemClock.elapsedRealtime();
chronometer.stop();
}
public void resumeWork(){
chronometer.setBase(SystemClock.elapsedRealtime() + timeWhenStopped);
timeWhenStopped = 0;
chronometer.start();
}
public void startWork(){
chronometer.start();
}
}
But my problem is that Chronometer obviously is null in my service, because I read that is not possible, in the service, interact with the ui.
And so, how i can send, or work with Chronometer in background?
Chronometer is a UI widget (actually a TextView) in Android. So, you can't use it for non-UI purposes. Try to use Timer or CountDownTimer instead.
See this for an example usage of Timer inside Service: https://stackoverflow.com/a/3819721/5250273
How to use timer in android for auto logout after 15 minutes due to inactivity of user?
I am using bellow code for this in my loginActivity.java
public class BackgroundProcessingService extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
timer = new CountDownTimer(5 *60 * 1000, 1000) {
public void onTick(long millisUntilFinished) {
//Some code
//inactivity = true;
timer.start();
Log.v("Timer::", "Started");
}
public void onFinish() {
//Logout
Intent intent = new Intent(LoginActivity.this,HomePageActivity.class);
startActivity(intent);
//inactivity = false;
timer.cancel();
Log.v("Timer::", "Stoped");
}
};
return null;
}
}
and onclick of login button I have called intent for service.
Intent intent1 = new Intent(getApplicationContext(),
AddEditDeleteActivity.class);
startService(intent1);
Please advice......
This type of error message is shown after 15 mins
Use CountDownTimer
CountDownTimer timer = new CountDownTimer(15 *60 * 1000, 1000) {
public void onTick(long millisUntilFinished) {
//Some code
}
public void onFinish() {
//Logout
}
};
When user has stopped any action use timer.start() and when user does the action do timer.cancel()
I am agree with Girish in above answer. Rash for your convenience i am sharing code with you.
public class LogoutService extends Service {
public static CountDownTimer timer;
#Override
public void onCreate(){
super.onCreate();
timer = new CountDownTimer(1 *60 * 1000, 1000) {
public void onTick(long millisUntilFinished) {
//Some code
Log.v(Constants.TAG, "Service Started");
}
public void onFinish() {
Log.v(Constants.TAG, "Call Logout by Service");
// Code for Logout
stopSelf();
}
};
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Add the following code in every activity.
#Override
protected void onResume() {
super.onResume();
LogoutService.timer.start();
}
#Override
protected void onStop() {
super.onStop();
LogoutService.timer.cancel();
}
First Create Application class.
public class App extends Application{
private static LogoutListener logoutListener = null;
private static Timer timer = null;
#Override
public void onCreate() {
super.onCreate();
}
public static void userSessionStart() {
if (timer != null) {
timer.cancel();
}
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
if (logoutListener != null) {
logoutListener.onSessionLogout();
log.d("App", "Session Destroyed");
}
}
}, (1000 * 60 * 2) );
}
public static void resetSession() {
userSessionStart();
}
public static void registerSessionListener(LogoutListener listener) {
logoutListener = listener;
}
}
This App Class add into manifest
<application
android:name=".App"
android:allowBackup="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="#style/AppTheme">
<activity android:name=".view.activity.MainActivity"/>
</application>
Then Create BaseActivity Class that is use in whole applications
class BaseActivity extends AppCompatActivity implements LogoutListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
//setTheme(App.getApplicationTheme());
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
super.onResume();
//Set Listener to receive events
App.registerSessionListener(this);
}
#Override
public void onUserInteraction() {
super.onUserInteraction();
//reset session when user interact
App.resetSession();
}
#Override
public void onSessionLogout() {
// Do You Task on session out
}
}
After that extend Base activity in another activity
public class MainActivity extends BaseActivity{
private static final String TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
You can start a service and start a timer in it. Every 15 minutes, check if a flag, let's say inactivity flag is set to true. If it is, logout form the app.
Every time the user interacts with your app, set the inactivity flag to false.
you may need to create a BaseActivity class which all the other Activities in your app extend. in that class start your timer task (TimerTask()) in the onUserInteraction method:
override fun onUserInteraction() {
super.onUserInteraction()
onUserInteracted()
}
. The onUserInteracted class starts a TimerTaskService which will be an inner class for my case as below:
private fun onUserInteracted() {
timer?.schedule(TimerTaskService(), 10000)
}
The TimerTaskService class will be asfollows. Please note the run on UI thread in the case you want to display a DialogFragment for an action to be done before login the user out:
inner class TimerTaskService : TimerTask() {
override fun run() {
/**This will only run when application is in background
* it allows the application process to get high priority for the user to take action
* on the application auto Logout
* */
// val activityManager = applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
// activityManager.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_NO_USER_ACTION)
runOnUiThread {
displayFragment(AutoLogoutDialogFragment())
isSessionExpired = true
}
stopLoginTimer()
}
}
You will realise i have a stopTimer method which you have to call after the intended action has be envoked, this class just has timer?.cancel() and you may also need to include it in the onStop() method.
NB: this will run in 10 seconds because of the 10000ms
Use the build-in function called: onUserInteraction() like below:
#Override
public void onUserInteraction() {
super.onUserInteraction();
stopHandler(); //first stop the timer and then again start it
startHandler();
}
I hope this will help
I found it on github https://gist.github.com/dseerapu/b768728b3b4ccf282c7806a3745d0347
public class LogOutTimerUtil {
public interface LogOutListener {
void doLogout();
}
static Timer longTimer;
static final int LOGOUT_TIME = 600000; // delay in milliseconds i.e. 5 min = 300000 ms or use timeout argument
public static synchronized void startLogoutTimer(final Context context, final LogOutListener logOutListener) {
if (longTimer != null) {
longTimer.cancel();
longTimer = null;
}
if (longTimer == null) {
longTimer = new Timer();
longTimer.schedule(new TimerTask() {
public void run() {
cancel();
longTimer = null;
try {
boolean foreGround = new ForegroundCheckTask().execute(context).get();
if (foreGround) {
logOutListener.doLogout();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}, LOGOUT_TIME);
}
}
public static synchronized void stopLogoutTimer() {
if (longTimer != null) {
longTimer.cancel();
longTimer = null;
}
}
static class ForegroundCheckTask extends AsyncTask < Context, Void, Boolean > {
#Override
protected Boolean doInBackground(Context...params) {
final Context context = params[0].getApplicationContext();
return isAppOnForeground(context);
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List < ActivityManager.RunningAppProcessInfo > appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess: appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
}
Use above code in Activity as below :
public class MainActivity extends AppCompatActivity implements LogOutTimerUtil.LogOutListener
{
#Override
protected void onStart() {
super.onStart();
LogOutTimerUtil.startLogoutTimer(this, this);
Log.e(TAG, "OnStart () &&& Starting timer");
}
#Override
public void onUserInteraction() {
super.onUserInteraction();
LogOutTimerUtil.startLogoutTimer(this, this);
Log.e(TAG, "User interacting with screen");
}
#Override
protected void onPause() {
super.onPause();
Log.e(TAG, "onPause()");
}
#Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume()");
}
/**
* Performing idle time logout
*/
#Override
public void doLogout() {
// write your stuff here
}
}
I have an application in which when the user starts the application a timer starts. After 10sec an AlertDialog pops up saying only 15 seconds reaming and displays a timer, and after 14 seconds it disappears. This works fine when on the first activity of the application. If the user passes from first Activty --> TimedNotify Activity the timer stops after 10seconds. onUserInteraction() in TimedNotify the timer restarts and works absolutely fine. Please assist me as to where I am going wrong.
public class FirstActivity extends TimedNotify{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.timercheck);
final Button btnstart2 = (Button) findViewById(R.id.btn);
btnstart2.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,
TimedNotify.class);
startActivity(intent);
}
});
}
}
public class TimedAlert extends Activity
{
static CountDownTimer timer1, timer2;
int flag = 0;
protected static final String TAG = null;
public static AlertDialog alert, alertdialog;
private static Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView mCounter1TextField = (TextView) findViewById (R.id.mCounter1TextField);
// first timer set for 10sec
timer1 = new CountDownTimer(10000, 1000)
{
#Override
public void onTick(long millisUntilFinished)
{
Log.v(TAG, "timer1 ticking");
mCounter1TextField.setText("Seconds left: "
+ formatTime(millisUntilFinished));
}
public void onFinish() {
//after 10sec display alert box and show timer
Log.v(TAG, "timer1 finished");
timer1.cancel();
AlertDialog.Builder builder = new AlertDialog.Builder(
TimedAlert.this);
builder.setTitle("Session Time Out");
builder.setMessage("00:15");
builder.setPositiveButton("Resume", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog2,int iwhich)
{
Intent in = new Intent(TimedAlert.this,FirstActivity.class);
//in case there are many events ..the intent should be passed to the last activity on clicking resume
in.setAction(Intent.ACTION_MAIN);
in.addCategory(Intent.CATEGORY_LAUNCHER);
onUserInteraction();
}
});
builder.setNegativeButton ("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog2,int iwhich)
{
timer2.cancel();
timer1.start();
}
});
alert = builder.create();
alert.show();
timer2 = new CountDownTimer(15000, 1000)
{
#Override
public void onTick(long millisUntilFinished)
{
Log.v(TAG, "timer2 ticking");
alert.setMessage("Your Session will expire in 5 minutes . Timleft00:"+ (millisUntilFinished / 1000));
mCounter1TextField.setText("Seconds left: "+ formatTime (millisUntilFinished));
}
//after 15 sec dismiss alert box
public void onFinish() {
Log.v(TAG, "timer2 finished");
timer2.cancel();
alert.dismiss();
}
}.start();
}
}.start();
}
#Override
public void onBackPressed() {
Intent in = new Intent(TimedAlert.this, FirstActivity.class);
startActivity(in);
}
public String formatTime(long millis) {
String output = "00:00";
long seconds = millis / 1000;
long minutes = seconds / 60;
seconds = seconds % 60;
minutes = minutes % 60;
String secondsD = String.valueOf(seconds);
String minutesD = String.valueOf(minutes);
if (seconds < 10)
secondsD = "0" + seconds;
if (minutes < 10)
minutesD = "0" + minutes;
output = minutesD + " : " + secondsD;
return output;
}
public void onUserInteraction() {
super.onUserInteraction();
// Remove any previous callback
try {
Log.v(TAG, "user interacted");
timer1.start();
timer2.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
Log.v(TAG, "paused");
onUserInteraction();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
Log.v(TAG, "resumed");
onUserInteraction();
}
private void handleIntent(Intent intent) {
timer1.start();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
Log.v(TAG, "stopped");
timer1.start();
}
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.v(TAG, "started");
timer1.start();
}
}
OK, here are a few things I noted that might help you out:
public void onClick(DialogInterface dialog2, int iwhich) {
Intent in = new Intent(TimedAlert.this,
FirstActivity.class);
in.setAction(Intent.ACTION_MAIN);
in.addCategory(Intent.CATEGORY_LAUNCHER);
onUserInteraction();
}
You don't have a startActivity(in); after setting up all the parameters.
Why do onPause() and onResume() call onUserInteraction(), but onStart() and onStop() don't?
In fact, you should choose whether to use onPause() and onResume() only or onStart() and onStop(). Furthermore, onPause() or onStop() shouldn't restart the timers?
Thinking further about your reported problem, you say that it is when you are on your second activity that you have problems. Check out the lifecycle of an Activity - I suspect what might be happening is that you launch a new instance of your activity. Try setting your manifest to use android:launch mode="singleTask" for your activity.