[TUT] Supporting multiple icons in your app
Posted by Chainfire on 20-02-2013 at 22:15:00 - Comments: 241 - Views: 42797
Project: Tutorials - Tags: Code Android Good news
Project: Tutorials - Tags: Code Android Good news
After a lot of noise about the icon to use for SuperSU, I finally released SuperSU v1.00 in late January 2013, with support for multiple icons that the user could pick from.
As far as I know, SuperSU was the first app on Android to allow you to choose between several different icons. Other developers quickly picked up on this, and I have received quite a few requests to explain how I did it.
It is in fact very easy to do, and once you've seen how it's done, you'll probably think "heck, I could've thought of that !". And you could have - within a day of the SuperSU release that brought this feature, Ronald Ammann already figured it out after having a quick glance at SuperSU's AndroidManifest.xml file.
Long story short: use <activity-alias> and PackageManager.setComponentEnabledSetting().
Short story long: following is how I thought of it, the nitty gritty, and copy/pastes straight from SuperSU sources.
Instead of using only the winning icon from the competition, I wanted to give the end-user the choice of several options. Thinking for a few minutes how to accomplish this, the first thing that came to mind was to use multiple launcher activities (you can have as many activities listed in launcher as you want) that simply launched the main activity in their onCreate's and passed it some extra parameter in the intent, so the main activity knew which icon to show in the ActionBar, and finish(). I quickly realised this was a terrible idea and ain't nobody got time for that to make all these copy/paste activities.
Then I remembered seeing <activity-alias> somewhere in the docs. I had never actually had a use for it, so I looked it up to see if it could be the solution I was looking for - and indeed it was. By using <activity-alias> I could easily create several icon options leading to the same activity.
But of course we do not want all the icons to show in the launcher, so we need a way to select which one to show. We can do this easily in the AndroidManifest.xml file using the android:enabled attribute of the <activity-alias> tag to define the default, and use PackageManager.setComponentEnabledSetting() in code to switch to a different icon.
The Android Manifest
Here's a relevant excerpt from SuperSU's AndroidManifest.xml file (some lengthy and irrelevant attributes to this example stripped), with two of the five <activity-alias>'s:
As you can see, the <activity-alias>'s point back to .MainActivity - which itself does not show up in launcher, as it does not have the launcher category set. .MainActivity-SuperAndy is the one shown by default, it's the only with android:enabled set to true.
CAVEAT: If you duplicate this, make sure that your default alias - the only alias which is enabled in the XML - is also the first <activity-alias> listed. I'm not sure what exactly the cause is, but I've had issues with no icon showing up at all on some Android versions if the enabled alias was not also the first one.
CAVEAT: (Eclipse) If you try to run the app now, it is likely that Eclipse/ADT/whatever-is-responsible will not be able to deduce how to launch your app, so it will just install your app, instead of launching it. To work around this, go to your project's properties, Run/Debug Settings, Edit your launch configuration, and select your main activity to launch manually.
The Java Code
Here's a slightly modified excerpt of the code in SuperSU to actually change the icon:
As far as I know, SuperSU was the first app on Android to allow you to choose between several different icons. Other developers quickly picked up on this, and I have received quite a few requests to explain how I did it.
It is in fact very easy to do, and once you've seen how it's done, you'll probably think "heck, I could've thought of that !". And you could have - within a day of the SuperSU release that brought this feature, Ronald Ammann already figured it out after having a quick glance at SuperSU's AndroidManifest.xml file.
Long story short: use <activity-alias> and PackageManager.setComponentEnabledSetting().
Short story long: following is how I thought of it, the nitty gritty, and copy/pastes straight from SuperSU sources.
Instead of using only the winning icon from the competition, I wanted to give the end-user the choice of several options. Thinking for a few minutes how to accomplish this, the first thing that came to mind was to use multiple launcher activities (you can have as many activities listed in launcher as you want) that simply launched the main activity in their onCreate's and passed it some extra parameter in the intent, so the main activity knew which icon to show in the ActionBar, and finish(). I quickly realised this was a terrible idea and ain't nobody got time for that to make all these copy/paste activities.
Then I remembered seeing <activity-alias> somewhere in the docs. I had never actually had a use for it, so I looked it up to see if it could be the solution I was looking for - and indeed it was. By using <activity-alias> I could easily create several icon options leading to the same activity.
But of course we do not want all the icons to show in the launcher, so we need a way to select which one to show. We can do this easily in the AndroidManifest.xml file using the android:enabled attribute of the <activity-alias> tag to define the default, and use PackageManager.setComponentEnabledSetting() in code to switch to a different icon.
The Android Manifest
Here's a relevant excerpt from SuperSU's AndroidManifest.xml file (some lengthy and irrelevant attributes to this example stripped), with two of the five <activity-alias>'s:
Code
#
1
<activity
2
android:name=".MainActivity"
3
android:label="@string/app_name"
4
... >
5
<intent-filter>
6
<action android:name="android.intent.action.MAIN" />
7
</intent-filter>
8
</activity>
9
10
<activity-alias
11
android:enabled="true"
12
android:name=".MainActivity-SuperAndy"
13
android:label="@string/app_name"
14
android:icon="@drawable/ic_launcher_superandy"
15
android:targetActivity=".MainActivity">
16
<intent-filter>
17
<action android:name="android.intent.action.MAIN" />
18
<category android:name="android.intent.category.LAUNCHER" />
19
</intent-filter>
20
</activity-alias>
21
22
<activity-alias
23
android:enabled="false"
24
android:name=".MainActivity-Original"
25
android:label="@string/app_name"
26
android:icon="@drawable/ic_launcher_original"
27
android:targetActivity=".MainActivity">
28
<intent-filter>
29
<action android:name="android.intent.action.MAIN" />
30
<category android:name="android.intent.category.LAUNCHER" />
31
</intent-filter>
32
</activity-alias>
33
34
...
As you can see, the <activity-alias>'s point back to .MainActivity - which itself does not show up in launcher, as it does not have the launcher category set. .MainActivity-SuperAndy is the one shown by default, it's the only with android:enabled set to true.
CAVEAT: If you duplicate this, make sure that your default alias - the only alias which is enabled in the XML - is also the first <activity-alias> listed. I'm not sure what exactly the cause is, but I've had issues with no icon showing up at all on some Android versions if the enabled alias was not also the first one.
CAVEAT: (Eclipse) If you try to run the app now, it is likely that Eclipse/ADT/whatever-is-responsible will not be able to deduce how to launch your app, so it will just install your app, instead of launching it. To work around this, go to your project's properties, Run/Debug Settings, Edit your launch configuration, and select your main activity to launch manually.
The Java Code
Here's a slightly modified excerpt of the code in SuperSU to actually change the icon:
Code
#