I’ve been playing with Nexus 7 for few days now. I know it’s one of the strange devices with tvdpi sporting 216ppi. However, I didn’t feel anything different as such. While trying to solve the fuzzy refresh icon problem, I found quite a lot of problems.
Basically Nexus 7 has a scaling factor of 1.33 (or is it 1.34?). Let’s take an image of size 50×50 px in mdpi scale. The same image will be of size 75×75 px for hdpi devices. Nexus 7 uses scales down this image to 67x67px. This would seem to look good if the image is flat with no shadows. However, Firefox for Android uses images with shadows to give an embossed feel over the textured background. A 2dp shadow is scaled to 3px on tvdpi, while a 4dp shadow is scaled to 5px. Basically a scale of 1.33 cannot yield a whole number like a scale of 1.5 (for any even number). And hence the rounded off scaled value can either be ceil or floor, causing the above visual artifacts.
So, isn’t there any solution? Not exactly! Like I mentioned, it’s hard to believe there is a problem with the scaling unless one watches it closely. If you compare the Nexus 4 and Nexus 7 side by side, the fuzziness is instantly noticeable all over the OS. The way default Android apps mitigate this is with the Holo theme. Since, in Holo theme all the icons are flat, with no shadows and gradients, the fuzziness is not that blatant. Does this enforce every app to follow Holo theme? That’s a big discussion in itself. However, that seems to mitigate the problem.
Is this the only problem? Unfortunately, no! Canvas uses a lot of float calculations. With the device having a scaling factor of 1.33, the chances of getting a whole number on float multiplications is very less. For example, there is a white line to the right of refresh button in the above image. In Firefox for Android, we use a cubic bezier path to create those curves. The width of the curve is 1.125 times the height of the view. Since the curve is in the ActionBar, the height is 48dp on portrait, 40dp on landscape and 56dp on tablets. Hence the width of the curve will be 45dp, 54dp and 63dp respectively. Except for a HDPI tablet, these always yield whole numbers. On a HDPI tablet, the value defaults to its ceil value. However on Nexus 7, the width will be 74 * 1.125 = 83.25. (Note: 74 is the Android’s approximation of 56 at 1.33 scale). Using this float directly to set control points at 75% and 25% will result in floating values with 4 decimal places. This would make Android to round off the number to it’s floor value, leading to 1px difference than the intended value.
Hence, a scale like 1.33 is not helpful for the app developers in any ways! If Angry Birds is fuzzy on your Nexus 7, now you why!