I am using the onCreateOptionsMenu method to create a toolbar with icons in the MainActivity of my app. I am testing on different screen sizes and pixel densities with Android Studio's emulator. The documentation states, "Based on the density of the current screen, the system uses any density-specific resources from your app. If resources are not available in the correct density, the system loads the default resources and scales them up or down as needed." I've tried putting all of my vector icons the default drawable directory, but the system does not scale them for different screen sizes or densities at all. Nor does onCreateOptionsMenu scale the height of the toolbar or the title text. Is it supposed to? Because of this, I have also tried using different density buckets to address that problem. However, I'm running into an issue with greatly varying screen sizes sharing the same density bucket.
As an example, I'm testing on Pixel 3 (5.5" phone) and Pixel C (10" tablet). They are using the same density bucket (xhdpi) so if I use a 24dp x 24dp icon for the phone, then it looks way too small on the tablet. How do I work around this?
You can string together multiple qualifiers and create a custom bucket. So in addition to the drawable-xhdpi bucket I added a drawable-sw720dp-xhdpi bucket with larger icons for the 10" tablet. Now tablet displays the slightly larger icons while the phone still uses the standard bucket. The solution can be found in the comments of the selected answer in this post by #Theo. Unfortunately the documentation does not state that multiple qualifiers are supported.
I am using the "Icon Pack Drawable Importer" plugin which I think is probably importing the icons from "https://design.google.com/icons". Each icon has many sizes (18dp, 24, 36, 48...) and for each size, there are multiple DPIs (mdpi ~ xxxhdpi) for it.
This is a little bit confusing, because as far as I know on Windows, you just define multiple resolutions of the same icon, and the system will automatically choose the closest resolution (best) version for the actual drawing size.
Suppose I want to display two arrows in two different sizes on the same device. Suppose I only added one arrow icon whose size is 48dp but has 5 different DPI versions in it. If I specified the final drawable size programmatically, does Android select the closest one? For example, mdpi version for the small arrow and the xxxhdpi version for the large arrow? Or does Android select one version that matches the system's DPI and resize and use it for the two arrows?
I want to let users choose the icon size for them (some may want big, some may want small), but adding multiple size versions of one icon which itself has DPI versions seems a little bit complex. So, I thought of adding the biggest size only (48dp version, but it has 5 DPI versions in it) and specifying smaller resolution programmatically if the user wants smaller icon, because upscaling would make an icon blurry but downscaling would not. Is that a bad idea, and should I add multiple sizes and multiple DPIs of the same icon to the resources?
If your screen is mdpi, all your drawables will be loaded first from res/drawable-mdpi directory, then, if the file is not found, from res/drawable directory. So if you resize 24x24 mdpi icon programmatically to 64x64 pixels, you will get degraded picture quality, Android will not load xxdpi icon for you instead.
If you set all your icon sizes in a programmatic way, simply select the highest-resolution icons and dump them all into res/drawable directory.
Icons in res/drawable-mdpi still has the advantage that they use less memory and don't need to be mipmapped, however modern phones can resize all graphics, with smoothing and mipmapping applied, in hardware.
As far as I know it is possible to provide multiple resource paths for multiple dpis (mdpi, hdpi etc.). What if I want to support multiple screen sizes at the same dpi?
For example, if I have an application that draws an icon whose size is always a percentage of the screen size (e. g. 25 %) and I replace the screen by a larger one with the same dpi, then the icon has to be scaled up. This will make the icon blurry unless I provide a version with a higher resolution. Since Android only distinguishes by dpi and not by screen size, how can I do this?
If the icon is included in the APK, you may as well just put just one copy - the highest resolution you have. Large icons can be scaled down just fine, it's scaling small icons up that causes the blurriness. The reason for including different sizes is to save bandwidth when icons are downloaded, but since all the copies would already be on the device, in effect all you will be doing is making the APK bigger. First prize would be to include a vector image (infinitely scalable, small size).
You should also note that the blurriness is really only in comparison with the sharpness of the rest of the display. In reality the 2x scaled-up icons would look just as good as the same icons on a display with a density half as much.
If, however, you still want to select a certain copy of an image based on the dpi and screen size, there are ways you can detect this in Android. See this SO question, for example.
Since Android 4.3 (Jelly Bean) we can now make use of the res/mipmap folders to store "mipmap" images.
For example, Chrome for Android stores its icons in these folders instead of the more normal res/drawable folders.
How are these mipmap images different from the other familiar drawable images?
I see that in my manifest, we use the #mipmap/ qualifier, instead of #drawable/, which makes sense given the resource folder name:
<activity
android:name=".MipmapDemp"
android:icon="#mipmap/ic_launcher" />
References:
The Android 4.3 APIs document has the following to say:
Using a mipmap as the source for your bitmap or drawable is a simple
way to provide a quality image and various image scales, which can be
particularly useful if you expect your image to be scaled during an
animation.
Android 4.2 (API level 17) added support for mipmaps in the Bitmap
class—Android swaps the mip images in your Bitmap when you've supplied
a mipmap source and have enabled setHasMipMap(). Now in Android 4.3,
you can enable mipmaps for a BitmapDrawable object as well, by
providing a mipmap asset and setting the android:mipMap attribute in a
bitmap resource file or by calling hasMipMap().
I don't see anything in there that helps me to understand.
XML Bitmap resources have an android:mipMap property:
Boolean. Enables or disables the mipmap hint. See setHasMipMap() for
more information. Default value is false.
This does not apply to launcher icons as far as I can see.
The question was raised on Google Groups (The purpose of resource name "mipmap"?!), to which Romain Guy replied:
It's useful to provide an image at a larger resolution that would
normally be computed (for instance, on an mdpi device, Launcher might
want the larger hdpi icon to display large app shortcuts.)
I feel like this almost makes sense of it, but not quite.
I'm still inclined to go with Randy Sugianto's follow up:
What are the advantages of this? Is there any guide how to use
mipmaps, probably for better launcher icons?
Of course, Wikipedia has a page for "Mipmap", which refers to an older technique invented in 1983, that I can't quite relate to the current Android implementation.
Should we be storing all our app icons in res/mipmap folders these days, and what are the guidelines for these mipmap images?
Update #1
Here's a blog post that tries to explain it a bit.
Mipmapping for drawables in Android 4.3
But the image used in that blog post shows what looks like one file with many logos in it. This is not what I see in Chrome's mipmap folder.
Chrome's mipmap-hdpi folder contains three images. One is the Chrome logo, on its own.
Strangely, it is 72x72, not 48x48 which I would expect to see.
Perhaps that is all there is to this - we just need to keep bigger icons in the mipmap folders?
Update #2
The Android Developers Blog post of 23/10/2014 again confirms the idea of using the mipmap folders for application icons:
Getting Your Apps Ready for Nexus 6 and Nexus 9
When talking about the Nexus 6 screen density, the author writes:
It’s best practice to place your app icons in mipmap- folders (not the
drawable- folders) because they are used at resolutions different from
the device’s current density. For example, an xxxhdpi app icon can be
used on the launcher for an xxhdpi device.
Update #3
Note that Android Studio creates the ic_launcher.png icons in the mipmap... folders rather than the drawable... folders that Eclipse used to create them in.
There are two distinct uses of mipmaps:
For launcher icons when building density specific APKs. Some developers build separate APKs for every density, to keep the APK size down. However some launchers (shipped with some devices, or available on the Play Store) use larger icon sizes than the standard 48dp. Launchers use getDrawableForDensity and scale down if needed, rather than up, so the icons are high quality. For example on an hdpi tablet the launcher might load the xhdpi icon. By placing your launcher icon in the mipmap-xhdpi directory, it will not be stripped the way a drawable-xhdpi directory is when building an APK for hdpi devices. If you're building a single APK for all devices, then this doesn't really matter as the launcher can access the drawable resources for the desired density.
The actual mipmap API from 4.3. I haven't used this and am not familiar with it. It's not used by the Android Open Source Project launchers and I'm not aware of any other launcher using.
It seems Google have updated their docs since all these answers, so hopefully this will help someone else in future :) Just came across this question myself, while creating a new (new new) project.
TL;DR: drawables may be stripped out as part of dp-specific resource optimisation. Mipmaps will not be stripped.
Different home screen launcher apps on different devices show app launcher icons at various resolutions. When app resource optimization techniques remove resources for unused screen densities, launcher icons can wind up looking fuzzy because the launcher app has to upscale a lower-resolution icon for display. To avoid these display issues, apps should use the mipmap/ resource folders for launcher icons. The Android system preserves these resources regardless of density stripping, and ensures that launcher apps can pick icons with the best resolution for display.
(from http://developer.android.com/tools/projects/index.html#mipmap)
How are these mipmap images different from the other familiar drawable images?
Here is my two cents in trying to explain the difference. There are two cases you deal with when working with images in Android:
You want to load an image for your device density and you are going to use it "as is", without changing its actual size. In this case you should work with drawables and Android will give you the best fitting image.
You want to load an image for your device density, but this image is going to be scaled up or down. For instance this is needed when you want to show a bigger launcher icon, or you have an animation, which increases image's size. In such cases, to ensure best image quality, you should put your image into mipmap folder. What Android will do is, it will try to pick up the image from a higher density bucket instead of scaling it up. This will increase sharpness (quality) of the image.
Thus, the rule of thumb to decide where to put your image into would be:
Launcher icons always go into mipmap folder.
Images, which are often scaled up (or extremely scaled down) and whose quality is critical for the app, go into mipmap folder as well.
All other images are usual drawables.
The Android implementation of mipmaps in 4.3 is exactly the technique from 1983 explained in the Wikipedia article :)
Each bitmap image of the mipmap set is a downsized duplicate of the
main texture, but at a certain reduced level of detail. Although the
main texture would still be used when the view is sufficient to render
it in full detail, the renderer will switch to a suitable mipmap image
(...) when the texture is viewed from a distance or at a small size.
Although this is described as a technique for 3D graphics (as it mentions "viewing from a distance"), it applies just as well to 2D (translated as "drawn is a smaller space", i.e. "downscaled").
For a concrete Android example, imagine you have a View with a certain background drawable (in particular, a BitmapDrawable). You now use an animation to scale it to 0.15 of its original size. Normally, this would require downscaling the background bitmap for each frame. This "extreme" downscaling, however, may produce visual artifacts.
You can, however, provide a mipmap, which means that the image is already pre-rendered for a few specific scales (let's say 1.0, 0.5, and 0.25). Whenever the animation "crosses" the 0.5 threshold, instead of continuing to downscale the original, 1.0-sized image, it will switch to the 0.5 image and downscale it, which should provide a better result. And so forth as the animation continues.
This is a bit theoretical, since it's actually done by the renderer. According to the source of the Bitmap class, it's just a hint, and the renderer may or may not honor it.
/**
* Set a hint for the renderer responsible for drawing this bitmap
* indicating that it should attempt to use mipmaps when this bitmap
* is drawn scaled down.
*
* If you know that you are going to draw this bitmap at less than
* 50% of its original size, you may be able to obtain a higher
* quality by turning this property on.
*
* Note that if the renderer respects this hint it might have to
* allocate extra memory to hold the mipmap levels for this bitmap.
*
* This property is only a suggestion that can be ignored by the
* renderer. It is not guaranteed to have any effect.
*
* #param hasMipMap indicates whether the renderer should attempt
* to use mipmaps
*
* #see #hasMipMap()
*/
public final void setHasMipMap(boolean hasMipMap) {
nativeSetHasMipMap(mNativeBitmap, hasMipMap);
}
I'm not quite sure why this would be especially suitable for application icons, though. Although Android on tablets, as well as some launchers (e.g. GEL), request an icon "one density higher" to show it bigger, this is supposed to be done using the regular mechanism (i.e. drawable-xxxhdpi, &c).
One thing I mentioned in another thread that is worth pointing out -- if you are building different versions of your app for different densities, you should know about the "mipmap" resource directory. This is exactly like "drawable" resources, except it does not participate in density stripping when creating the different apk targets.
https://plus.google.com/105051985738280261832/posts/QTA9McYan1L
Since I was looking for an clarifying answer to this to determine the right type for notification icons, I'd like to add this clear statement to the topic. It's from http://developer.android.com/tools/help/image-asset-studio.html#saving
Note: Launcher icon files reside in a different location from that of
other icons. They are located in the mipmap/ folder. All other icon
files reside in the drawable/ folder of your project.
There are two cases you deal with when working with images in Android:
You want to load an image for your device density and you are going to use it “as is”, without changing its actual size. In this case you
should work with drawables and Android will give you the best fitting
image.
You want to load an image for your device density, but this image is going to be scaled up or down. For instance this is needed when you
want to show a bigger launcher icon, or you have an animation, which
increases image’s size. In such cases, to ensure best image quality,
you should put your image into mipmap folder. What Android will do is,
it will try to pick up the image from a higher density bucket instead
of scaling it up.
SO
Thus, the rule of thumb to decide where to put your image into would
be:
Launcher icons always go into mipmap folder.
Images, which are often scaled up (or extremely scaled down) and whose quality is critical for the app, go into mipmap folder as
well.
All other images are usual drawables.
Citation from this article.
When building separate apks for different densities, drawable folders for other densities get stripped. This will make the icons appear blurry in devices that use launcher icons of higher density.
Since, mipmap folders do not get stripped, it’s always best to use them for including the launcher icons.
When we build separate APKs for different densities, for the APK of the particular density, the drawable folders for other densities get stripped. This will make the icons appear blurry on devices that use launcher icons of higher density. Since mipmap folders do not get stripped, it's always best to use them for including the launcher icons.
res/
mipmap-mdpi/ic_launcher.png (48x48 pixels)
mipmap-hdpi/ic_launcher.png (72x72)
mipmap-xhdpi/ic_launcher.png (96x96)
mipmap-xxhdpi/ic_launcher.png (144x144)
mipmap-xxxhdpi/ic_launcher.png (192x192)
MipMap for app icon for launcher
http://android-developers.blogspot.co.uk/2014/10/getting-your-apps-ready-for-nexus-6-and.html
https://androidbycode.wordpress.com/2015/02/14/goodbye-launcher-drawables-hello-mipmaps/
If you build an APK for a target screen resolution like HDPI, the Android asset packageing tool,AAPT,can strip out the drawables for other resolution you don’t need.But if it’s in the mipmap folder,then these assets will stay in the APK, regardless of the target resolution.
The understanding I have about mipmap is more or less like this:
When an image needs to be drawn, given we have different screen sizes are resolutions, some scaling will have to take part.
If you have an image that is ok for a low end cell phone, when you scale it to the size of a 10" tablet you have to "invent" pixels that don't actually exist. This is done with some interpolation algorithm. The more amount of pixels that have to be invented, the longer the process takes and quality starts to fail. Best quality is obtained with more complex algorithms that take longer (average of surrounding pixles vs copy the nearest pixel for example).
To reduce the number of pixels that have to be invented, with mipmap you provide different sizes/rsolutions of the same image, and the system will choose the nearest image to the resolution that has to be rendered and do the scaling from there. This should reduce the number of invented pixels saving resources to be used in calculating these pixels to provide a good quality image.
I read about this in an article explaining a performance problem in libgdx when scaling images:
http://www.badlogicgames.com/wordpress/?p=1403
i just released my app on android and have problems with customers with high density displays.
i added a debug thing to see what's going in, here is one sample output
Device: Nexus 10 Android version: 4.2.2
DisplayMetrics{density=2.0, width=2560, height=1504, scaledDensity=2.0, xdpi=298.275, ydpi=298.823}
MainView w=1900 h=1342
mDrumKitMode=BIG
KitView w=640 h=1266 x=1920.0 y=0.0
the main view is the music notation area on the left of the screen shot, its 1900 wide (MainView w=1900 h=1342) the drum kit is a bitmap that is 640w and 640 high. somehow, the display is scaling it to be full height of the parent, (KitView w=640 h=1266 x=1920.0 y=0.0). this doesn't happen on displays where density=1.0.
i have no way to test this since i can't get the emulator work on big displays for some reason and i don't have a high density tablet.
does anyone have an idea what could be going on? thanks
and here's another customer with a similar problem
Device: A700 Android version: 4.1.1
DisplayMetrics{density=1.5, width=1920, height=1128, scaledDensity=1.5, xdpi=224.73732, ydpi=224.11765}
MainView w=1260 h=1044
mDrumKitMode=BIG
KitView w=640 h=968 x=1280.0 y=0.0
i think its the scaledDensity=1.5 parameter, maybe i need to do something to disable automatic image scaling, i.e. set scaledDensity=1?
i should add that the entire application is based on exact pixel positions, both for the music notation display and the drum kit display which overlays images on top of the base drum kit image (you can see the drum pedals are in the wrong place on this image too). i don't want automatic scaling as i handle scaling inside the app for different display sizes and user preferences.
i should also add that all my drum kit images are in drawable-mdpi and all the other dpis are empty. this is because i scale images programmatically based on screen size and user preference BUT i think maybe the problem is a need to put some images in xhdpi? i guess i can do that but it will be a lot of work.
PS, i guess i found my answer here http://developer.android.com/guide/practices/screens_support.html
Provide different bitmap drawables for different screen densities
By default, Android scales your bitmap drawables (.png, .jpg, and .gif files) and Nine-Patch drawables (.9.png files) so that they render at the appropriate physical size on each device. For example, if your application provides bitmap drawables only for the baseline, medium screen density (mdpi), then the system scales them up when on a high-density screen, and scales them down when on a low-density screen. This scaling can cause artifacts in the bitmaps. To ensure your bitmaps look their best, you should include alternative versions at different resolutions for different screen densities.
i wonder if simply copying all the -mdpi images to -xhdpi will work?
If you intend for this app to be used across devices you have no choice but to put in images for all the various density folders that exist (xhdpi,xxhdpi, hdpi, mdpi). It's also worth considering that you may want to change the actual layouts you include, to offer different ones for different devices.
Consult the documentation for how to handle this.
http://developer.android.com/guide/practices/screens_support.html
If that creates an apk that's too heavy (I have no idea how many images you have) then you can go the other way and specify a no scaling drawable folder which will just use the images in their native density across devices. It's definitely wrong to use ONLY mdpi unless you intend to support only mdpi devices.