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.
Related
We recently migrated our Device Policy App(MDM) to support android 12 and would like to open our MDM dpc app after initial setup wizard is complete. This was working fine till android 11 until android 12 updates came out. We are handling GET_PROVISIONING_MODE and ADMIN_POLICY_COMPLIANCE but PROVISIONING_SUCCESSFUL is never called.
This is our code in Manifest for PROVISIONING_SUCCESSFUL :
<activity
android:name=".pages.ProvisioningSuccessActivity"
android:exported="true"
android:theme="#android:style/Theme.NoDisplay"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<intent-filter>
<action android:name="android.app.action.PROVISIONING_SUCCESSFUL"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
We are calling setResult(RESULT_FIRST_USER, intent); on receive of ADMIN_POLICY_COMPLIANCE intent.
Can anyone please help us with this?
Starting with Android 12 the PROVISIONING_SUCCESSFUL intent is only sent when
Provisioning does not happen within the initial setup wizard (e.g. when the end-user installs and starts the DPC app which then triggers provisioning through ACTION_PROVISION_MANAGED_PROFILE) or
No activity for the ADMIN_POLICY_COMPLIANCE activity action can be resolved
See here for the corresponding source code.
So in your case you have to replace the intent filter for PROVISIONING_SUCCESSFUL of your ProvisioningSuccessActivity with an intent filter for ADMIN_POLICY_COMPLIANCE.
Background Information
The ADMIN_POLICY_COMPLIANCE intent has already been introduced in Android 10, together with GET_PROVISIONING_MODE. Since then, it is the recommended intent for DPCs, to extend the initial setup wizard with a compliance screen and enforce initial policy settings:
DPCs must use this new Intent instead of listening for the ACTION_PROFILE_PROVISIONING_COMPLETE broadcast.
(source).
Until Android 12 this change didn't affect existing DPC implementations, that only supported fully managed provisioning. DPCs that also wanted to make use of the new working profiles, already had to switch to the new intents with Android 10.
With the deprecation of ACTION_PROVISION_MANAGED_DEVICE, fully managed provisioning can now only be triggered by the setup wizard. DPC implementations that support only fully managed provisioning have to switch now also to the new intents.
The ACTION_PROFILE_PROVISIONING_COMPLETE broadcast and the PROVISIONING_SUCCESSFUL intent are now only sent, when provisioning is triggered outside of the setup wizard. E.g. when a user installs and starts a DPC app, which triggers provisioning of a working profile through ACTION_PROVISION_MANAGED_PROFILE.
This question targets Android for work.
I have written an app including a DevicePolicyController following this guide. The controller creates a managed profile for my Android device.
I added an app to that profile which is called FooApp.
Now I can see two icons of FooApp in my launcher, one with work badge and one without.
I also have an app BarApp, which is only in the primary profile.
How do I get the launch intent for the work version of FooApp in BarApp? (Start the work version of FooApp from within BarApp)
I can't use CrossProfileApps as I am on API 23.
The Solution I came up with cannot happen without the users consent. Maybe there will be a better one in the future. But here is mine:
I added the following intent filter for FooActivity in the Manifest of FooApp.
<intent-filter>
<action android:name="com.example.FooApp.ACTION_HOMELAUNCHER"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Then I added a crossProfileIntentfilter for my work profile (put the following code in the profile administration app currently running in the work profile).
DevicePolicyManager manager =
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName componentName = BasicDeviceAdminReceiver.getComponentName(context);
IntentFilter filterin = new IntentFilter("com.example.FooApp.ACTION_HOMELAUNCHER");
manager.addCrossProfileIntentFilter(componentName, filterin, DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
In the end, when I want to launch the App in the work profile, I fire the ACTION_HOMELAUNCHER intent from BarApp and then the user can select, whether he wants to lauch the work profile version or the normal version of FooApp.
Feel free to improve upon this answer.
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.
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.
Could you please explain me purpose and usage of LauncherActivity? Documentation says that it "Displays a list of all activities which can be performed for a given intent". I understood that it should automatically build list of all activities found in application and provide their launching. Am I right?
And how to use it? I have found no examples in the web.
Google Code shows the class code itself... It has a different constructor than is described in the Android Platform API.
public abstract class LauncherActivity extends ListActivity {
Intent mIntent;
PackageManager mPackageManager;
IconResizer mIconResizer;
Your phone can have more than one possible app which handles a given intent. One great example is opening a webpage. There's the stock WebKit based browser, you can install Firefox Mobile, Dolphin Browser, Opera Mini... When they all advertise that they can handle a given intent, how does the device know which one it should pass the intent to?
Android will use a LauncherActivity to bring up a selection list of packages where each one listed is one that knows how to do something with the given intent you provide it. When you pick one, you're picking which app you want, and the intent is routed to the matching app.
From that perspective, it's a class that's really part of the Android OS support code, part of figuring out where to distribute given intents to. It's hard to see a situation where you would need to involve yourself with it directly... you should be able to just call StartActivity(Intent), which throws the intent over the wall to the OS, and at that point the device itself should fire up LauncherActivity on its own (if it's even needed).
Completely unrelated (and horribly name-disambiguated) is your application's "Launcher Activity" (documentation) -- an activity that shows in AndroidManifest.xml with an intent filter with "android.intent.action.MAIN" and "android.intent.category.LAUNCHER" ... This is how your app advertises to the system that it wants to have an icon in the device's application list, and that a specific activity should be started when that icon's clicked. You absolutely need to do that.