Icon Packs
Kvaesitso has built-in support for the ADW launcher icon pack format (the format that is nowadays used by virtually all icon packs and supported by all major custom launchers).
Get started
AndroidManifest.xml
In order to be recognized as an icon pack, your app must declare an activity with at least one of the following intent filters in your AndroidManifest.xml
:
<activity android:name="[...]" android:exported="true">
<intent-filter>
<action android:name="org.adw.ActivityStarter.THEMES" />
</intent-filter>
<intent-filter>
<action android:name="com.novalauncher.THEME" />
</intent-filter>
<intent-filter>
<!-- Themed icons; only add this if your icon pack supports themed icons -->
<action android:name="app.lawnchair.icons.THEMED_ICON" />
</intent-filter>
</activity>
appfilter.xml
Icons are mapped to apps using a file called appfilter.xml
. This file must be located in one of these locations:
res/xml/appfilter.xml
(recommended)res/raw/appfilter.xml
assets/appfilter.xml
The file has the following structure:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- icons are added here -->
</resources>
drawable.xml
drawable.xml
is a file that lists all icons that are included in the icon pack. This file is required for manual icon picking. The file lives in res/xml/drawable.xml
, and looks like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item drawable="messages" />
<category title="System" />
<item drawable="settings" />
<item drawable="settings_alt_1" />
</resources>
Every icon that should be available for manual icon picking must be listed in this file. You can optionally group icons by adding <category>
elements, but these categories aren't used by Kvaesitso.
Static icons
Icons are added to the appfilter.xml
file using the <item>
tag:
<item component="ComponentInfo{com.android.deskclock/com.android.deskclock.DeskClockTabActivity}"
drawable="clock" />
component
is the component name of the target activity. The short form is also supported if the class' package name starts with the app's package name:ComponentInfo{com.android.deskclock/.DeskClockTabActivity}
drawable
is the name of the icon drawable which must be located in theres/drawable/
folder (or any of its variants, e.g.res/drawable-hdpi/
)
Autogenerated icons
The launcher can generate fallback icons for apps that don't have an icon in the icon pack. Fallback icons consist of four parts:
<resources>
<scale factor="1.0" />
<iconback img="iconback" />
<iconupon img="iconupon" />
<iconmask img="iconmask" />
</resources>
scale
: the original icon is scaled by thisfactor
iconback
: this is drawn behind the original iconiconupon
: this is drawn on top of the original iconiconmask
: this is used to mask the original icon
You can provide multiple variants of each part by adding a number to the img
attribute:
<iconback img1="iconback" img2="iconback2" />
The launcher will then randomly pick one of the variants for each icon.
Dynamic icons
Calendar icons
Kvaesitso supports Nova launcher's dynamic calendar icon standard:
To your appfilter.xml
file, add the following:
<calendar component="ComponentInfo{com.google.android.calendar/com.android.calendar.LaunchActivity}"
prefix="calendar_" />
prefix
is the prefix of the icon drawables. You need to provide one drawable for each day of the month (calendar_1
, calendar_2
, etc. up to calendar_31
).
NOTE
Single digit days must not be zero-padded (e.g. calendar_1
is correct but calendar_01
is not). Make sure that all 31 drawables are present, or the launcher will reject the icon.
Clock icons
Dynamic clock icons are supported as well but they work a bit differently than calendar icons. A dynamic clock icon needs at least two entries in your appfilter.xml
file:
<resources>
<item
component="ComponentInfo{com.google.android.deskclock/com.android.deskclock.DeskClockTabActivity}"
drawable="clock" />
<dynamic-clock defaultHour="10" defaultMinute="10" defaultSecond="30" drawable="clock"
hourLayerIndex="0" minuteLayerIndex="1" secondLayerIndex="2" />
</resources>
- The first entry is a normal icon entry.
- The second entry tells the launcher that that specific drawable is a dynamic clock icon. That way you can reuse the same clock icon config for multiple apps.
The icon itself must be either a LayerDrawable
, or an AdaptiveIconDrawable
with a LayerDrawable
as its foreground layer.
NOTE
Some launchers only support AdaptiveIconDrawable
s, so you should prefer that if possible.
The entry in the appfilter.xml
file tells the launcher which layer corresponds to which clock hand. If your icon does not have all three clock hands, you can omit the corresponding layer index attribute or set it to -1
.
Here is an example of a clock icon:
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/clock_background" />
<foreground>
<layer-list>
<item>
<rotate android:drawable="@drawable/clock_hour" android:fromDegrees="300.0"
android:pivotX="50.0%" android:pivotY="50.0%" android:toDegrees="5300.0" />
</item>
<item>
<rotate android:drawable="@drawable/clock_minute" android:fromDegrees="60.0"
android:pivotX="50.0%" android:pivotY="50.0%" android:toDegrees="60060.0" />
</item>
<item>
<rotate android:drawable="@drawable/clock_second" android:fromDegrees="180.0"
android:pivotX="50.0%" android:pivotY="50.0%" android:toDegrees="6180.0" />
</item>
<item android:drawable="@drawable/clock_top" />
</layer-list>
</foreground>
</adaptive-icon>
Pay attention to how each of the three clock hand layers is wrapped in a RotateDrawable
and how there are very specific values set for android:fromDegrees
and android:toDegrees
. This is required for launchers to be able to animate the clock hands. The values for android:fromDegrees
and android:toDegrees
must follow these rules:
- For the clock hour hand, the difference between
android:fromDegrees
andandroid:toDegrees
must be5000
. - For the clock minute hand, the difference between
android:fromDegrees
andandroid:toDegrees
must be60000
. - For the clock second hand, the difference between
android:fromDegrees
andandroid:toDegrees
must be6000
. - Each hand can have an offset from 0° to set the clock to a specific time (this is useful so that launchers that don't support dynamic clock icons don't display the icon as noon). In the example above, the hour hand is offset by 300°, the minute hand by 60° and the second hand by 180°. This means that the clock shows 10:10:30 in its default state.
- To let the launcher know which time the clock shows in its default state, you can use the
defaultHour
,defaultMinute
anddefaultSecond
attributes in theappfilter.xml
entry.
NOTE
defaultHour
, defaultMinute
and defaultSecond
are independent from each other. If you set defaultHour
to 10, then it is expected that the hour hand drawable is rotated by exactly 300°, regardless of the positions of the minute and second hands even if that means that the clock shows an impossible time.
INFO
Why these numbers?
Launchers use the android:level
attribute to animate the clock hands. A drawable's level is a number between 0 and 10000 that influences how the drawable is drawn. For RotateDrawable
s, the level attribute is used to set the rotation angle. Each level corresponds to 1/10000 of the angle between android:fromDegrees
and android:toDegrees
.
For the second hand, it is expected that 10 levels are equal to 1 second. which means that 600 levels correspond to a full rotation. But since a drawable has 10000 levels, the total angle must be 360/600 * 10000 = 6000
degrees.
For the minute layer, one level is equal to one minute so 60 levels are equal to a full rotation. This means that the total angle must be 360/60 * 10000 = 60000
degrees.
For the hour layer, one level is also equal to one minute, so there are 12 * 60 = 720
levels in a full rotation. 360/720 * 10000 = 5000
degrees.
Technically, you could also use other kinds of drawables that support the android:level
attribute (such as a LevelListDrawable
), as long as you follow the rules above.
Themed icons
Themed icons are monochrome icons that are tinted to match the theme color of the launcher.
To declare that your icon pack supports themed icons, add the following intent filter to your AndroidManifest.xml
:
<intent-filter>
<action android:name="app.lawnchair.icons.THEMED_ICON" />
</intent-filter>
The launcher will then show a toggle in the icon pack picker which allows the user to enable themed icons.
Themed icons can be provided in any of the following ways:
- If the icon is an adaptive icon, and the drawable has a
<monochrome>
layer, this icon will be used as the themed icon. - If the icon is an adaptive icon, and it does not have a
<monochrome>
layer, the foreground layer will be used. - If the icon is not an adaptive icon, the entire icon will be used.
In any case, the icon will be tinted using the theme color and the background will be set to a solid color.