Search code examples
androidandroid-intentandroid-activityandroid-manifestandroid-activity-alias

Extract / distinguish ActivityAlias name from TargetActivity


I have multiple ActivityAliases which all start one single TargetActivity. Inside of my TargetActivity I try to distinguish the alias that started the TargetActivity.

The aliases are defined in Manifest as launchables (intent-filter), which will be displayed as shortcuts on the homescreen. The user will click on the shortcut and android will start the activity, which I defined in the "android:targetActivity=.." tag.

For that I currently extract the componentName from the Intent, which is given to my TargetActivity and using the className().

Like:

String aliasName = targetActivity.getComponentName().getClassName();

This works fine for a lot of devices. But currently I see some failures on the OnePlus. At that device, my technique only returns the className of my TargetActivity and therefore I can't deliver the action, based on the alias that the user started.

Are there any other, reliable methods to get ActivityAlias that was used to start the TargetActivity? It does not need to be the name itself, as long as I can distinguish them. I do not want to create dedicated TargetActivities for every Alias!

Thanks!

Ps.: I saw another way, which uses the PackageManager to retrieve the activityInfo and using the Activity.name. But I doubt that this will return something different than my first approach.

ActivityInfo aInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), PackageManager.GET_META_DATA);

String aliasName = aInfo.name;

I also tried meta-data:

Edit:

Unfortunately this method does not work for all devices. If the parsed alias-className from the activity.component returns the target-activity, then the meta-data approach fails, too.

I continued searching for an answer and found a good workaround to distinguish between my aliases inside of the TargetActivty.

You can provide meta-data within your ActivityAlias tag like so:

<activity-alias 
    android:name=".aliasName" 
    android:enabled="false" 
    android:exported="true" 
    android:icon="@drawable/someIconRes" 
    android:label="@string/someLabelRes" android:targetActivity=".yourTargetActivity"> 
    <meta-data android:name="alias" android:value="valueToDistinguish"/>
    <intent-filter>  
        <action android:name="android.intent.action.MAIN"/> 
        <category android:name="android.intent.category.LAUNCHER"/> 
    </intent-filter> 
</activity-alias>

The important part here is:

<meta-data android:name="alias" android:value="valueToDistinguish"/>

Which is within the <activity-alias> here </activity-alias> tag.

To extract the meta-data you can get an ActivityInfo from the PackageManager with the TargetActivity:

ActivityInfo appInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), PackageManager.GET_META_DATA);

And extract the meta-data via:

    private static String getAliasNameByMetaData(ActivityInfo app) {
    String aliasName = "";
    if (app.metaData != null && app.metaData.containsKey(ALIAS_META_DATA_KEY)) {
        aliasName = app.metaData.getString(ALIAS_META_DATA_KEY, "");
    } else {
        LOG.i("AliasName by META-DATA didn't work!");
    }
    LOG.v("AliasName by META-DATA: " + aliasName);
    return aliasName;
}

Edit:

Inspecting the Activity class using the debugger, it includes a mActivityInfo field that is different from the ActivityInfo returned by getPackageManager().getActivityInfo() so you can extract it using reflection and check it's name.

Note: It seems that the ActivityInfo returned by getPackageManager().getActivityInfo() is a shallow copy of the mActivityInfo from the Activity. So, maybe this method does not resolve the issue:

Field field = Activity.class.getDeclaredField("mActivityInfo");
field.setAccessible(true);
ActivityInfo value = (ActivityInfo) field.get(this);
Log.e("APPINFO2", "NAME: " + value.name);

Solution

  • 1. Meta-Data

    Unfortunately this method does not work for all devices. If the parsed alias-className from the activity.component returns the target-activity, then the meta-data approach fails, too.

    I continued searching for an answer and found a good workaround to distinguish between my aliases inside of the TargetActivty.

    You can provide meta-data within your ActivityAlias tag like so:

    <activity-alias 
        android:name=".aliasName" 
        android:enabled="false" 
        android:exported="true" 
        android:icon="@drawable/someIconRes" 
        android:label="@string/someLabelRes" android:targetActivity=".yourTargetActivity"> 
        <meta-data android:name="alias" android:value="valueToDistinguish"/>
        <intent-filter>  
            <action android:name="android.intent.action.MAIN"/> 
            <category android:name="android.intent.category.LAUNCHER"/> 
        </intent-filter> 
    </activity-alias>
    

    The important part here is:

    <meta-data android:name="alias" android:value="valueToDistinguish"/>
    

    Which is within the <activity-alias> here </activity-alias> tag.

    To extract the meta-data you can get an ActivityInfo from the PackageManager with the TargetActivity:

    ActivityInfo appInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), PackageManager.GET_META_DATA);
    

    And extract the meta-data via:

        private static String getAliasNameByMetaData(ActivityInfo app) {
        String aliasName = "";
        if (app.metaData != null && app.metaData.containsKey(ALIAS_META_DATA_KEY)) {
            aliasName = app.metaData.getString(ALIAS_META_DATA_KEY, "");
        } else {
            LOG.i("AliasName by META-DATA didn't work!");
        }
        LOG.v("AliasName by META-DATA: " + aliasName);
        return aliasName;
    }
    

    2. mActivityInfo

    Inspecting the Activity class using the debugger, it includes a mActivityInfo field that is different from the ActivityInfo returned by getPackageManager().getActivityInfo() so you can extract it using reflection and check it's name.

    Note: It seems that the ActivityInfo returned by getPackageManager().getActivityInfo() is a shallow copy of the mActivityInfo from the Activity. So, maybe this method does not resolve the issue:

    Field field = Activity.class.getDeclaredField("mActivityInfo");
    field.setAccessible(true);
    ActivityInfo value = (ActivityInfo) field.get(this);
    Log.e("APPINFO2", "NAME: " + value.name);