How does "parallel apps" feature work on OnePlus 3 devices, and how can we use Intents properly with them?
Asked Answered
C

0

33

Background

Apps use Intents to open other apps, sometimes with specialized Intents.

One example is this Intent, to choose a contact from WhatsApp:

val WHATSAPP_PACKAGE_NAME = "com.whatsapp"
val whatsAppPickIntent = Intent(Intent.ACTION_PICK).setPackage(WHATSAPP_PACKAGE_NAME)

This works fine in general. Same goes for when you wish to launch the app:

val launchIntent=packageManager.getLaunchIntentForPackage(WHATSAPP_PACKAGE_NAME)

The problem

Recently I was informed of a relatively new feature, allowing the user to have multiple instances of the same app. It might be available on other devices, but on OnePlus devices it's called "parallel apps". Here's an example of 2 instances of WhatsApp, each is assigned to a different phone number :

enter image description here

Thing is, this can break how Intents work with a single instance of the app. Now the Intent doesn't know for which app to go to. The launcher show 2 icons now for WhatsApp:

enter image description here

If you choose to launch WhatsApp via the normal launcher icon (the left one), it shows this dialog:

enter image description here

Works fine, but if you choose to use the picker intent, you still get this dialog, but when you choose an item, from the dialog, it doesn't let you really do anything with it (opens and closes the app), while showing a toast "The file format is not supported".

What I've tried

Since I don't have the device, I tried to read about it over the Internet, but I only found user-related information, such as these:

I've decided to try to investigate it further, by sending an APK to the person who told me about it, trying to see if the next code will work any different:

    val whatsAppPickIntent = Intent(Intent.ACTION_PICK).setPackage(WHATSAPP_PACKAGE_NAME)
    val queryIntentActivities: List<ResolveInfo> = packageManager.queryIntentActivities(whatsAppPickIntent, 0)
    button2.setOnClickListener {
        intent = Intent(Intent.ACTION_PICK)
        val resolveInfo = queryIntentActivities[0]
        toast("number of possible choices:" + queryIntentActivities.size)
        intent.component = ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)
        startActivity(intent)
    }

The toast that will be shown tells that I have only one thing that can handle the intent, and indeed when I use it, I get the same dialog for choosing which instance of it to use. And like in the original Intent, it fails with the same toast.

EDIT: Later I tried the next thing: I asked to show what are the ResolveInfo properties, before and after enabling the feature, by using this code:

    val launchIntent = packageManager.getLaunchIntentForPackage(WHATSAPP_PACKAGE_NAME)
    val whatsAppPickIntent = Intent(Intent.ACTION_PICK).setPackage(WHATSAPP_PACKAGE_NAME)
    var queryIntentActivities: List<ResolveInfo> = packageManager.queryIntentActivities(whatsAppPickIntent, 0)
    var sb = StringBuilder()
    queryIntentActivities[0].dump(object : Printer {
        override fun println(x: String?) {
            if (x != null)
                sb.append(x)
        }
    }, "")
    val pickResult = "pick result:packageName:\"" + queryIntentActivities[0].activityInfo.packageName + "\" name:\"" + queryIntentActivities[0].activityInfo.name + "\"\n\n" + "extended:" + sb.toString()
    sb = StringBuilder()
    queryIntentActivities = packageManager.queryIntentActivities(launchIntent, 0)
    queryIntentActivities[0].dump(object : Printer {
        override fun println(x: String?) {
            if (x != null)
                sb.append(x)
        }
    }, "")
    val launchResult = "launch result:packageName:\"" + queryIntentActivities[0].activityInfo.packageName + "\" name:\"" + queryIntentActivities[0].activityInfo.name + "\"\n\n" + "extended:" + sb.toString()
    val body = pickResult + "\n\n" + launchResult
    val emailIntent = Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "", null))
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, "whatsApp investigation")
    emailIntent.putExtra(Intent.EXTRA_TEXT, body)
    startActivity(Intent.createChooser(emailIntent, "Send email..."))

The result is that both are the same, as if everything is fine. Here's the result when it's turned on/off (exact same thing) :

pick result:packageName:"com.whatsapp" name:"com.whatsapp.ContactPicker"
extended:priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=falseActivityInfo:  name=com.whatsapp.ContactPicker  packageName=com.whatsapp  enabled=true exported=true directBootAware=false  taskAffinity=com.whatsapp targetActivity=null persistableMode=PERSIST_ROOT_ONLY  launchMode=0 flags=0x3 theme=0x7f110173  screenOrientation=-1 configChanges=0xfb3 softInputMode=0x0  lockTaskLaunchMode=LOCK_TASK_LAUNCH_MODE_DEFAULT  resizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION  ApplicationInfo:    name=com.whatsapp.AppShell    packageName=com.whatsapp    labelRes=0x7f100473 nonLocalizedLabel=null icon=0x7f080c15 banner=0x0    className=com.whatsapp.AppShell    processName=com.whatsapp    taskAffinity=com.whatsapp    uid=10099 flags=0x3 privateFlags=0x1010 theme=0x7f110164    requiresSmallestWidthDp=0 compatibleWidthLimitDp=0 largestWidthLimitDp=0    sourceDir=/data/app/com.whatsapp-NaKTLVhiNTh4zEGhFdkxrg==/base.apk    seinfo=default:targetSdkVersion=26    seinfoUser=:complete    dataDir=/data/user/0/com.whatsapp    deviceProtectedDataDir=/data/user_de/0/com.whatsapp    credentialProtectedDataDir=/data/user/0/com.whatsapp    enabled=true minSdkVersion=15 targetSdkVersion=26 versionCode=452238 targetSandboxVersion=1    supportsRtl=true    fullBackupContent=true    category=4

launch result:packageName:"com.whatsapp" name:"com.whatsapp.Main"

extended:priority=0 preferredOrder=0 match=0x0 specificIndex=-1 isDefault=falseActivityInfo:  name=com.whatsapp.Main  packageName=com.whatsapp  labelRes=0x7f10044c nonLocalizedLabel=null icon=0x0 banner=0x0  enabled=true exported=true directBootAware=false  taskAffinity=com.whatsapp targetActivity=null persistableMode=PERSIST_ROOT_ONLY  launchMode=0 flags=0x3 theme=0x0  screenOrientation=-1 configChanges=0xfb3 softInputMode=0x0  lockTaskLaunchMode=LOCK_TASK_LAUNCH_MODE_DEFAULT  resizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION  ApplicationInfo:    name=com.whatsapp.AppShell    packageName=com.whatsapp    labelRes=0x7f100473 nonLocalizedLabel=null icon=0x7f080c15 banner=0x0    className=com.whatsapp.AppShell    processName=com.whatsapp    taskAffinity=com.whatsapp    uid=10099 flags=0x3 privateFlags=0x1010 theme=0x7f110164    requiresSmallestWidthDp=0 compatibleWidthLimitDp=0 largestWidthLimitDp=0    sourceDir=/data/app/com.whatsapp-NaKTLVhiNTh4zEGhFdkxrg==/base.apk    seinfo=default:targetSdkVersion=26    seinfoUser=:complete    dataDir=/data/user/0/com.whatsapp    deviceProtectedDataDir=/data/user_de/0/com.whatsapp    credentialProtectedDataDir=/data/user/0/com.whatsapp    enabled=true minSdkVersion=15 targetSdkVersion=26 versionCode=452238 targetSandboxVersion=1    supportsRtl=true    fullBackupContent=true    category=4

So I wanted to check on something else: Try to put a widget-shortcut of WhatsApp (called "whatsApp chat"), that requires you to choose a contact, when this feature is turned on. Turns out, it can't handle it well. It asks which app to create the widget to: the original or the clone. If you choose the original, all is fine. If you choose the clone, it adds the widget all fine and well, but when clicking on it, it goes to the main window of the app instead of going to the person.

The questions

  1. How can I differentiate between the main instance and the "cloned" one? I mean, how can an Intent be directed to a single instance (the main one) of the targeted app? I ask this about both of the Intents I've presented (launch and picker).

  2. How does this feature even work? Where does the private data of each instance gets saved now? Does each of them have a process, with a different name?

  3. Do other devices of other OEMs have this feature? Does it work there the same way as here ?

  4. Why do we see the toast message, if the user chose the app to target to? Is it maybe a buggy feature, that will work only for launch-intents?

  5. Is there at least a way to know that a given app (given a package name of it) has this feature enabled for it?

Cudlip answered 19/4, 2018 at 21:44 Comment(13)
For 3. Yes, MI Phones have a similar feature called Dual Apps. IRC There's also an app called Parallel Space that let's you do this as well. As for 4. Maybe you could look at system logs around when this event occurs. There's a chance that this was caused by an exception which may give you more information to work with. Essentially, 1. and 5. are more or less the same question. To be able to distinguish between two instances, it requires you to know that there are two instances.Bid
@KaranModi 1 and 5 aren't the same. 1 is about the Intent, and 5 is for the more general thing, to at least know if the feature is enabled for a package name. Doesn't require an Intent.Cudlip
From what I was able to gather, since the process of "cloning" is independent of the target app, with the actual implementation differing across platforms (Dual Apps, Parallel Apps, Parallel Space, etc.). There seems to be be no way to find out if your target app can or has been cloned. Therefore, the most that you can reliably find out is if your target app has multiple instances if a method to do so exists.Bid
I have a OP 3T and from my experience the two WhatsApp works perfectly with every external action I came across after you pick which one you want to use. Never tried to do it myself though. Might give it a try and let you know. Maybe you can ask on the official forums too?Shanonshanta
@Shanonshanta Actually I noticed it exists on other smartphones and not just of OnePlus company. Just with different name for the feature. Still, was hoping for a possible workaround, and I don't think there is. Have you tried the widget-shortcut of WhatsApp, to chat directly with a person?Cudlip
Not a big fan of widget, but I just tried because you asked. Widget do not work properly. There's a single entry in the widget list for WhatsApp, and although when you try to add one the system ask for which copy to use, once added they only work with the original one, even if you choose the clone when adding it. They work nonetheless, the chat shortcut opens the wrong copy of the app but it opens it on the correct chat, not the main screen as in your caseShanonshanta
@Shanonshanta Well maybe they fixed it on your case, by making it work as if you've chosen the original app and not its clone.Not working the best, but at least it's better than what I was told.Cudlip
Maybe it depends on the model or sw version... if you can get the exact data we can compareShanonshanta
@Shanonshanta In either case, my original question isn't about it. It's about how to check things programmatically about it, and how to work with it (or at least launch the original app instead of the clone or the chooser-dialog), including the above Intents.Cudlip
yes of course, but given that it's not an android built in feature, I doubt there's a standard way to do any of that. That's why I proposed to check/ask on the official forum, either of OnePlus or other brandsShanonshanta
@Shanonshanta Where exactly? And how could I know it works, and that it works on other devices that OnePlus don't own?Cudlip
No idea about that, sorry. I'd just ask somewhere on the official forums or maybe on XDA.Shanonshanta
Does anyone has answer for this problem?Lacagnia

© 2022 - 2024 — McMap. All rights reserved.