open android activity in new task without using android:launchMode="singleTask" - android

I've created a browser application with main activity which response to the following intents:
<intent-filter>
<data android:scheme="http"/>
<data android:scheme="https"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<action android:name="android.intent.action.VIEW"/>
</intent-filter>
On url click from other task (gmail, sms) if i choose my application, the activity is open in the same task as the calling task.
When I choose different browser (Mozila firefox, chrome, dolphine) they are opening in different task.
Looking on other browsers manifest, I see that no one using android:launchMode="singleTask".
I don't want to use single task flag since it is not recommended by google and also makes me other prolems.
I tried to understand how does other browsers do it but didn't figure it out.
any ideas? is there other way to open my activity in different task without using singleTask flag?

You can check in onCreate if the activity is running in a single task. If not just finish() it and create it again with using FLAG_ACTIVITY_NEW_TASK
This may help you
ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (RunningTaskInfo task : tasks) {
if (ctx.getPackageName().equalsIgnoreCase(task.baseActivity.getPackageName()))
// check if it's the only one activity or whatever
}

I have found the following description on Android Developers site:
As another example, the Android Browser application declares that the
web browser activity should always open in its own task—by specifying
the singleTask launch mode in the element. This means that
if your application issues an intent to open the Android Browser, its
activity is not placed in the same task as your application. Instead,
either a new task starts for the Browser or, if the Browser already
has a task running in the background, that task is brought forward to
handle the new intent.
As you can see android:launchMode=singleTask is the right choice in your case. You already mentioned that you had issues with this property so maybe let's focus on them.
Update 28.05.2014
Note from Google regarding singleTask launchMode:
The other modes — singleTask and singleInstance — are not appropriate
for most applications, since they result in an interaction model that
is likely to be unfamiliar to users and is very different from most
other applications.
singleTask and singleInstance use case from Google:
Specialized launches (not recommended for general use)
As you can see singleTask may not be recommended for general use but your case is not general, actually it's one of the cases where singleTask fits perfectly.
In other words, singleTask is not forbidden, it's just need to be used with caution in order to provide end users common experience with your app.
I hope I made it clear now for you. Feel comfortable with this launch mode in your case.

You're trying to "bend the rules" a little, and you're not clear enough on what you're trying to avoid by not using android:launchMode="singleTask".
So I would suggest researching into either:
Creating a Service and having that Service listen to the intent filter. Then having this Service open your Activity, and having the Activity's affinity set correctly to match the Service's. This would allow you to get over the issue where affinity is not binding the Activity correctly.
Having a silent Activity starting a new Activity and quiting. The silent Activity would start in a new stack (not in a singletask mode), and would shut itself down upon starting the Activity you actually need.

Related

Android Lollipop behavior change

As per changes in Android Lollipop, reference :
StackOverflow Question
Cheese factory blog
I expect that when I start an activity of other application from my application, it should open in a new task even if the behavior is default (launchmode is standard). So, I made 2 test apps to verify the same behavior. But surpirisingly, the other app always opens up in my app's task, if there's no launchmode specified. I've tested this on Xiaomi Redmi Note 3 (5.1.1), Marshmallow emulator (x86), and the behavior is same for both. I'd appreciate some help on this, and also a link for reference from Android developer's site.
Some code :
Launching app :
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
startActivity(intent);
break;
App to be launched :
<activity android:name="com.android.sample.launchdemo.ActivityB">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
On a button click from launching app, the intent is fired and activity B successfully opens up, but in the same task. Thanks in advance for any help/suggestions.
After looking through the documentation, the feeling I have is that standard mode works the same way as it did before Android 5.0 (Lollipop). The cheese factory blog post was the only one that specified that action and even in my own experience standard launch modes have opened an activity in the same task it was sent in (unless intent flags were passed through). Someone correct me if I am wrong but it is not specified in Android documentation that standard mode would open a new task. From the Android documentation:
"standard" (the default mode): The system creates a new instance of the activity in the task from which it was started and routes the intent to it. The activity can be instantiated multiple times, each instance can belong to different tasks, and one task can have multiple instances. See full documentation
For what you are looking for, when firing off the Intent, the only way to guarantee a new task is use the flag FLAG_ACTIVITY_NEW_TASK. You can set this by calling either intent.setFlag(Intent.FLAG_ACTIVITY_NEW_TASK) or intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) (the latter is for chaining flags together because that method will return the intent).
After doing more research, the only change (relating to this) that appears to be made in Android 5.0 Lollipop is that the recent apps screen can show multiple instances of an activity.
In previous releases, the recents screen could only display only one task for each app that the user interacted with most recently. Now your app can open more tasks as needed for additional concurrent activities for documents. This feature facilitates multitasking by letting users quickly switch between individual activities and documents from the recents screen, with a consistent switching experience across all apps. Examples of such concurrent tasks might include open tabs in a web browser app, documents in a productivity app, concurrent matches in a game, or chats in a messaging app.
To me this seems like the only change relating and the post (cheesefactory and SO) have documentLaunchMode set to create new tasks for each activity (which very well could be the case considering the cheesefactory had a "Gallery" app). Documentation on concurrent documents and documentLaunchMode. documentLaunchMode and the flag FLAG_ACTIVITY_NEW_TASK can be configured to do similar things documentLaunchMode is preferred.
I've found the documentation below.
https://developer.android.com/guide/components/activities/recents.html
=> when the user is using their browser, and they tap Share > Gmail. The Gmail app's Compose screen appears. Tapping the Recents button at that time reveals Chrome and Gmail running as separate tasks. In lower versions of Android, all of the activities appear as a single task, making the Back button the only means of navigation. Figure 2 shows how the Recents screen looks in Android 5.0 and higher, versus lower versions of the platform. The image on the left screen for Android 5.0 and higher, and the image on the right shows how it appears in lower versions of Android.
and refer to the following link.
Lollipop: making my activity stay in the task that launched the share intent
=> By default, launchMode of myfirstapp.MainActivity is "standard" and any intent flags weren't set.
But after myfirstapp.MainActivity is started through share action of Album, the intent flag contains FLAG_ACTIVITY_MULTIPLE_TASK, FLAG_ACTIVITY_NEW_DOCUMENT.
When an activity is started through share, an activity which contains share in its Toolbar just sets Intent to its ShareActionProvider, and then ShareActionProvider starts an activity with this Intent - in this case, myfirstapp.MainActivity.
So I think that from Lollipop, the system begins a new task for the activity from a different app whose launchMode is "standard" only when the activity is started through share action.

How to get all intent filters for application (with root)

I am working on a system application and I need to know programmatically what intents an application is capable of handling. I have seen other questions related to this, but none of them seem to have an answer but also do not seem to be concerned with system privileges.
PackageManager only seems to provide methods to query activities for a given intent. I can not find a way to get intents for a given activity.
For example, if I have an activity which has intent filters defined as such:
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT"/>
</intent-filter>
And I know the activities class name and package name, I would like to find out from the package manager (or any other source) what intents it can handle (in this case, BOOT_COMPLETED and USER_PRESENT).
Good question. I don't think it's possible to find out the intents that an app can handle. Some standard activity actions and broadcast actions are listed at http://developer.android.com/reference/android/content/Intent.html. If you are writing your own app that's having it's own intent filters, then i don't think other apps will know what intents your app can handle because there is no way to publish them or announce them to the world, i believe.
But what is possible is that you can make a call for a particular intent and if that returns null, then you know for sure that there are no apps on the device that can handle that particular intent.
HTH.
So after just asking this question, I found this wonderful answer here:
Android — How to I get a list of all available intent filters?
Which leads to this 5 year old issue
So it doesn't seem like there is any way to do what I want to do at the moment. If it becomes available, I would love to know.
you could try a decompiler, such as "DexDump" (available on GooglePlay), and retrieve the "AndroidManifest.xml" of the application you want to know about.

Android - what is the best way of using Activities (best practice)

I'm writing my first Android app and want to pick up good coding practices. I have an Activity which contains the following:
Button btn = (Button)findViewById(R.id.btnPressMe);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
startActivity(new Intent(Main.this, SecondScreen.class));
}
});
or
startActivity(new Intent("net.mysite.MediaPlayer.CLEARSCREEN"));
AndroidManifest.xml:
<activity
android:name=".landingpage"
android:label="#string/app_name" >
<intent-filter>
<action android:name="net.mysite.MediaPlayer.CLEARSCREEN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
The first way described is best used within your application, the other is used for other application to call your activity.
Abu,
The answer to your question depends largely on what you are trying to accomplish. Keep in mind that the other answers provided thus far have valuable input in regard to making your decision.
The Android Philosophy
Android is designed such that the User ultimately decides which applications take care of which tasks. Applications may overstep them, but should only do so if they are the only ones reasonably able to take care of that task OR if it is necessary for the functioning of the application as a whole.
An Intent marks the User's or the System's or an Application's desire to perform said task. Just because an Intent is made does not require that the User know or initiate it, though often it is best. However, if the Intent is hidden to the User, one might question whether it should be an Intent at all. This is something that is still being worked out by the development community and there are advocates both for and against the practice.
Static Class Intents
startActivity(new Intent(Main.this, SecondScreen.class));
These should be used when you cannot trust another application to handle your desired Task effectively. These kinds of tasks should also be "hidden" from the User, as the User may not care what is happening or who is doing it, so long as it gets done. Additionally, they should only be used for stable code that is not subject to changes. As Snicolas stated (and I personally agree):
Classes can vary in the life of an app.
Action String Intents
startActivity(new Intent("net.mysite.MediaPlayer.CLEARSCREEN"));
These should be used whenever possible. However, they should only be used when the Task can be performed by another application without destabilizing your own application. The Action String can be designed in such a way that it is rare enough to not be called by anyone else, but understand that an Action will prompt the User if more than one Application can handle it.
Analogize the idea similar to: "I use Microsoft Office for Databases and Word Processing, but when I want a Spreadsheet, I use Open Office". Both provide compatible results, but one is preferred for one reason or another. This works because Excel is not required for Word or Access to work correctly. Neither are Open Office's equivalents required for any other working part. They are all installed together but work independantly because they work with different resources and data entirely.
Hope this helps,
FuzzicalLogic
It's better not to use a static class name to call an intent. Classes can vary in the life of an app. Later, if you decide that this activity should change for another class, you would just have to change it in one and only one place if you use the AndroidManifest way.
Also, defining this kind of configuration provides other apps with a way to call your activities to get a service done. And that's the actual power of android to let apps communicate through intents.

How to start a Service when .apk is Installed for the first time

In my Application I am not having any UI part, so I need to start a Service as soon as the Applicaton gets installed on the Device. I saw many links from which the answer was that its not possible but I guess it is surely possible. Just have a look at PlanB Application on the Android Market that does fulfil my requirement. Below is my Manifest file how I tried, but the Service was not called at all. So, let me know what is the best possible way to start a Service when the Application gets Installed.
UPDATE
I also tried using android.intent.action.PACKAGE_ADDED it works fine for detecting the Package for the other Applications but not for itself.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.auto.start"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:icon="#drawable/ic_launcher" >
<service android:name=".MyService">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</service>
<receiver android:name=".BootUpReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.PACKAGE_INSTALL" />
<action android:name="android.intent.action.PACKAGE_ADDED" />
<data android:scheme="package"/>
</intent-filter>
</receiver>
</application>
</manifest>
Fortunately, Plan B does not work on Android 3.1+, as tested on a XOOM and a Galaxy Nexus.
What Plan B does is exploit a security hole that could be used by drive-by malware, which is specifically why Android prevents it from happening anymore.
UPDATE
To clarify: As inazaruk posted and I put into comments on other answers, all applications, upon installation, are placed in a "stopped" state. This is the same state that the application winds up in after the user force-stops the app from the Settings application. While in this "stopped" state, the application will not run for any reason, except by a manual launch of an activity. Notably, no BroadcastReceviers will be invoked, regardless of the event for which they have registered, until the user runs the app manually.
This block covers the Plan B scenario of remote-install-and-run, which they were taking advantage of previously. After all, with that, anyone with a hacked Google account would be at risk of having their device infected, hands-free as it were.
So, when the OP says:
I need to start a Service as soon as the Applicaton gets installed on the Device
the OP will be unsuccessful and will need to redesign the application to avoid this purported "need".
Applications installed on the /system partition are not subject to being placed into the "stopped" state after installation. If you have root, you can do,
$ adb root
$ adb remount
$ adb push your.apk /system/app
And it can immediately receive broadcast intents. This certainly doesn't provide a general purpose solution, but i wanted to mention it for completeness.
EDIT: Keep in mind that different versions of Android locate system APKs in different places. For example, Android 8 puts them under /system/app//.apk. Shell into your device and poke around and follow the same scheme used for other system APKs.
I agree with CommonsWare's answer to question: How to start android service on installation. In other words, you can't automatically start your service after you've just been installed.
One more thing about newer Android platforms: if you don't have UI at all, you'll have trouble starting your service even when using BOOT_COMPLETE intent on Android 3.1+.
That's because all installed applications are in stopped state. In this state applications will not receive ANY broadcast notifications.
In order to activate your application some other application (or user) needs to start your service or activity, or content provider. The usual workflow is when user clicks on your application's icon.
I've written a detailed explanations about this in my blog post.
Plan B does this launch by listening to the events which happen in the system. It uses a receiver which literally listenes to hundreds of events hoping that some of them will eventually fire up. So this is how you can do it. Otherwise, there are no built-in means to launch the application as soon as it gets installed.
I'm not sure what your constraints/purpose is, but if you can install another application that has an activity you can have it send an intent with the flag FLAG_INCLUDE_STOPPED_PACKAGES.
This will use your application for the intent resolution, even though it's in a stopped state. If the action of the intent matches one of your filters, it will also bring the package out of the stopped state.
I don't think so You can start service immediately after installed your application on device,
The application must first be invoked by the user through some sort of Activity.The only things you have to register some Broadcast Receiver with appropriate intents in manifest which invoke you service when something is happening on device but this remaing to Android 3.1 version.
EDIT:
After Android 3.1+ onwards you can not use any Broadcast for starting your application, because all application remains in inactive state after completion of device boot and to launch the application the user have to invoke it.(By touching the app icon).
As stated by CommonsWare in the answer to this question (which I suppose you have all ready seen, but chose to ignore) starting a Service on install is not possible - it is simply not a thing that is implemented into the platform.
Starting it automaticly at the next boot is however possible.
As stated in the Technical Details for PlanB:
Plan B will attempt to launch as soon as it downloads, but in some cases you will need to send an SMS to get it started.
My guess is that on a rooted phone you might be able to start the Service on install - but there's no guarantee that the phone is rooted, which is why PlanB will require recieving a text in some cases because that can be registered by the IntentFilter of the app and then used to start the Service.
there is an app on google play Android Lost which invoke the registration service for google push messages via an incoming sms without launching the app even once for version 3.0+.
Perhaps the best way to accomplish this (and now I'm speaking to the specific intent of the OP, a program that gets installed in order to retrieve a stolen phone, not the general question) is social engineering, not software engineering.
So, an icon with text like "Password List" or "My Bank Accounts" which suddenly appeared on the home screen would undoubtedly be clicked on. Look at the success of all sorts of other phishing, and here you would be targeting a thief, who's already motivated to continue nefarious activity. Let the thief start it for you. :)
HEY I think using a BroadcastRecivier to automatically start the app on restart of device hence it will automatically start on device start.Hope this will help

Understanding which Activity starts first in an Android app

It isn't clear to me how Android determines which Activity starts first when an app starts. The Android documentation states the following concerning the AndroidManifest.xml file about Activities:
"Only one activity should have the "main" action and "launcher" category..."
So in the AndroidManifest.xml file, you should essentially have only one:
action android:name="android.intent.action.MAIN"
category android:name="android.intent.category.DEFAULT"
However, while looking at sample code from the Android SDK, the application called "APIDemos" contains a manifest file with tons of
"android.intent.action.MAIN" and
"android.intent.category.DEFAULT"
I am totally confused. This seems to go contrary to what Google is stating about there only suppose to be one. Does Android simply grab whichever one appears first in the manifest and ignores all the others? If not, why are there multiple MAINs and DEFAULTs?
Activities will very often need to support the CATEGORY_DEFAULT so that they can be found by Context.startActivity(). So, CATEGORY_DEFAULT can appear number of times.
Android does not grab whichever one appears first in the manifest but it starts with activity having CATEGORY_LAUNCHER.
CATEGORY_LAUNCHER : The activity can be the initial activity of a task and is listed in the top-level application launcher.
For more details refer:
http://developer.android.com/guide/topics/intents/intents-filters.html
action.MAIN and category.LAUNCHER are the ones that are used to specify what activity gets launched when the user presses your app icon or selects it from the running list of apps.
You can use other combinations of actions and category.DEFAULT to respond to different events but the combination of action.MAIN and category.LAUNCHER should only be defined once.
I am totally confused. This seems to go contrary to what Google is stating about there only suppose to be one.
It isn't contrary. These activities have category CATEGORY_DEFAULT, but not CATEGORY_LAUNCHER.

Categories

Resources