Related
I need to create a login screen and a simple first screen (with a log out button). When a user logs in, for convenience, it does not require to log in again (only when the log out button is hit). To do this, i need to store a boolean variable whether the users is logged in or not.
When I hit the home button and open the app again, the app remembers that I already logged in. But when I hi the back button, it does not remember it.
Here is my code of the login screen:
package com.example.a20172425.login;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
public class LoginActivity extends AppCompatActivity {
EditText usernameEditText;
EditText passwordEditText;
TextView falseLoginTextView;
SharedPreferences pref;
boolean validCredentials = false;
public static Boolean login = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
usernameEditText = (EditText)findViewById(R.id.usernameField);
passwordEditText = (EditText)findViewById(R.id.passwordField);
falseLoginTextView = (TextView)findViewById(R.id.falseLoginText);
pref = getPreferences(MODE_PRIVATE);
login = getLoginStatus();
if(login) {
toMainActivity();
}
}
public void checkCredentials(View v){
//clear possible previous content
falseLoginTextView.setText("");
//retrieve username and password
String username = usernameEditText.getText().toString();
String password = passwordEditText.getText().toString();
if ((username.equals("username")) && (password.equals("password"))) {
validCredentials = true;
setLoginStatus(true);
//setUsername(username);
} else if ((username.equals("a")) && (password.equals("a"))) {
validCredentials = true;
setLoginStatus(true);
//setUsername(username);
}
if (validCredentials){
toMainActivity();
}
else
{
falseLoginTextView.setText("Incorrect username and or password");
}
}
public void toMainActivity(){
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.putExtra("Username", usernameEditText.getText().toString());
this.startActivity(intent);
//makes sure pressing the back button does not send the app back to the login screen
this.finish();
}
// gets the logged_in value from persistent memory.
public Boolean getLoginStatus (){
return pref.getBoolean("Logged_in",false);
}
//sets the logged_in boolean value in persistent memory.
public void setLoginStatus(Boolean loginStatus){
//editor to change values to be stored in memory
SharedPreferences.Editor edit = pref.edit();
edit.putBoolean("Logged_in",loginStatus);
//save changes
edit.commit();
}
}
This is my code of the simple first screen:
package com.example.a20172425.login;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import static com.example.a20172425.login.LoginActivity.login;
public class MainActivity extends AppCompatActivity {
TextView LoginTextView;
LoginActivity loginActivity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LoginTextView = (TextView) findViewById(R.id.LoginTV);
String username = getIntent().getStringExtra("Username");
LoginTextView.setText("Currently logged in as: " + username);
loginActivity = new LoginActivity();
}
public void toLoginActivity(View v) {
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
this.startActivity(intent);
login = false;
//loginActivity.setLogin(false);
//makes sure pressing the back button does not send the app back to the login screen
this.finish();
}
}
Any suggestion will be appreciated.
EDIT: I write Kotlin in my day to day job, I didn't actually compile the Java examples below so there may be some syntactical errors. However, it should be fairly trivial to resolve these with basic working Java knowledge. The concepts in this answer are applicable to the vast majority of OO languages (Kotlin, Java, C# etc.).
I'm updating this answer to give some more detail on what an interface is, why they are useful, how callbacks work and how they are implemented under the hood.
In object oriented programming (OO) and, in this case, Java; there is a type system that allows for polymorphism. Polymorphism, when broken down, means (poly -> many) and (morphism -> behaving like), or, in other words, many similarly behaving different types.
What these means in more concrete coding terms is that you can have many different classes of types which conform to a common behaviour (or interface). The behaviour of a type should be thought of as it's outwardly observable behaviours and not the internal implementation. It is useful to conceptualise this with respect to the type system. For example, a behaviour is defined as a transformation from one type to another (for instance a function that takes a collection of strings and returns a string). There are many functions that could perform this transformation, but the outwardly observable behaviour of all of these functions is the same (in other words, a transformation Collection -> String).
It therefore follows that such a type system can allow for arbitrary swapping of implementations as long as the outwardly observable behaviour is maintained.
Interfaces are a popular language construct to achieve this. An interface merely defines the tranformations between types and gives them names. Other types may then depend on this interface and call methods of this interface without any concern as to the actual implementation of the methods (the only constraint being that the implementors of said interface must conform to the type transformations - this is enforced at compile time in Java).
Here is a very simple interface:
public interface Car {
public Int accelerate(Int force);
public Int steer(Int direction);
}
I use the car example as it's quite intuitive. Here we can see two type transformations, from Int -> Int with a name accelerate, and from Int -> Int with a name of steer.
All cars can accelerate and steer. But not all cars accelerate and steer in the same way. However, all cars steer and accelerate behaviours follow a common pattern (or type transformation). They take some input value and result in some output value.
So, we could provide several implementations of car like so (bear in mind this is a very contrived example, so don't judge):
public class Ford implements Car {
#Override
public Int accelerate(Int force) {
return force * 1;
}
#Override
public Int steer(Int direction) {
return direction * 1;
}
}
public class Ferrari implements Car {
#Override
public Int accelerate(Int force) {
return force * 10;
}
#Override
public Int steer(Int direction) {
return direction * 10;
}
}
As you can see, a Ford and Ferrari both steer and accelerate. But the Ferrari does it differently (but it still conforms to the type transformation just as the Ford does).
Now, here we introduce polymorphism, which is a very powerful tool. Imagine we have the following class:
public class Person {
private Car car;
public Person(Car car) {
this.car = car
}
}
So, a person can be constructed by passing a car as a dependancy to it. Due to polymorphism we can pass any instance of an object that implements (or conforms to) the Car interface. For instance, we could do the following:
public class Main {
public void main([String] args) {
Person poorPerson = new Person(new Ford());
Person richPerson = new Person(new Ferrari());
}
}
Pretty nifty! Now we can create hundreds of different types of cars but our person class never has to change! Our person class can call methods on their respectively owned cars and never have to worry about anything breaking (because all cars can accelerate and steer).
So, how does this relate to the original question? Let us consider this very contrived example of an Android View class and a Callback interface:
public interface ContrivedCallback {
public void onClick();
}
public class ContrivedView {
private ContrivedCallback callback;
public void setOnClickListener(ContrivedCallback: callback) {
this.callback = callback;
}
private void onClick() {
this.callback.invoke();
}
}
Let us assume that the onClick method in the ContrivedView class is magically called by the Android OS when the view is clicked. Now, when the view is clicked, the callback (if set) is invoked. But, as we now know, the callback is just an interface, so whatever implementation was provided to the setCallback method will be invoked.
So, the callbacks single defined method is merely a transformation from Void -> Void (in other words, it takes no arguments and returns no value). It's just some code to run. The implementation may launch rockets, save to a database, print a string or do literally nothing, it's up to the coder providing the implementation).
I hope this makes sense? Now, with respect to the original question:
You can use an onClickListener callback. In this callback implementation you can write some code that updates some state of the Activity or Fragment (or write to preferences or local database, or launch missiles... you get the picture).
You create an implementation and then assign this implementation to the callback listener on the button in question like so (in your onCreate method):
logoutButton = (Button)findViewById(R.id.logoutButton);
logoutButton.addOnClickListener(class callback extends DialogInterface.OnClickListener {
#Override
public void onClick() {
// Do stuff here...
}
});
I am working on an app and in the IOS version whenever an external event happens such as the home button or a call comes in the app shows its password entry screen as it shows sensitive data.
I am trying to replicate this in android, I am having trouble because the lifecycle methods can be called and it does not necessarily mean that it was an external event like another app taking focus.
Is there a standard way to detect if onPause() was called because a external event triggered it?
Edit: I have a partially working solution:
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
Intent login = new Intent(this, AppEntryPoint.class);
login.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(login);
}
The issue with this is that if the home button is pressed, this method is called but as the app loses focus it is then brought back into focus by the login intent being fired.
The same applies to the open apps button, pressing it my app goes to the login screen which obscures the view of the page but then it has focus again immediately.
I want the intent to fire but for it not to bring the app back into focus.
You can use TRIM_MEMORY_UI_HIDDEN callback for this.
Level for onTrimMemory(int): the process had been showing a user
interface, and is no longer doing so. Large allocations with the UI
should be released at this point to allow memory to be better managed.
Example for it:
Create a class which extends from Application, register it in the Manifest and override it's onTrimMemory.
manifest:
<application
android:name=".AppContext" // the declared class name
android:allowBackup="true"
android:icon="#mipmap/app_icon"
android:label="#string/app_name"
android:theme="#style/AppTheme"
tools:replace="icon"
>
Aplication class:
public class AppContext extends Application{
....
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if(level >= TRIM_MEMORY_UI_HIDDEN)
{
//do your job here
}
}
I can't share all of my code, but the basic gist of it is to:
Set static integers to track the app's state
For example:
private static int resumed = 0;
private static int paused = 0;
private static int started = 0;
private static int stopped = 0;
private static boolean appInBackground = true;
Update these integers accordingly
For example:
#Override
public void on ActivityResumed(Activity activity) {
++resumed;
}
#Override
public void onActivityPaused(Activity activity) {
++paused;
}
#Override
public void onActivityStopped(Activity activity) {
++stopped;
if(stopped == started) {
appInBackground = true;
// other stuff here
}
}
User that logic to determine what state the app is in
For example:
public static boolean isApplicationInForeground() {
return resumed > paused;
}
All of this is in a AppLifecycleHandler file. I hope this helps, despite my inability to share all the details of my code!
The TextToSpeech constructor looks like it's designed to be 'owned' by an Activity. I'm producing an app with multiple different Activities, and I don't want to have to initialise a new TextToSpeech instance for each - I want the speech to carry on smoothly even if the Activity is changing.
My idea is to have a static TextToSpeech object accessed by all activities, initialised by the first one.
Does anyone know if the TextToSpeech implementation is thread-safe? I'm guessing not, but someone out there might know.
If I initialise it with the Context of my default Activity, will the TextToSpeech instance stop working when the Activity is destroyed?
I have never tried that, but I think you can pass an Application context as the parameter in the constructor, not necessarily an Activity.
But paying attention to the documentation, I see that the TTS engine has its own queing system, so you can call speak several times without worrying about the thread timing.
Regardind to your questions, I'm not sure about the number two, but as I wrote first, I would try passing an Application context, rather than Activity context.
About number one, well, there is one instance per engine at a time, I guess. And you normally have just one engine, but again, if the engine controls queries queuing, don't worry about the threads.
Thanks to those that told me to pass the ApplicationContext. Turned out that was the easy bit... The hard bit was whether the TextToSpeech object is guaranteed thread-safe.
Thanks for answers telling me how to make something thread-safe / assuming that it is, but the question was about whether the object already is. I probably should have said, I'm fine with implementing thread-safety, but I wanted to know whether I need to bother. And I don't want to assume thread-safety without being certain.
I ran the following and it seemed to work. So I assume the Android SDK TTS is thread-safe, but can't find any documentation saying that it's safe to assume this across all devices, so I'll be wrapping my TTS instance for the time being!
package com.example.testproject;
import java.util.Random;
import android.os.Bundle;
import android.app.Activity;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
public class TestActivity extends Activity implements OnInitListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tts = new TextToSpeech(getApplicationContext(), this);
}
TextToSpeech tts = null;
#Override
public void onInit(int arg0) {
for (int i = 0; i < 100; ++i) {
class Irritate implements Runnable {
Irritate(int iIn) {
i = iIn;
}
#Override
public void run() {
Random r = new Random();
try {
Thread.sleep(r.nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
tts.speak(Integer.toString(i), TextToSpeech.QUEUE_ADD, null);
}
int i;
}
Thread t = new Thread(new Irritate(i));
t.start();
}
}
}
I've always used TTS as an Activity that I startedForResult.
I just fire an intent to it and then wait for it to come back.
If I remember correctly, if returns an array of answers sorted by confidence.
So you if you don't have a Context, then I don't believe there is another way to call it (at least using this model). Not sure if there is an object reference that you can get for it.
However, if there is, to use your idea. Then you can just extend Application and hold the static reference to your TTS in there. That way it's visible to all your Activities. I think this is answer you are looking for.
The above was helpful in helping me resolve this issue. In my case, I had also had a fragment and so, I did the following:
From a fragment (from a fragment, you want to say "getActivity().getApplicationContext()" instead of just "getApplicationContext()") :
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode == MY_DATA_CHECK_CODE){
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
tts = new TextToSpeech(getActivity().getApplicationContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status == TextToSpeech.SUCCESS){
result = tts.setLanguage(Locale.UK);
}
}
});
} else {
// missing data, install it
Intent installIntent = new Intent();
// The ACTION_INSTALL_TTS_DATA intent will take the user to Android Market, and will let the user initiate the download
installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
}
TextToSpeech is not thread-safe with respect to the GUI, because a TextToSpeech listener method is called from a non-GUI thread.
If your listener methods interact with the GUI, you will have to include code to put the GUI changes into the Looper for the GUI thread.
There are plenty of examples of how to wrap a GUI command in a Handler and post it on the GUI thread's looper. Here is a sketch of what you'd do:
public class SpeechUtteranceListener extends UtteranceProgressListener {
#Override
public void onDone(String utteranceId) {
Runnable guiCommand = new Runnable() {
#Override
public void run() {
someButton.setEnabled(true);
}
}
};
runOnUiThread(asrStartCommand);
}
private void runOnUiThread(Runnable command){
Looper.getMainLooper().post(command);
}
}
There are three different cases:
1) A user launches an app, navigates in it, pressed home and click on the app icon again to launch our app again.
2) A user launches an app, navigates in it, presses home, chooses recent and click on the app to launch our app again.
3) A user launches an app, navigates in it, click something in the app (TextView with a link), which calls another app (as example Email) and user clicks back button, which bring us back to our app.
I know about flag "clearTaskOnLaunch" flag, it solves case #1.
I know about about flag "excludeFromRecents", it solves case #2 (may be not the most user friendly solution, but it works).
What about case #3? I have a workaround right now. However, I will have to put it on all activities which can be lead to another app. I wonder, whether there is better way to solve it (without handling it in all such activities).
This should be handled on the Application level.
For API level 14, you can register an ActivityLifeCycleCallback in your Application class
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
You can use it, to know on an Application level, which activities are destroyed, paused, resumed etc etc. Whenever, an activity is paused, without a new activity being created/resumed, you should clear the Activity stack, and re-launch your startActivity
If you target SDK versions < 14, you should implement your own method, to know which activities are created/resumed and paused, and do the same whenever an activity is paused, without a new activity being created/resumed
1) define a public static normalPause = true variable in a Class.
2) in onPause method of all of your activities set it false (I am worry. We might not be in a normal pause)
2) in onCreate method of all of your activities set it true (Do not worry. We are in a normal pause)
3) in onResume of all of your Activities:
if(!Utilities.normalPause)
{
this.finish()
}
Enjoy!
It seems a similar question has already been asked. It sounds like the OP came up with a working solution. How do I collapse "child activities"?
EDIT:
Instead of using a button you can use a boolean to tell whether or not you need to collapse back to the main activity. Have your root activity extend from Activity and the child activities extend from CollapsableActivity. To get this to work in all cases I added startOutsideActivity() and startOutsideActivityForResult().
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class CollapsableActivity extends Activity {
private boolean returnToRoot;
public static final int COLLAPSE_BACK = -1; // something other than RESULT_CANEL (0)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
returnToRoot = true;
}
#Override
protected void onStart() {
super.onStart();
returnToRoot = true;
}
#Override
protected void onRestart() {
super.onRestart();
// start collapsing the stack
if (returnToRoot) {
setResult(COLLAPSE_BACK);
finish();
}
}
#Override
public void startActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
returnToRoot = false;
}
public void startOutsideActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
returnToRoot = true;
}
#Override
public void startActivity(Intent intent) {
// call startActivityForResult to make sure and catch the collapse condition
super.startActivityForResult(intent, 0);
returnToRoot = false;
}
public void startOutsideActivity(Intent intent) {
super.startActivity(intent);
returnToRoot = true;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == COLLAPSE_BACK) {
returnToRoot = true;
}
}
}
This worked properly for me in all cases you listed. The only difference is you need to call startOutsideActivity() or startOutsideActivityForResult() when you navigate away from you app. Personally, I think this adds clarity to your intentions. Hope it helps!
I know you don't want to manage it in all activities but you can do this and still handle the code in one place with a super activity
public abstract class BlundellActivity extends Activity {
#Override
public void onPause(){
// Whatever strategy you want
}
}
public class SomeActivity extends BlundellActivity {
// Do whatever you normally want to do
}
public class SomeActivity extends BlundellActivity {
// Do whatever you normally want to do here as well
}
Perhaps, android:noHistory is what you're looking for. If you declare all your activities except StartupActivity with this attribute, then they will be finished as the user navigates away from them and only StartupActivity will appear.
You can try this steps:
use one boolean static flag isFinish in StartupActivity with default false value.
in onCreate() of StartupActivity set isFinish value to false.
write below code in onResume() method of all activities in your project.
if(isFinish)
{
finish();
}
set isFinish value to true when you open any native app like email, browser etc.
or
5 . set isFinish value to true in onBackPress() method whenever you want to close application on back press.
Case 6: if android browser open on clicking on any link then use below code is onPause() method
if(isBrowserRunning("com.android.browser"))
{
isFinish = true;
finish();
}
////////////////
private boolean isBrowserRunning(String processName)
{
ActivityManager manager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
String packageName = manager.getRunningTasks(1).get(0).topActivity.getPackageName();
Log.i("LogTest", "Current process package name: " + packageName);
return processName.equalsIgnoreCase(packageName);
}
You can create a sample project to know other browser package name like opera mini, US browser etc.
add below permission in manifest:
<uses-permission
android:name="android.permission.GET_TASKS" />
You can call this.finish() on the onPause() of your Activity, that way the activity will be closed in the three cases.
You need to use bundle and pass appropriate parameter/or parameters from the calling app (i.e. click something in the app (TextView with a link)).
Retrieve the parameter in the called app (Email app).
You can send the name of the activity in the parameter.
Now being in Email app(the called app) Click of back button navigate back to your calling application.
Optionally you can save the state of activity from the caller program, as required.
You need to use Bundle, and Intent to implement this logic.
Code snippet:
In the calling program, we need to store parameters/data required for back button functionality in the called program.
Bundle bndleData = new Bundle();
Use putString(), putInt() methods of Bundle class.
String prefix = getPackageName().toString();
(this prefix can be stored in application level constants.java file as applicable)
bndleData.putString("ParentActivity", this.getLocalClassName());
Also store additional parameters if required
bndleData.putString("paramName", valueofParamName);
bndleData.putInt("IntChannelImage", chImageInt);
Intent intent = new Intent(v.getContext(), AMRChannelPlayer.class);
intent.putExtra(prefix + "bndleChnlData", bndleData);
startActivity(intent);
Caller Program:
Retrive the data, activity nae from bundle and use it in back button implementation:
prefix = getPackageName().toString();
Bundle extras = getIntent().getBundleExtra(prefix + "bndleData");
String parentActivity = extras.getString("ParentActivity");
extras.getString("paramName");
I hope this helps you.
Instead of using multiple solutions you can use a single one that solves all the problems.
Check this answer:
https://stackoverflow.com/a/8576529/327011
With a Broadcast and BroadcastReceivers in each activities of your application you can kill all activities whenever your application goes to background.
UPDATE:
To detect if your application when to background you can use onStop, check this to understand the theory: Activity side-by-side lifecycle
And this is the implementation: https://stackoverflow.com/a/5862048/327011
I think this is all you need :-)
I am doing a status bar notification in my android app that is triggered by c2dm. I don't want to display the notification if the app is running. How do you determine if the app is running and is in the foreground?
Alternately, you can check with the ActivityManager what tasks are running by getRunningTasks method. Then check with the first task(task in the foreground) in the returned List of tasks, if it is your task. Here is the code example:
public Notification buildNotification(String arg0, Map<String, String> arg1) {
ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> services = activityManager
.getRunningTasks(Integer.MAX_VALUE);
boolean isActivityFound = false;
if (services.get(0).topActivity.getPackageName().toString()
.equalsIgnoreCase(appContext.getPackageName().toString())) {
isActivityFound = true;
}
if (isActivityFound) {
return null;
} else {
// write your code to build a notification.
// return the notification you built here
}
}
And don't forget to add the GET_TASKS permission in the manifest.xml file in order to be able to run getRunningTasks() method in the above code:
<uses-permission android:name="android.permission.GET_TASKS" />
p/s : If agree this way, please to note that this permission now is deprecated.
Make a global variable like private boolean mIsInForegroundMode; and assign a false value in onPause() and a true value in onResume().
Sample code:
private boolean mIsInForegroundMode;
#Override
protected void onPause() {
super.onPause();
mIsInForegroundMode = false;
}
#Override
protected void onResume() {
super.onResume();
mIsInForegroundMode = true;
}
// Some function.
public boolean isInForeground() {
return mIsInForegroundMode;
}
This is a pretty old post but still quite relevant. The above accepted solution may work but is wrong. As Dianne Hackborn wrote:
These APIs are not there for applications to base their UI flow on, but to do things like show the user the running apps, or a task manager, or such.
Yes there is a list kept in memory for these things. However, it is off in another process, managed by threads running separately from yours, and not something you can count on (a) seeing in time to make the correct decision or (b) have a consistent picture by the time you return. Plus the decision about what the "next" activity to go to is always done at the point where the switch is to happen, and it is not until that exact point (where the activity state is briefly locked down to do the switch) that we actually know for such what the next thing will be.
And the implementation and global behavior here is not guaranteed to remain the same in the future.
The correct solution is to implement : ActivityLifeCycleCallbacks.
This basically needs an Application Class and the handler can be set in there to identify the state of your activities in the app.
As Vinay says, probably the best solution (to support newer android versions, 14+) is to use ActivityLifecycleCallbacks in the Application class implementation.
package com.telcel.contenedor.appdelegate;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;
/** Determines global app lifecycle states.
*
* The following is the reference of activities states:
*
* The <b>visible</b> lifetime of an activity happens between a call to onStart()
* until a corresponding call to onStop(). During this time the user can see the
* activity on-screen, though it may not be in the foreground and interacting with
* the user. The onStart() and onStop() methods can be called multiple times, as
* the activity becomes visible and hidden to the user.
*
* The <b>foreground</b> lifetime of an activity happens between a call to onResume()
* until a corresponding call to onPause(). During this time the activity is in front
* of all other activities and interacting with the user. An activity can frequently
* go between the resumed and paused states -- for example when the device goes to
* sleep, when an activity result is delivered, when a new intent is delivered --
* so the code in these methods should be fairly lightweight.
*
* */
public class ApplicationLifecycleManager implements ActivityLifecycleCallbacks {
/** Manages the state of opened vs closed activities, should be 0 or 1.
* It will be 2 if this value is checked between activity B onStart() and
* activity A onStop().
* It could be greater if the top activities are not fullscreen or have
* transparent backgrounds.
*/
private static int visibleActivityCount = 0;
/** Manages the state of opened vs closed activities, should be 0 or 1
* because only one can be in foreground at a time. It will be 2 if this
* value is checked between activity B onResume() and activity A onPause().
*/
private static int foregroundActivityCount = 0;
/** Returns true if app has foreground */
public static boolean isAppInForeground(){
return foregroundActivityCount > 0;
}
/** Returns true if any activity of app is visible (or device is sleep when
* an activity was visible) */
public static boolean isAppVisible(){
return visibleActivityCount > 0;
}
public void onActivityCreated(Activity activity, Bundle bundle) {
}
public void onActivityDestroyed(Activity activity) {
}
public void onActivityResumed(Activity activity) {
foregroundActivityCount ++;
}
public void onActivityPaused(Activity activity) {
foregroundActivityCount --;
}
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
public void onActivityStarted(Activity activity) {
visibleActivityCount ++;
}
public void onActivityStopped(Activity activity) {
visibleActivityCount --;
}
}
And in Application onCreate() method:
registerActivityLifecycleCallbacks(new ApplicationLifecycleManager());
Then ApplicationLifecycleManager.isAppVisible() or ApplicationLifecycleManager.isAppInForeground() would be used to know the desired state.
Since API 16 you can do it like this:
static boolean shouldShowNotification(Context context) {
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
if (myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
return true;
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
// app is in foreground, but if screen is locked show notification anyway
return km.inKeyguardRestrictedInputMode();
}
FYI, if you use Gadenkan solution (which is great!!) don't forget to add
<uses-permission android:name="android.permission.GET_TASKS" />
to the manifest.
Slightly cleaned up version of Gadenkan's solution. Put it any Activity, or maybe a base class for all your Activities.
protected boolean isRunningInForeground() {
ActivityManager manager =
(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1);
if (tasks.isEmpty()) {
return false;
}
String topActivityName = tasks.get(0).topActivity.getPackageName();
return topActivityName.equalsIgnoreCase(getPackageName());
}
To be able to call getRunningTasks(), you need to add this in your AndroidManifest.xml:
<uses-permission android:name="android.permission.GET_TASKS"/>
Do note what ActivityManager.getRunningTasks() Javadoc says though:
Note: this method is only intended for debugging and presenting task
management user interfaces. This should never be used for core logic
in an application, such as deciding between different behaviors based
on the information found here. Such uses are not supported, and will
likely break in the future.
Update (Feb 2015)
Note that getRunningTasks() was deprecated in API level 21!
As of LOLLIPOP, this
method is no longer available to third party applications: the
introduction of document-centric recents means it can leak person
information to the caller. For backwards compatibility, it will still
return a small subset of its data: at least the caller's own tasks,
and possibly some other tasks such as home that are known to not be
sensitive.
So what I wrote earlier is even more relevant:
In many cases you can probably come up with a better solution. For example, doing something in onPause() and onResume(), perhaps in a BaseActivity for all your Activities.
(In our case we didn't want an offline alert activity to be launched if we are not in the foreground, so in BaseActivity onPause() we simply unsubscribe from the RxJava Subscription listening for "went offline" signal.)
Following up on Gadenkan's reply I needed something like this so I could tell if my app wasn't running in the foreground, but I needed something that was app wide and didn't require me setting/unsetting flags throughout my application.
Gadenkan's code pretty much hit the nail on the head but it wasn't in my own style and felt it could be tidier, so in my app its condensed down to this.
if (!context.getPackageName().equalsIgnoreCase(((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1).get(0).topActivity.getPackageName()))
{
// App is not in the foreground
}
(Side note: You can just remove the ! if you want the check to work the other way around)
Although with this approach you need the GET_TASKS permission.
Starting support library version 26 you can use ProcessLifecycleOwner to determine app current state, just add it to your dependencies like described here, for example:
dependencies {
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
}
, Now you can query ProcessLifecycleOwner whenever you want to check app state, for example to check if app is running in foreground you just have to do this:
boolean isAppInForeground = ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
if(!isAppInForeground)
//Show Notification in status bar
Based on the various answers and comments, here is a more inlined version that you can add to a helper class:
public static boolean isAppInForeground(Context context) {
List<RunningTaskInfo> task =
((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE))
.getRunningTasks(1);
if (task.isEmpty()) {
return false;
}
return task
.get(0)
.topActivity
.getPackageName()
.equalsIgnoreCase(context.getPackageName());
}
As mentioned in other answers you need to add the following permission to your AndroidManifest.xml .
<uses-permission android:name="android.permission.GET_TASKS"/>
I would like to add that a safer way to do this - than checking if your app is in the background before creating a notification - is to just disable and enable the Broadcast Receiver onPause() and onResume() respectively.
This method gives you more control in the actual application logic and is not likely to change in the future.
#Override
protected void onPause() {
unregisterReceiver(mHandleMessageReceiver);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
}
I found a more simpler and accurate way to check if the application is in foreground or background by mapping the activities to boolean.
Check the complete gist here
Here's the code for nice simple solution described above by #user2690455 . Although it looks a bit verbose, you'll see overall it's actually quite light-weight
In my case we also use AppCompatActivity, so I had to have 2 base classes.
public class BaseActivity extends Activity {
/**
* Let field be set only in base class
* All callers must use accessors,
* and then it's not up to them to manage state.
*
* Making it static since ..
* 1. It needs to be used across two base classes
* 2. It's a singleton state in the app
*/
private static boolean IS_APP_IN_BACKGROUND = false;
#Override
protected void onResume() {
super.onResume();
BaseActivity.onResumeAppTracking(this);
BaseActivity.setAppInBackgroundFalse();
}
#Override
protected void onStop() {
super.onStop();
BaseActivity.setAppInBackgroundTrue();
}
#Override
protected void onPause() {
super.onPause();
BaseActivity.setAppInBackgroundFalse();
}
protected static void onResumeAppTracking(Activity activity) {
if (BaseActivity.isAppInBackground()) {
// do requirements for returning app to foreground
}
}
protected static void setAppInBackgroundFalse() {
IS_APP_IN_BACKGROUND = false;
}
protected static void setAppInBackgroundTrue() {
IS_APP_IN_BACKGROUND = true;
}
protected static boolean isAppInBackground() {
return IS_APP_IN_BACKGROUND;
}
}
This is useful only when you want to perform some action just when your activity starts and its where you want to check if app is in foreground or background.
Instead of using Activity manager there is a simple trick which you can do through code.
If you observe the activity cycle closely, the flow between two activities and foreground to background is as follows.
Suppose A and B are two activities.
When transition from A to B:
1. onPause() of A is called
2. onResume() of B is called
3. onStop() of A is called when B is fully resumed
When app goes into background:
1. onPause() of A is called
2. onStop() of A is called
You can detect your background event by simply putting a flag in activity.
Make an abstract activity and extend it from your other activities, so that you wont have to copy paste the code for all other activities wherever you need background event.
In abstract activity create flag isAppInBackground.
In onCreate() method:
isAppInBackground = false;
In onPause() method:
isAppInBackground = false;
In onStop() method:
isAppInBackground = true;
You just to need to check in your onResume() if isAppInBackground is true.
n after you check your flag then again set isAppInBackground = false
For transition between two activities since onSTop() of first will always called after second actvity resumes, flag will never be true and when app is in background, onStop() of activity will be called immediately after onPause and hence the flag will be true when you open the app later on.
There is one more scenario though in this approach.
If any of your app screen is already open and you put the mobile idle then after some time mobile will go into sleep mode and when you unlock mobile, it will be treated at background event.
Here is a method that I use (and supporting method):
private boolean checkIfAppIsRunningInForeground() {
ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
for(ActivityManager.RunningAppProcessInfo appProcessInfo : activityManager.getRunningAppProcesses()) {
if(appProcessInfo.processName.contains(this.getPackageName())) {
return checkIfAppIsRunningInForegroundByAppImportance(appProcessInfo.importance);
}
}
return false;
}
private boolean checkIfAppIsRunningInForegroundByAppImportance(int appImportance) {
switch (appImportance) {
//user is aware of app
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND:
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE:
return true;
//user is not aware of app
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND:
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY:
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE:
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE:
default:
return false;
}
}
There is no global callback for this, but for each activity it is onStop(). You don't need to mess with an atomic int. Just have a global int with the number of started activities, in every activity increment it in onStart() and decrement it in onStop().
Follow this
public static boolean isAppRunning(Context context) {
// check with the first task(task in the foreground)
// in the returned list of tasks
ActivityManager activityManager = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> services =
activityManager.getRunningTasks(Integer.MAX_VALUE);
if
(services.get(0).topActivity.getPackageName().toString().equalsIgnoreCase(context.getPackageName().toString()))
{
return true;
}
return false;
}
The previous approaches mentioned here are not optimal. The task based approach requires a permission that might not be desired and "Boolean" approach is prone to concurrent modification mess ups.
The approach I use and which (I believe) works quite well in most cases:
Have a "MainApplication" class to track activity count in AtomicInteger:
import android.app.Application;
import java.util.concurrent.atomic.AtomicInteger;
public class MainApplication extends Application {
static class ActivityCounter {
private static AtomicInteger ACTIVITY_COUNT = new AtomicInteger(0);
public static boolean isAppActive() {
return ACTIVITY_COUNT.get() > 0;
}
public static void activityStarted() {
ACTIVITY_COUNT.incrementAndGet();
}
public static void activityStopped() {
ACTIVITY_COUNT.decrementAndGet();
}
}
}
And create a base Activity class that other activities would extend:
import android.app.Activity;
import android.support.annotation.CallSuper;
public class TestActivity extends Activity {
#Override
#CallSuper
protected void onStart() {
MainApplication.ActivityCounter.activityStarted();
super.onStart();
}
#Override
#CallSuper
protected void onStop() {
MainApplication.ActivityCounter.activityStopped();
super.onStop();
}
}