Disclaimer: This might not be the 100% best way to do this and it might be considered bad practice by some.
I have used the below code in a production app and it works. I have however edited it (removed app specific references and code) into a basic sample that should give you a very good start.
The static mIsAppVisible
variable can be called anywhere (via your App
class) in your app to check if code should run based on the condition that the app needs to be in focus/visible.
You can also check mIsAppInBackground
in your activities that extend ParentActivity
to see if the app is actually interactive, etc.
public class App extends Application {
public static boolean mIsAppVisible = false;
...
}
Create a "Parent" activity class, that all your other activities extend.
public class ParentActivity extends Activity {
public static boolean mIsBackPressed = false;
public static boolean mIsAppInBackground = false;
private static boolean mIsWindowFocused = false;
public boolean mFailed = false;
private boolean mWasScreenOn = true;
@Override
protected void onStart() {
applicationWillEnterForeground();
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
applicationDidEnterBackground();
}
@Override
public void finish() {
super.finish();
// If something calls "finish()" it needs to behave similarly to
// pressing the back button to "close" an activity.
mIsBackPressed = true;
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
mIsWindowFocused = hasFocus;
if (mIsBackPressed && !hasFocus) {
mIsBackPressed = false;
mIsWindowFocused = true;
}
if (!mIsWindowFocused && mFailed)
applicationDidEnterBackground();
if (isScreenOn() && App.mIsAppVisible && hasFocus) {
// App is back in focus. Do something here...
// this can occur when the notification shade is
// pulled down and hidden again, for example.
}
super.onWindowFocusChanged(hasFocus);
}
@Override
public void onResume() {
super.onResume();
if (!mWasScreenOn && mIsWindowFocused)
onWindowFocusChanged(true);
}
@Override
public void onBackPressed() {
// this is for any "sub" activities that you might have
if (!(this instanceof MainActivity))
mIsBackPressed = true;
if (isTaskRoot()) {
// If we are "closing" the app
App.mIsAppVisible = false;
super.onBackPressed();
} else
super.onBackPressed();
}
private void applicationWillEnterForeground() {
if (mIsAppInBackground) {
mIsAppInBackground = false;
App.mIsAppVisible = true;
// App is back in foreground. Do something here...
// this happens when the app was backgrounded and is
// now returning
} else
mFailed = false;
}
private void applicationDidEnterBackground() {
if (!mIsWindowFocused || !isScreenOn()) {
mIsAppInBackground = true;
App.mIsAppVisible = false;
mFailed = false;
// App is not in focus. Do something here...
} else if (!mFailed)
mFailed = true;
}
private boolean isScreenOn() {
boolean screenState = false;
try {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
screenState = powerManager.isInteractive();
} catch (Exception e) {
Log.e(TAG, "isScreenOn", e);
}
mWasScreenOn = screenState;
return screenState;
}
}
For your use you might want to create a method in your activity (code snippet assumes MainActivity
) that handles the animation to call the t.cancel();
method that penguin suggested. You could then in the ParentActivity.applicationDidEnterBackground()
method add the following:
if (this instanceof MainActivity) {
((MainActivity) this).cancelTimer();
}
Or you could add the timer to the ParentActivity
class and then not need the instanceof
check or the extra method.