I have an app that starts an activity that isn't the MainActivity first, but it is possible within the course of the app to start the activity on its own. I would like code that runs when the activity is closed to be able to determine if it should go the front of the application(first run) or if it should go back to the previous Activity on the stack(all other runs). Is it possible to determine how an Activity was started inside of it?
You said:
I would like to determine within the course of the Child
Activity what Parent Activity started the Child. In my case that will
either be the Launcher or the MainActivity.
Unfortunately, there is no way to find out what Activity launched your Activity. This information is not available. However...
You can tell if the launcher started your Activity by checking the Intent for ACTION = MAIN and CATEGORY = LAUNCHER:
Intent intent = getIntent();
if (Intent.ACTION_MAIN.equals(intent.getAction()) && intent.hasCategory(Intent.CATEGORY_LAUNCHER)) {
// started by launcher
}
You can also check if the Activity was launched from the list of recent tasks by checking for Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY like this:
Intent intent = getIntent();
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
// Launched from recent task list
}
If this isn't enough for you, then you can always add an "extra" yourself when launching the child Activity from the parent, so that it can tell what Activity started it. For example:
Intent intent = new Intent(this, ChildActivity.class);
intent.putExtra("startedFromMainActivity", true);
startActivity(intent);
and then in your child Activity you can check like this:
Intent intent = getIntent();
if (intent.hasExtra("startedFromMainActivity") {
// started from MainActivity
}
You can store a value in the intent launching your activity, and once opened read it to adapt your behaviour:
intent.putExtra(key,value);
And on the activity side (in onCreate for eg):
getIntent().getExtra(key,defaultValue);
Default value is what you get if no value is found.
getExtra depends o the type of the data stored, so there is getIntExtra ,booleanExtra ,stringExtra ...
Learn more here
your manifesto file exchange mainactivity DEFAULT...
<activity
android:name="com.example.iiintent.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="com.example.iiintent.al">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
</activity>
Related
I have a confusion with how android starts its launcher activities.
If I am declaring a launcher activity in the manifest file like this
<activity android:name=".Activities.Home">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
and I have an Application class which calls an activity based on a check like
if(ParseUser.getCurrentUser() == null){
Intent intent = new Intent(context,Home.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}else{
Intent intent = new Intent(context,MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
which one has the precedence ? The manifest or the Application. What is the flow of events ? e.g. Application->Manifest (or) Manifest->Application (or) Application overrides Manifest ?
If I am receiving a notification in Android, my Application class is called. This makes the activities in the application class to be started, like shown above. Is there a way to detect who calls the Application class ? I mean whether the user starts it, or it starts from the notification which comes in ?
If there is a way to figure this out. How do I prevent the activity in the Application class to be called when I receive a notification ?
Thanks in advance.
Just pass the boolean extras from application and make the diffrence in the call from Application class and User Launch.
Intent intent = new Intent(context,Home.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("APP_CALL",True);
startActivity(intent);
Now in your Home activity Just check for APP_CALL if it is called from Application class then bool value will be true else false.
Also you can write in splash activity for checking login .
I am trying to test how implicit intent can be used to invoke a component within the same app (I am using Android 4.4).
I have a MainActivity and a Activity2. In the AndroidManifest.xml,
<activity
android:name="com.android.intenttest.Activity2"
android:label="#string/title_activity_activity2" >
<intent-filter>
<action android:name="com.android.intesttest.Activity2Action"/>
</intent-filter>
</activity>
In the MainActivity, I tried using:
Intent intentObj = new Intent();
intentObj.setAction("com.android.intesttest.Activity2Action");
if(intentObj.resolveActivity(getPackageManager()) != null){
startActivity(intentObj);
}
else{
Toast.makeText(getApplicationContext(), "No matching activity found", Toast.LENGTH_SHORT).show();
}
It's unable to invoke Activity2 (I can see the Toast). Can someone please point out what I am doing wrong ?
Thanks.
Edit :
I modified the scenario a bit and can't explain what I observe. I have two apps : App 1 and App 2.
App 1 has :
Activity 2 : intent filter with action 'com.android.intenttest.testAction' and category DEFAULT
Activity 3 : no intent filter
App 2 has :
Activity 2 : intent filter with action 'com.android.intenttest.testAction' and category DEFAULT
In App 1's Activity 3, I have :
Intent intentObj = new Intent();
intentObj.setAction("com.android.intesttest.testAction");
if(intentObj.resolveActivity(getPackageManager()) != null){
startActivity(intentObj);
}
else{
Toast.makeText(getApplicationContext(), "No matching activity found", Toast.LENGTH_SHORT).show();
}
I would expect a chooser dialog to pop up and ask to choose between App 1's Activity2 and App 2's Activity2.
But it always displays Activity2 from App2. Can someone explain why ?
Thanks.
For first part of the question, the intent filter needs to be as follows :
<activity
android:name="com.android.intenttest.Activity2"
android:label="#string/title_activity_activity2" >
<intent-filter>
<action android:name="com.android.intesttest.Activity2Action"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
From Android's documentation :
In order to receive implicit intents, you must include the CATEGORY_DEFAULT
category in the intent filter. The methods startActivity() and
startActivityForResult() treat all intents as if they declared the
CATEGORY_DEFAULT category. If you do not declare this category in your intent
filter, no implicit intents will resolve to your activity.
I have an implicit intent in a service that sends information to my main activity, as well as to another class. I also now want that intent to launch my main activity. I've looked at the myriad posts related to this, and tried lots of different things--addCategory, setAction(MAIN; the activity's name; you name it, I've tried it...), category.DEFAULT in the manifest, and several other things that either resulted in ActivityNotFoundExceptions (most commonly) or behavior that was otherwise undesirable.
Here's where the intent is set up and the relevant part of the manifest. The receiver for the intent is registered in the main activity.
final String NEW_DOSES = "changed to protect the innocent";
Intent bluetoothBroadcast = new Intent();
several putExtra lines here
bluetoothBroadcast.setAction(NEW_DOSES);
sendBroadcast(bluetoothBroadcast);
<activity
android:name=".AsthmaAppActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Is it possible to get this intent to launch my main activity with relatively minor changes? Thanks in advance.
Yes it is possible but no with sendBroadcast(bluetoothBroadcast); sendBroadcast does not launch an activity. You must use startActivity to achieve this. For example here is what a launcher application will do in order to launch an application:
public static void LaunchApplication(Context cx, String packagename) {
PackageManager pm = cx.getPackageManager();
Intent i = pm.getLaunchIntentForPackage(ai.packageName);
if (i != null) cx.startActivity(i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
You can easily adjust the extras and the data needed in order to launch the activity. For example if your activity is named myActivity then you can go like this:
Intent i = new Intent(cx, myActivity.class);
//Put the extras and the data you want here...
//If you are launching the activity from a receiver component you must use
//i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
cx.startActivity(i);
Hope this helps...
I am looking to start an activity in my app using a custom action. I have found a few answers but everything I try it throws java.lang.RuntimeException saying No Activity found to handle Intent { act=com.example.foo.bar.YOUR_ACTION }.
This is the activity in my manifest file:
<activity
android:name=".FeedbackActivity" >
<intent-filter>
<action android:name="com.example.foo.bar.YOUR_ACTION" />
</intent-filter>
</activity>
And this is how I'm starting the activity:
Intent intent = new Intent("com.example.foo.bar.YOUR_ACTION");
startActivity(intent);
Any help would be greatly appreciated.
I think what you need is to add a default category to your intent-filter,
eg.
<activity
android:name=".FeedbackActivity" >
<intent-filter>
<action android:name="com.example.foo.bar.YOUR_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
see this answer for more info.
I think you are creating your intent wrong. Try like this:
String CUSTOM_ACTION = "com.example.foo.bar.YOUR_ACTION";
//Intent i = new Intent(this, FeedBackActivity.class); // <--- You might need to do it this way.
Intent i = new Intent();
i.setAction(CUSTOM_ACTION);
startActivity(i);
Just add and intent-filter category as Default.
Implicit intent works perfectly and in many cases its better to use a implicit intent with Intent-action to call a service/Activity than using class-name.
Before startActivty() / startService() with proper context you cane use this method 'queryIntentActivities(Intent intent, int flags)' from package manager class.
It helps the ActivityManager (responsible for launching activities) to check whether the Android system is getting any match with you Intent.
If it doesn't it returns a list size 0 or else >0.
By this you can also check if your app is getting the call,and in this case even if your app is not installed / has got some problem, it will not crash but will throw a warning in Log. Users will face no big trouble apart from app not being launched.
(users will never forgive you if tour app crashes).
Hope this will help !!!
Happy Coding. :)
I faced the same problem when trying to launch the activity residing in the dynamic feature module and starting through action String as the Activity is not resolvable by name at compile time.
So I set the action but the activity crashes every time (No Activity found to handle intent bla bla.. ) until I set the correct package name.
Context c = getApplicationContext();// flag would be require Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag
Intent i = new Intent(action_string);
i.setPackage(context.getPackageName());//this did the trick actually
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
In the Manifest : add catrgory default to the intent filters
from google docs:
<category android:name="android.intent.category.DEFAULT"/>
Note: In order to receive implicit intents, you must include the CATEGORY_DEFAULT category in the intent filter. The methods startActivity() and startActivityForResult() treat all intents as if they declared the CATEGORY_DEFAULT category. If you do not declare it in your intent filter, no implicit intents will resolve to your activity.
I am relatively new to Android programming. I have been given a task at work where I need to create a Custom Home activity launcher. I did a bit of research and found the example on the Android developer website (home sample). This was the start for my prototype.
The custom Home activity will need to require the user to authenticate (enter some simple credentials). My thought was to launch a sub-activity from the Home activity and pass back the results in the intent to the Home activity. I need to be able to capture information about these credentials and that information was going to be passed back to the Home activity. However, I have problems when trying this. I get a log in the LogCat that says the following: "Activity is launching as a new task, so canceling activity result."
I am aware of the startActivityForResult method, but that does not seem to be working for me. Here is where I launch the activity from my Home activity:
#Override
protected void onResume() {
super.onResume();
bindRecents();
Intent iii = new Intent(this, Login.class);
startActivityForResult(iii, STATIC_LOGIN_INTEGER_VALUE);
}
When that code executes, I get the above mentioned log from the ActivityManager tag.
My Login activity has a button that the user will hit once they have entered their credentials. If the credentials are good, then I try to do the following (I put in several logs so that I could try to figure out what is going on):
public void onClick(View src) {
// check for authentic credentials
if(IsValid())
{
Intent loginAuth = new Intent("Login");
loginAuth.putExtra("userRole", userRole);
Log.d("LOGIN", "Setting result...");
if (getParent() == null) {
Log.d("LOGIN", "Parent was null");
setResult(Activity.RESULT_OK, loginAuth);
}
else {
Log.d("LOGIN", "setting result on parent...");
getParent().setResult(Activity.RESULT_OK, loginAuth);
}
Log.d("LOGIN", "Finishing the activity");
finish();
}
}
I defined these activities in my manifest file as the following:
<activity android:name="Home"
android:theme="#style/Theme"
android:launchMode="singleInstance"
android:stateNotNeeded="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="Login"
android:label="Login"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</activity>
I was playing around with the intent filter on the Login activity. I had originally had it set to nothing. I also had the launchMode blank (which defaults to standard I believe). I have played around with most of these options and nothing seems to change the fact that the ActivityManager seems to want to launch the activity as a new task and wants to ignore the returned intent (which I need).
The problem is that you declared your activities with launchMode="singleInstance", so Android creates a new task (i.e. a new process) when it launches the Login activity. Activities in different tasks cannot return results to each other. From the Activity.startActivityForResult() docs:
For example, if the activity you are
launching uses the singleTask launch
mode, it will not run in your task and
thus you will immediately receive a
cancel result.
singleInstance is like singleTask but even more restrictive. Try removing the launchMode attribute from your manifest so that the Login activity will launch in the same task, then using FLAG_ACTIVITY_NEW_TASK when you need to launch a different activity in a separate task.
Barry
The documentation says
For example, if the activity you are launching uses the singleTask
launch mode, it will not run in your task and thus you will
immediately receive a cancel result.
THIS IS WRONG.
You can use the singleTask just fine, what you can't use is singleInstance.
Let's return to the problem. What is the problem?
The problem is that when you call startActivityForResult() on an activity, the caller activity and the activity you are launching must be on the same task for the startActivityForResult() to work properly that means that you can't call startActivityForResult() to an activity using the Intent.FLAG_ACTIVITY_NEW_TASK.
why singleInstance isn't working?
Because a "singleInstance" activity stands alone as the only activity in its task. If it starts another activity, that activity will be launched into a different task regardless of its launch mode — as if FLAG_ACTIVITY_NEW_TASK was in the intent. In all other respects, the "singleInstance" mode is identical to "singleTask".
Why singleTask is working?
Because singleTask doesn't require the creation of a new task for the new activities being launched.
I quoted from this answer to explain the difference between the two launch modes.
Have you declared the setResult(int resultCode, Intent data) in your Login activity.
Android Documentation says
"Note that this method should only be used with Intent protocols that are defined to return a result." If it is not or some other conditions matches as in the documentation of Activity.startActivityForResult(), it will not run in your task and thus you will immediately receive a cancel result."