Detect if user starts an application, android - android

Thanks in advance for the help.
I have an app that can be started by either the user physically starting the app (like you would any normal app) or by a repeating service. Depending on what starts the app (the user or the service) I want to preform different initialization actions. How might I be able to detect if an user starts the app without doing anything custom (I imagine that there has to be some kind of built in setting in android for me to determine this)?

If service, that starts your Activity, is yours service, you can put some custom information (using Intent#putExtra for example) in Intent you use to start Activity from Service.
In Activity you can use Activity#getIntent(), that returns the intent that started this activity.
If you started Activity from Service, that Intent will be the one you passed in Service#startActivity, and will have your custom information. Otherwise, that was not your Service, that started your Activity.
That could look somehow like that, for example:
//in Activity
public static final String EXTRA_STARTED_FROM_MY_SERVICE = "com.example.extra_started_from_sevice";
private boolean wasActivityStartedFromService() {
Intent startingIntent = getIntent();
//assuming you will use Intent#putExtra in your service when starting activity
return startingIntent.getBooleanExtra(EXTRA_STARTED_FROM_MY_SERVICE, false);
}
//...
//in Service
//...
Intent startingIntent = new Intent(this, MainActivity.class);
startingIntent.putExtra(MainActivity.EXTRA_STARTED_FROM_MY_SERVICE, true);
startActivity(startingIntent);

Related

Resume background activity on notification

I've read some answers here, I think I have what I need in order to achieve my result, but I need some help.
My app launches an notification on specific conditions, and I need my app to behave as follow:
if there is an instance of my main activity running in background I need to make it to the foreground (I found this on the site: intent.setFlags(FLAG_ACTIVITY_REORDER_TO_FRONT);, so I think this point is solved;
if there isn't any activity of the app running in background I need to start the app from the beginning (and this can be achieved starting the launcher activity of the app.);
My question is: how can I make the app search for any istance of itself running in background? Because the activity that I need to reorder to front with the Intent flag is different from the launcher activity.
The notification is handled by a service that check periodically some infos from the internet.
Thanks for the help.
What you need is just a simple Activity that decides what to do. Here is an example:
public class NotificationActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Check if the app was already running
if (isTaskRoot()) {
// App wasn't running, so start the app from the beginning
Intent startIntent = new Intent(this, MyStartingActivity.class);
startActivity(startIntent);
} else {
// App was already running, bring MainActivity to the top
Intent reorderIntent = new Intent(this, MainActivity.class);
reorderIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(reorderIntent);
}
// We are done now so just finish
finish();
}
}
Set up your notification to start this activity. Make sure that in the manifest the task affinity of this activity is the same as the task affinity of the other activities in your application (by default it is, if you haven't explicitly set android:taskAffinity).

Android intent service onClick, or start new activity and then Asynctask

Many times in android apps, users click a button/view and start a new activity, where the new activity pops up in front of what the user was previously looking at, and loads data.
Would there be any difference from a user perspective if the data started loading (from network or disk or both) when the user clicked the button before the next activity started. And then that data was returned to the new activity in a broadcast receiver.
This is compared to starting the process in the oncreate of the activity. Assuming these network and i/o processes only take milliseconds either way, would it make a difference to the user if the methods were started in onCreate of the new activity, or started in the old activity onClick.
First way, starting I/O and changing views after I/O finishes
//first activity
public void onClick(View v){
startActivity(new Intent(this, NewActivity.class);
}
//NewActivity.class
onCreate(Bundle mBundle){
super.onCreate(mBundle);
setContentView(R.layout.mView);
mObject = networkCall(); //after network call, the view objects in this layout will reflect data from the network call
}
second way, starting the I/O in the first activity
//first activity
public void onClick(View v){
IntentService networkCall = new IntentService();
//start network call
startActivity(new Intent(this, NewActivity.class);
}
//second activity on create just sets the view and also broadcast receiver
My GUESS is that in the split second that it takes for the activity to pop up, the data from the intent service could become available. But at the same time, passing data via intent could take just as long making the benefits marginal
Insight appreciated
In my experience the onCreate() of your new activity is called almost instantly from when you call startActivity(). The new activity doesn't show up right way because it has to take time to render your layout.
You could play around with timings yourself by using the Log.d() function. Something like Log.d(TAG, "This happend at: " + System.currentTimeMillis()); at different points in your code to see when things happen. Watch the LogCat while your apps runs and you can decide for your self which way is better.

Pass information from remote service to application

I created my own custom browser and I also have a background service that runs on startup. These are not in the same package, they are two separate installs. I want the service to be able to open my custom browser and launch a specific website in it at a specific time. I am currently able to launch the custom browser from the service but I don't know how to pass the specified url to it. Is this possible?
EDIT
I currently have it working now using something along the lines of this in my background service.
intent.putExtra("WebSite", "www.android.com")
then in my custom browser I put this in the onCreate() method
Intent sender = new Intent();
sender = getIntent();
String address = sender.getExtras().getString("WebSite");
I am getting the url then, but it is obviously force closing when I launch the app on my own instead of letting the remote service launch it because there is no intent for getIntent to get. I'm going to put a method in to check if there is an intent and if there is to launch it and if not skip. I think that should work. does anyone else have a better idea?
First activity (thus your service):
Intent myIntent = new Intent();
myIntent.putExtra("website", "www.android.com");
startActivity(myIntent);
Second activity (thus your browser:)
String website = "";
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
website = bundle.getString("website");
}

Notification to restore a task rather than a specific activity?

I have a foreground service that keeps a connection open with the server as long as the user is logged into the application. This is so that the connection is kept alive and can receive messages directly from the server even when the application has been sent into the background by the user pressing Home.
The application has a number of Activities, any of which could be the active one when it is sent into the background.
I would like to allow the user to click on the notification to restore the current Activity. I understand how to restore a particular activity, but wondered if there is a way to restore the last Activity that the user was on? Of course I could keep track of the the last one, and then call that from the Notification callback, but thought there might be a way at a task level?
Thanks for any advice you can offer.
What you need is just a simple Activity that does nothing. Here is an example:
public class NotificationActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Now finish, which will drop the user in to the activity that was at the top
// of the task stack
finish();
}
}
Set up your notification to start this activity. Make sure that in the manifest the task affinity of this activity is the same as the task affinity of the other activities in your application (by default it is, if you haven't explicitly set android:taskAffinity).
When the user selects this notification, if your application is running, then the NotificationActivity will be started on top of the topmost activity in your application's task and that task will be brought to the foreground. When the NotificationActivity finishes, it will simply return the user to the topmost activity in your application (ie: wherever the user left it when it went into the background).
This won't work if your application isn't already running. However, you have 2 options to deal with that:
Make sure the notification isn't present in the notification bar when your application is not running.
In the onCreate() method of the NotificationActivity, check if your application is running, and if it isn't running call startActivity() and launch your application. If you do this, be sure to set the flag Intent.FLAG_ACTIVITY_NEW_TASK when starting the application so that the root activity of the task is not NotificationActivity.
Works very well, thanks David! The following class checks if the application is already running and if not, starts it before finishing (as suggested by David in option 2).
public class NotificationActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// If this activity is the root activity of the task, the app is not running
if (isTaskRoot())
{
// Start the app before finishing
Intent startAppIntent = new Intent(getApplicationContext(), MainActivity.class);
startAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startAppIntent);
}
finish();
}
}
There is a simpler solution that does not require the extra activity. See this post for details. Basically, the notification starts the (possibly existing) task the same way it is started when you click the launcher icon while the app ist in the background.
My solution, which emulates the behaviour of the launcher (bringing up the task to the foreground):
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName(MyApplication.class.getPackage().getName(), MainActivity.class.getName());
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
This works, no doubts about it but the problem is when you set your intent as ACTION_MAIN. Then you will not be able to set any bundle to the intent. I mean, your primitive data will not be received from the target activity because ACTION_MAIN can not contain any extra data.
Instead of this, you can just set your activities as singleTask and call your intent normally without setting ACTION_MAIN and receive the intent from onNewIntent() method of your target activity.
But be aware if you call, super.onNewIntent(intent); then a second instance of the activity will be created. Just don't call super method.
I combined David Wasser's and Raginmari's solution by doing that approach to the root activity of your app then it will work for both cases when your app was already started or haven't been started.
public class YourRootActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (!isTaskRoot()) // checks if this root activity is at root, if not, we presented it from notification and we are resuming the app from previous open state
{
val extras = intent.extras // do stuffs with extras.
finish();
return;
}
// OtherWise start the app as usual
}
}

Question regarding account creation and sync on Android

I've been reading the sample code from the dev docs on Android's site, specifically this:
http://developer.android.com/resources/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.html
Which is the sole activity of the sample app. It refers to an intent in the onCreate method. I don't understand where this intent is coming from, or what it should contain if this is the only activity the app utilizes.
Log.i(TAG, "loading data from Intent");
final Intent intent = getIntent();
mUsername = intent.getStringExtra(PARAM_USERNAME);
mAuthtokenType = intent.getStringExtra(PARAM_AUTHTOKEN_TYPE);
mRequestNewAccount = mUsername == null;
mConfirmCredentials = intent.getBooleanExtra(PARAM_CONFIRM_CREDENTIALS, false);
That's the block of code working with the intent. Why would you have an intent for the only activity in the app? Is this app called in an unusual way? The Manifest does not include an intent filter for the activity... I guess I'm just a bit lost on this whole thing! If someone could set me straight that'd be great, thanks.
Why would you have an intent for the only activity in the app?
getIntent() gets you the intent that started this activity.
Is this app called in an unusual way?
I guess this activity is called programmatically from another app or activity, since it has been passed some extra data: getStringExtra() is used to extract some data from the intent that started it. putExtra.. and getExtra.. is a way to pass data between activities when they are started.
In that specific example, the intent is sent from the addAccount method in Authenticator.java. That method is called by the OS when you click the Add Account button in the Accounts & sync settings screen and choose your account type.

Categories

Resources