Launching Activities via package names

1

I have been working on testing some packages that I do not have the source code for, and one of the packages is normally launched by pressing three buttons for three seconds. When I try to launch the package using the typical method, I get a java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Intent android.content.Intent.addFlags(int) error. Below is my code

@Before
public void setup() {
    //Initialize UiDevice instance
    Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
    mDevice = UiDevice.getInstance(instrumentation);

    mDevice.pressHome();

    final String launcherPackage = mDevice.getLauncherPackageName();
    assertThat(launcherPackage, notNullValue());
    mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT);

    Context context = InstrumentationRegistry.getTargetContext();
    final Intent intent = context.getPackageManager()
            .getLaunchIntentForPackage(DEALER_DIAG_PACKAGE);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    context.startActivity(intent);

    mDevice.wait(Until.hasObject(By.pkg(DEALER_DIAG_PACKAGE).depth(0)), LAUNCH_TIMEOUT);
}

I tried using getContext instead of getTargetContext, however someone pointed out to me that if the intents are not exported, I will not be able to launch the package this way no matter what I do. I tried to get the package names by using the command adb logcat ActivityManager:V *:F as well as adb shell pm list packages -f

--------- beginning of main
I/ActivityManager( 2296): START u0 {flg=0x10000000 
cmp=com.android.systemui/.usb.UsbDebuggingActivity (has extras)} from uid 
1000 on display 0
I/ActivityManager( 2296): Displayed 
com.android.systemui/.usb.UsbDebuggingActivity: +184ms
I/ActivityManager( 2296): START u0 {act=android.intent.action.MAIN cat=
[android.intent.category.HOME] flg=0x10200000 
cmp=com.android.launcher3/.Launcher} from uid 1000 on display 0
I/ActivityManager( 2296): START u0 
{act=com.REDACTED.auto.diagnostics.dealer.MAIN flg=0x10800000 
cmp=com.REDACTED.auto.diagnostics/.dealer.MainActivity} from uid 1000 on 
display 0
I/ActivityManager( 2296): Start proc 
20943:com.REDACTED.auto.diagnostics/1000 for activity 
com.REDACTED.auto.diagnostics/.dealer.MainActivity
I/ActivityManager( 2296): Displayed 
com.REDACTED.auto.diagnostics/.dealer.MainActivity: +572ms

Does anyone have any input as to why I am getting this error? I have tried using every package name listed in the logcat dump with no success. Any input would be appreciated.

android
testing
android-junit
asked on Stack Overflow Jun 6, 2017 by Tadhg

2 Answers

1

If you want to launch another app just first check if this app is installed, or you'll get a NullPointerException, then launch the app by an intent with the package options:

Just like this:

Intent launchIntent = getPackageManager().getLaunchIntentForPackage("com.domain.anotherapp");
        if (launchIntent != null) {
            startActivity(launchIntent);//null pointer check in case package name was not found
        }

This will launch the app with the default launch activity, if you want to launch a specific activity you already have to know how to handle the requirements of the other app side or will simply crash or not work (probably you might need to pass some variable or some data to represent previous information of this app), anyway, to open this specific activity you have to use ComponentName.

The ComponentName constructor taking two Strings can be used to refer to a component in another application. But, the first argument is not the package name of the class; it is the package name of the application---the package attribute of the manifest element in that application's AndroidManifest.xml. So your first example should be

ComponentName cn = new ComponentName("com.domain.anotherapp",
    "com.domain.anotherapp.widget.WidgetProvider");

That constructor could certainly be used to refer to components in your own application, but since you already have hold of a Context from your own application you might as well use it and use one of the other constructors. In my opinion, the one taking a Class should be preferred whenever usable. You could use the one taking a String if you only know the class dynamically for some reason; in that case, it should take the fully-qualified class name as above.

The complete use to launch by an intent (without handle the null pointer exception for an incorrect passed information):

Intent launchIntent = new Intent(Intent.ACTION_MAIN);
                launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
                ComponentName cn = new ComponentName("com.domain.anotherapp",
                "com.domain.anotherapp.widget.WidgetProvider");
                launchIntent.setComponent(cn);

                startActivity(launchIntent);

Reference: https://developer.android.com/reference/android/content/ComponentName.html

answered on Stack Overflow Jun 6, 2017 by Brandon Zamudio • edited Dec 14, 2018 by Kees de Vriesch
0

I figured out a method that worked for me, though Brandon's could possibly work on another solution. Here is my solution:

Intent intent = new Intent("com.REDACTED.auto.diagnostics.dealer.MAIN");
intent.setClassName("com.REDACTED.auto.diagnostics", 
"com.REDACTED.auto.diagnostics.dealer.MainActivity");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Context c = InstrumentationRegistry.getContext();
c.startActivity(intent);

This possibly does the same thing that Brandon's solution does, however less abstracted.

answered on Stack Overflow Jun 6, 2017 by Tadhg

User contributions licensed under CC BY-SA 3.0