About launcher intent - android

I'm trying to make a certain function to start only when a user,
Opens the app for the first time,
Goes back to an app from home.
But not start if the user switches between activities within the app.
I have looked through this topic,and the best answer is to use singleTask with onNewIntent(). So, if a user is goes back to the app from Home, a onNewIntent call with the launcher intent passed to it can be used.
However, here is my code:
public class AdMobSDK_DFP_Interstitial extends Activity implements AdListener {
private static final String MOBMAX_INTERSTITIAL_AD_UNIT_ID = "/7732/test_portal7/android_app1_test_portal7/splash_banner_android_app1_test_portal7";
private DfpInterstitialAd interstitialAd;
private int num = 0;
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
Log.d("flow", "onNewIntent");
}
If I switch between different activities in the app, onNewIntent() is always called, which is the same as I go back to the app from Home.

First thing you can do is to implement your own "Application" object and have it run the needed function when it is created.
public class MyApplication extends Application {
#Override
public void onCreate() {
// Call your function
}
}
Your application object will be live as long as your app is alive (any activity/service is still running), but note that the Application object is not destroyed immediately when the user presses "Home", and might stay alive for a while and a user can return to it without the function being called.
If you need this function to run as part of your main activity, just save a flag in your Application context :
public boolean alreadyDisplayed = false; and then in your activity's onStart you can just call
if ((MyApplication)getApplication().alreadyDisplayed ) {
// Call your function
(MyApplication)getApplication().alreadyDisplayed = true;
}
** If this solution is not enough for you and you need to call your function every time your main activity is displayed from the home page you'll need to do something not as nice... one suggestion I can give you is to implement the same Application object but this time with an "open activity" counter:
public class MyApplication extends Application {
public int mActivityCounter = 0;
}
Then you can increment this counter on every onStart of activity in your app and decrement on every onStop (of course this can be done by implementing a class MyActivity and make all your relevant activities inherit it. Then you can use this counter to know if there are any other activities opened. Note that you'll have to make sure the access to this counter is synchronized and work your way with it as you need.
I hope this helps...

Related

Android - How to know when app has been resumed after being in background

I'm trying to determine when my app is being resumed after the user closed it, in any way, pressing home button, back button or switching to another app.
What I need to do is to set a boolean when the app goes in background, so, when it is resumed, I know that it was in background before and I can act accordingly.
I tried to use onResume and onPause methods in activities to know when the app goes in background and it is then resumed, but as only one activity can be alive at at time, I had no success. When an activity is paused, this doesn't mean that the app went to background, because another activity could have been launched, but the onResume event of that activity will trigger only after the previous one has paused.
I've also tried to list all the apps in foreground, but with no success, if I put my app in background resuming another app, my app always results to be in the foreground.
I read that since Android 4 there is a new method to know when the app is in foreground, but I need my app to be compatible with Android 3.0 devices too.
Here is the code I tried putting in every single activity (MyApp is my Application name):
#Override
protected void onResume() {
super.onResume();
MyApp.isPaused = false;
}
#Override
protected void onPause() {
super.onPause();
MyApp.isPaused = true;
}
This is also my attempt to list all the apps in foreground:
ActivityManager activityManager = (ActivityManager)((Activity) currentContext).getSystemService( ACTIVITY_SERVICE );
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for(RunningAppProcessInfo appProcess : appProcesses){
if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
if(appProcess.processName.equals("com.xxx.myapp")) {
Log.i("MyApp", "it's in foreground");
}
Log.i("MyApp", appProcess.processName);
}
}
This class provides a singleton to determine "the activity in background" status. It uses a timer with a threshold(i.e. 0.3s) to determine the activity is went to background or not.
One thing has to point out is that if the user resumes to the activity within the threshold (i.e. 0.3s), this test will be failed.
If you have a better solution, please share with us :)
Ref: https://gist.github.com/steveliles/11116937
You are absolutely correct :) Because only one activity can be alive at a time so you need something which remains alive through out the application life cycle :) like Application instance itself or you can also make use of shared preference for that matter. But seriously using shared prefference for checking lifecycle is wrong choice if you ask me.
If I was in your position I would have gone for Application class :) Here is code if you want to do the same :)
import android.app.Application;
/**
* Created by sandeepbhandari on 3/3/16.
*/
public class AppService extends Application{
private static AppService sInstance;
public static boolean isGoingToBackGround=false;
#Override
public void onCreate() {
super.onCreate();
sInstance = this;
}
public static AppService getInstance() {
return sInstance;
}
}
In all your activities onPause just set
AppService service = AppService.getInstance();
service.isGoingToBackGround =true;
And in onResume check the same variablethats all :) and yeah if you want to use your application class rather than default Application you have to make change to manifest.xml
<application
android:name=".AppService"
Thats all :)
Override onTrimMemory(int level) in your Application. Might not be the prettiest way, but it has worked for me.
You will get
TRIM_MEMORY_BACKGROUND = 40;
when your application went into the Background.
You can make Application class inside your project to save state of your project. When any activity goes to pause call on pause respectively while on resume call on resume method and save state of the inside this class. Even if one activity goes on pause another on resume your class will know exact state of the application. Or another way you can save applicaton state in shared preference in each activity can change its value.
i trust there is no need for u to post a code... that being said...
start by logging every implemented methods onCreate(), onPause(), onDestroy(), and other well reputed Activity methods...
but back button does not just pause it kills, thus onCreate is called most
and check onStart() too.
public class CustomApplication extends Application {
private static boolean activityVisible;
#Override
public void onCreate() {
super.onCreate();
}
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
}
and in your all activities set
#Override
protected void onResume() {
super.onResume();
CustomApplication.activityResumed();
}
#Override
protected void onPause() {
super.onPause();
CustomApplication.activityPaused();
}
and in your manifest
<application
android:name=".CustomApplication"

how to detect app is now foreground after minimizing the app?

by using onResume() i can check if an activity is foreground or not. My problem is this onResume() is fire each time even if i come from another activity to this activity.
So my main problem is ,if i minimizing the app by home button I want execute some code in each activity when app is come foreground BUT not using onResume().
I found an answer like this How to know in BroadcastReceiver if App is running on foreground? but i dont know how to register this receiver in android menifest to get the trigger when app is visible.
Please give me some tips how can i overcome this solution or code snippet which can help me. Thanks in advance :)
One thing to do what you want is to count the number of times onStart/onStop is called in your application. This will help you determine if you transitioned to your activity from inside or outside your application.
You must extend Application then create/register ActivityLifecycleCallbacks within that class. Also, make sure to specify the new Application class you created in the AndroidManifest.
Now, the trick is to keep a count variable in onActivityStarted/onActivityStopped to determine whether your Activity was navigated to from inside or outside the application.
Say you have 2 Activities in your app: FirstActivity & SecondActivity.
If you navigate from FirstActivity to SecondActivity the lifecycle calls will happen in this order: FirstActivity.onStart() > SecondActivity.onStart(), resulting in a count of 1.
If you navigate from outside your application, you will only see FirstActivity.onStart(), so the count is 0. This is all assuming you check the count after super.onStart() is called.
So, by checking count against 0/1 you can tell if your activity was launched from within the application or outside the application.
/**
* Extending the application class lets you use ActivityLifecycleCallbacks to
* keep track of all lifecycle callbacks in your application.
*/
public class MyApplication extends Application implements ActivityLifecycleCallbacks {
private int count = 0;
//Register activity lifecycle callbacks in onCreate
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
void onActivityStarted(Activity activity) {
count++;
}
void onActivityStopped(Activity activity) {
count--;
}
/**
* Use this method in your Activities to test if the activity was
* transitioned to from outside the application.
*
* If you call this method in Activity.onResume(), then count should be
* compared to 0. If you call this method in Activity.onStart() but
* *before* calling super.onStart(), then count should be compared to 0.
*
* However, if you call this method after super.onStart(), then count
* should be compared to 1.
*/
public boolean cameFromOutsideApplication() {
return count == 0;
}
//Don't need to use the rest of the activity lifecycle callbacks
void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
void onActivityDestroyed(Activity activity) {
}
void onActivityPaused(Activity activity) {
}
void onActivityResumed(Activity activity) {
}
void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
}
You may gain some more information here as well but it does not use ActivityLifecycleCallbacks which is easier to use.
If you want to register your receiver you can use the following code,
<receiver
android:name="com.package.name.ReceiverClassName"
android:enabled="true" >
</receiver>

Android: Display Staus Bar Notificacion only when leaving application

I have an application that contains four activities, within the application the user will find himself navigating through the 4 activities constantly. The application also has an ongoing service in the background, the service displays a statusbar notifications, and listens for changes to the content that will then appear on the notification.
Currently, the service displays the notification whenever the user starts an action that required the notification to show, therefore, the notification is shown even when you are still using the application. The desired scenario is to show the notification only when the user has navigated out of the application.
I attempted to override lifecycle methods like this:
#Override
protected void onPause() {
Intent intent = new Intent();
intent.setAction(MyService.ACTION_DISPLAY_PENDING_NOTIFICATION);
sendBroadcast(intent);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
Intent intent = new Intent();
intent.setAction(MyService.ACTION_CANCEL_NOTIFICATION);
sendBroadcast(intent);
}
And the service goes like this:
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_DISPLAY_PENDING_NOTIFICATION)) {
showNotification();
}
else if (action.equals(ACTION_CANCEL_NOTIFICATION)) {
mNotificationManager.cancel(mNotId);
}
}
This, works. But, since the intent is sent anytime the user navigates away from an activity , I am experiencing an undesired behaviour and slight performance hit when the user navigates through the 4 activities. The service will attempt to display the notification even when going from Activity A to Activiy B, or any combination within the 4 activities.
The notification is immediately cancelled, as when a new Activity B starts it will call mNotificationManager.cancel(mNotifId) during onResume, but the notification was built and shown for a fraction of a second as the service was told to do so when leaving Activity A. That is the behavior I want to address, rather than building and showing this notifications unnecessarily,
Is there any way I can know when the user is leaving the activity to another application, i.e the homepage, etc; but not within the application itself?
EDIT:
Just to clarify, there are two things the activity would have to check for during the onPause method,
a) Is there any previous activity on the foreground? Why? Because the user could navigate out of the activity by pressing back, meaning the last activity on the stack would be displayed. In order to check for this, the answer from DennisDrew would work, we can check like this:
if(!ForegroundHelper.activityExistsInForeground()){
//show your notification
}
But that is not the only way the user could navigate out of the activity, the user could also press the HomeKey, in which case, whether activityExistsInForeground() evaluates to true or false, the notification should be displayed.
b) Is the user going to another activity in the application? For instance, user is on Activity A, A is the only activity on the foreground for now, user clicks on an UI element that launches Activity B. Despite of activityExistsInForeground() evaluating to false, user is not leaving the application, he is launching a new instance of an activity that was previously not on the freground.
I've tried to add flags such as private boolean launchingNewActivity = false as default, and setting the flag to true when I know I am going to another activity, say for instance during the click of an item on my listview:
litview.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
launchingNewActivity = true
startActivity2(arg2);
}
});
and then checking for that during onPause:
#Override
protected void onPause() {
if(!ForegroundHelper.activityExistsInForeground() && launchingNewActivity){
//show your notification
}
But doing this, it never shows the notification, somehow the double check always defaults to false.
What if you used a singleton reference? You could make a class like:
public static class ForegroundHelper {
public static boolean[] activityStates = new boolean{false, false, false, false};
public static final int ACTIVITY_A = 0;
public static final int ACTIVITY_B = 1;
public static final int ACTIVITY_C = 2;
public static final int ACTIVITY_D = 3;
public static boolean activityExistsInForeground(){
for(boolean b : activityStates){
if(b)
return true;
}
return false;
}
}
Then, in each activity's onResume() do:
//For your first activity (Activity A)
ForegroundHelper.activityStates[ForegroundHelper.ACTIVITY_A] = true;
And in each activity's onPause() do:
ForegroundHelper.activityStates[ForegroundHelper.ACTIVITY_A] = false;
And then in the onStop() of each activity do:
if(!ForegroundHelper.activityExistsInForeground()){
//show your notification
}
By the way, I haven't ever done something like this, so I have no idea if it will work exactly as I've coded it...but let me know if this helps.
What I did for that is that I extended the application class and kept there the "topActivity" that I would set in each onResume /onPause method like so:
public class myApp extends Application{
private Activity topActivity;
}
Now in each activity
#Override
protected void onResume() {
((myApp) getApplication()).setOnTopActivity(this);
}
#Override
protected void onPause() {
((myApp) getApplication()).setOnTopActivity(null);
super.onPause();
}
This way, when the app is not visible, topActivity is null. So, before showing your notification, just check whether or not topActivity==null. If it is, your app is not in the foreground, you can show your notification.
If you don't have access to your application class, you can always store this value in a static way :)

How to always start from a startup activity on Android?

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 :-)

How to kill app on button press

I have an app that has a lot of activities. In the "Settings" page there is a delete account button that is supposed to reset all the saved variables and exit the app. I haven't found a simple solution to exiting the app (eg calling finish only destroys the current activity) What do I call to close the app on a button press (eg when I reopen the the app it should start from the first activity)
Easiest way to do this is to register a BroadcastReceiver in all Activity classes that listens for a specific Intent. When you want to close everything then just fire the matching Intent, and in the BroadcastReceiver in each Activity call finish.
Try System.exit(0), although you're technically suppose to use finish() on all the activities. This does the same, but quickly.
Use this:
Process.killProcess(Process.myPid());
Or there is another more safer approach. Just subclass all of your activities, from one parent Activity and keep list of all alive activities and then when necessary close them all using exit():
public class ControlActivity extends Activity
{
private static ArrayList<Activity> activities=new ArrayList<Activity>();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
activities.add(this);
}
#Override
public void onDestroy()
{
super.onDestroy();
activities.remove(this);
if(activities.size()==0) //last activity
//release resources and so on
}
//close all activities, when necessary
public static void exit()
{
for(Activity activity:activities)
activity.finish();
}
}

Categories

Resources