Resource folder selection not working as expected - android

I've a large image logo I'm currently scaling (usually down) to fill 50% of screen. At first I placed it in the base /res/drawable folder. It worked fine for most devices, but on some low-end phones with small screens the scaling introduced aliasing and it looks horrible. So I distributed the images as follows:
/res/drawable
-Large image, intended to be used on most devices
/res/drawable-normal
-Smaller image, intended to target smaller screens
However, when testing on Samsung Galaxy Tab 2 10' it picks the image in normal folder instead of the image in the base drawable folder. I know this tablet fits in the drawable-xlarge category since it is picking other resources from there. So I had to come up with this directory structure for the thing to work:
/res/drawable
-Large image, intended to be used on most devices
/res/drawable-normal
-Smaller image, intended to target smaller screens
/res/drawable-xlarge
-Same image as the drawable base folder, only used for the tablet to select the correct image.
Now it works as I want, but I can't understand why the system selects the normal folder for an xlarge device. Shouldn't it look first in the xlarge folder and then fallback on the base drawable folder?
Thanks in advance.

It falls back in a scaleable manner.
If it can't find Xlarge, then large is a closer match then normal is a closer match then the default folder
Reference:
How Android finds best matching resources
Android.Developer

Related

Do I need to use all of drawable, drawable-mdpi, drawable-hdpi, drawable-xhdpi, drawable-xxhdpi & drawable-xxxhdpi?

I realise that Android will try it's best if it does not find an icon in the required folder but I see someplaces they suggest all of the above and in others they don't include drawable ?
So should I populate drawable as well if all the others are filled with my tab icon images?
If you use a VectorDrawable, you don't need to add a Resource for every density (mdpi, xhdpi etc). VectorDrawable is supported since API 21 (Lollipop) or with Support Library (or AndroidX).
For simple types of images (usually icons), you can avoid creating separate images for each density by using vector graphics. Because vector graphics define the illustration with geometric line paths instead of pixels, they can be drawn at any size without scaling artifacts.
For images (PNG) on the other hand, you must add proper icons for every density because Android will try to scale the images (so they can proportionally occupy same area in all devices). When scaling, the image may become blurred reducing the quality of your UI.
To provide good graphical qualities on devices with different pixel densities, you should provide multiple versions of each bitmap in your app—one for each density bucket, at a corresponding resolution. Otherwise, Android must scale your bitmap so it occupies the same visible space on each screen, resulting in scaling artifacts such as blurring.
You can read more HERE and HERE
EDIT
Maybe, you don't need to duplicate ALL icons. A lot of factors can lead to different experiences such as using wrap_content or a specific dimension to control the icon size or even using a different scaleType in your ImageView. So, maybe, you can start by adding icons for xhdpi or xxhdpi folders only and check your screen in different screen (small display, large displays, low-resolution displays, high-resolution displays etc). Then, you can "duplicate" only the necessary icons... But if your project or APK size is relatively small, don't mind to duplicate the icons.
There's even some online tools to generate the assets for every density from a single PNG such Android Asset Studio website..
If you are adding all resolution drawable icon like :
drawable-mdpi
drawable-hdpi
drawable-xhdpi
drawable-xxhdpi
drawable-xxxdpi
then you need not to add any extra icons on drawable folder
because all the device resolution covers under the above drawable folders

Mipmap drawables for icons

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

Android, my app looks good on vertical screens, but size is all distorted on tablets (wide screen)

When my android app gets drawn on a tablet or a emulator that has a wide screen (wasvga,wxcage800 and my tablet) it draws the graphic images from the drawblw-ldpi folder (low res) instead of the drawl-hdpi folder. I'm curtly using a bitmap button. They are all very small (since the smallest image is being drawn) on the tables, but the correct image gets drawn on all the vertical screens.
Why is this????
Is there a way to fix it????
The default folder is the mdpi folder. If another folder doesn't exist, or doesn't have your image, android gets it from drawable-mdpi. Put your images there, and let us know if it works.

Use HDPI Resources on Kindle Fire

I'm currently looking into getting my android app to work on Kindle Fire. I've got artwork for both MDPI and HDPI screens, but I noticed that when I load the app up on the Kindle, it displays the MDPI artwork and stretches some of my artwork that I'm filling parent with a little more than I want.
I was wondering if there's any way on Android to under certain circumstances (like if I'm on a Kindle), force it to load from the HDPI artwork, instead of defaulting to MDPI.
I do realize that I could just save my HDPI artwork in the MDPI folder with a slightly different name and do a check for every resource, but that's a lot of overhead, not to mention an increase in the size of my app, which I'd also like to avoid.
Thanks
Update: Still looking at this one. I guess what I'm really getting at, is there a way for an android device to chose HDPI artwork instead of MDPI, even though the MDPI artwork exists?
The Kindle Fire is 1024x600 with 160 dpi, right?
You can try new resourses with that resolution. And place them in the MDPI folder.
Add layout-large at /res directory and copy your layout file there.
That way, with the Kindle Fire, you use the layout at layout-large pointing to bigger resources in the MDPI folder.
And make sure you always use nine-patch drawables for resources.
Hope this helps you.
Ended up using a hack solution in the meantime, but I came across this:
I don't want Android to resize my bitmap Automatically
Pretty much just needed to move my hdpi images into the nodpi folder (in order to avoid the scaling issues) and changed the names slightly (I added a _hd to the name). After that I made an image loader that takes in the name of the image I want and returns _hd images if device is hdpi or if it's kindle fire:
id = ctx.getResources().getIdentifier(string + "_hd", "drawable", context.getPackageName());
Note: The docs do discourage the use of getIdentifier(), as it is less efficient than just using the resource address, but I took a look at the load times and loading 1000 images with getIdentifier takes .25 seconds, which is fine with me especially since I'm not loading anywhere close to that many images.
You can try new resources with that resolution and place them in the MDPI folder. Add layout-large at /res directory and copy your layout file there. That way, with the Kindle Fire, you use the layout at layout-large pointing to bigger resources in the MDPI folder.

How can I alias an android bitmap to a drawable from another size (drawable-large-mdpi aliases to drawable-hdpi)

I'm working on adding support for tablet sized screens to my apps. I already have images in drawable-mdpi and drawable-hdpi for different density screens. My problem is with tablets like the Galaxy 7" which is a "large" screen but is still medium density. Part of my layout has 5 buttons across the width of the screen which are evenly spaced. On the large screen with mdpi graphics though the images are very small with tons of whitespace between them.
I would like to use larger graphics for the large layout to make them look appropriate as well as take advantage of the screen real estate. I have some double sized graphics in my hdpi directory that would work perfectly. As a test, I've copied all of the images from /res/drawable-hdpi into /res/drawable-large-mdpi and everything looked exactly as I want.
However, I don't want to bloat the size of my app by coping all of those images. I would like to just create aliases for each of them so that when /res/drawable-large-mdpi/button_0 is requested, it will actually use /res/drawable-hdpi/button_0 instead.
I've tried creating an xml bitmap but I don't know how to reference a drawable from a specific directory. Any help?
Contents of /res/drawable-large-mdpi/button_0.xml:
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable-hdpi/button_0" />
The error I get with the above is:
error: Error: No resource found that matches the given name (at 'src' with value '#drawable-hdpi/button_0_highlighted').
Move your button resource into the drawable-nodpi folder and rename it to button_0_hdpi.xml.
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/button_0" />
When using an XML alias you can not specify the qualifier. You had #drawable-hdpi and it needs to be just #drawable. You probably also need to make a second XML alias in the original location of you button bitmap.
Here is a good article on the method http://blog.evendanan.net/2011/03/Android-resources-and-device-fragmentation
this page talks about the different modifiers you can use on resource folders. It seems to indicate that the order of precedence is such that screen size(small, med, large, xlarge) is higher than density(ldpi, mdpi, hdpi). I would think that this means if you renamed your drawables-hdpi folder to drawables-large-hdpi even though the Galaxy tab has a medium density it will still use the drawables from this folder because it has a large screen.
Edit: I just tested this out, it does solve your problem one way. They images inside the drawables-large-hdpi folder to show up on the Galaxy tab when running the app. But unfortunately adding the large qualifier makes it so they don't show up on medium sized screens with hdpi densities. Its looking like you might have to make separate folders and have 2 copies of your large resources if you want to get this functionality =(.

Categories

Resources