Android: PDF created using PrintedPdfDocument looks different on different devices - android

I am trying to render a view to a PrintedPdfDocument. The size of the page, as expected, is in units 1/72nd of an inch. So, for an A0 size page (width = 33.11 in), document.getPageWidth() returns 2384 (33.11 * 72). The page canvas width equates one pixel to one 1/72nd of an inch unit - so, pageCanvas.getWidth() returns 2384. This is true on different devices. So far so good.
The problem I am facing is that on different devices, the generated PDF document for the same view looks different. On some devices it is stretched on the PDF page, and on somes devices it renders as it should.
What could be the issue here? Isn't the generation of the PDF supposed to be device independent? I noticed that pageCanvas.getDensity() is different on different phones. Why does the phone screen density impact the density of the PDF page canvas?
Given that the numerically document.getPageWidth() in 1/72nd of an inch == pageCanvas.getWidth() in pixels, shouldn't pageCanvas.getDensity() always be 72 DPI? On some phones it is 320 (where it shows correctly) and on others it is 420 (where the view is rendered stretched).
A bit stuck here, so would really appreciate any pointers. Thanks in advance!

I found a way to work around this problem.
I still don't know why pageCanvas.getDensity() is set to the display density instead of the density of the PDF Page (72dpi). My guess is that it may be because some views may incorrectly use display metrics of the screen when drawing to a canvas, even when the canvas is not the screen - but this is just my guess.
Regardless of why pageCanvas.getDensity() is set to screen density, the way I worked around it was by computing the page dimensions (which is in dp) using the screen density. So, if I want to draw to an A0 page (which is 33.11 inches wide), I set the width of the page (when creating the PrintedPdfDocument) to 33.11 * 420 = 13906 dp, instead of the recommended 33.11 * 72 = 2384 dp. This way, when the views draw to the canvas that has 420 dpi density, the resultant page is the required 33.11 inches wide.
This is working perfectly and the created PDF page now looks the same regardless of the device where it was created. The only side effect is that Adobe Acrobat thinks the pages are 33.11 * 420 / 72 inches wide instead of 33.11 inches wide. But this doesn't really matter practically, since we can shrink the pages to fit an A0 paper while printing.

Related

How do I translate the sizings of a Lenovo Tab M8 into pixels for Figma?

My company has a Android app. Our clients view the app with a Lenovo Tab M8. I am a designer tasked with recreating the current app experience in Figma so that our design team can have a design system and make accurate mockups. But I'm struggling to capture basic measurements (my experience is in Web and not Native apps).
The first question is, what is the width and length of the screen in pixels? I'm trying to create a basic screen template in Figma. I know the Lenovo display is 1280x800px with 16:10 screen ratio. But when I create a 1280x800 frame in Figma it's significantly larger than the physical device. I'm a little lost.
The other question is, I'm trying to recreate font sizes but I know the app uses dp and not px. I found a site that convert them, but I don't know if the tablet is LDPI, MDPI, or whatever.
https://www.pixplicity.com/dp-px-converter
Thanks for any insights you have.
You shouldn't need to know what density the tablet is, the point of using dp (density-independent pixels) is that everything will look pretty much the same size in the real world. The baseline density is LDPI, which is 160 pixels per inch - so 160dp is one inch on the screen.
XHDPI is 320 pixels per inch, so double the density - but converting 160dp to pixels on XHDPI devices involves multiplying it by 2, so the result is 320 pixels - which again corresponds to 1 inch on a 320dpi screen. See how it works?
So the pixel resolution isn't important, a tablet will be large in dp terms because they're physically bigger than a phone, more inches and all that. But if you're curious, if your M8 is the 2nd-gen one, according to the tech specs it's 4.8" on the 800 px axis (the one with the smallest bezels), and that works out to 166.7 DPI without taking those bezels into account - so it's an LDPI device!
I don't know anything about Figma, but so long as you're using dp measurements it should work ok? You have to be aware of the size of your screen though - when you said you created a frame 800 high and it was too big, if that was 800dp then 800 / 160 is 5" and your screen is only 4.8" high. Ideally your layout shouldn't require a specific physical size though, it should be able to adjust since different devices (even very similar ones) are different sizes - but I don't know how Figma works with that! That's just the way it works for the standard Android stuff
Also ideally fonts should use sp which is like dp but it has an additional scaling step depending on the user's font size settings on the device - it lets them shrink or enlarge text to their preference and for accessibility (the latter is especially important). Sometimes you want a fixed size for something that's more of a graphic element, but generally text should be scalable
If you want to know how to convert, have a look at the Material Type System - there's a chart there for converting between different units (also 1sp = 1dp for the Normal text size FYI). There's also a tool on there to create a type scale but only for stuff on Google Fonts - just saves you doing it yourself!

How to test android app on all screen sizes

I've created my app but I decided to test it on all screens to be adaptive. Maybe testing it in
MDPI(160dpi), HDPI(240dpi), XHDPI(320dpi), XXHDPI(480dpi) and XXXHDPI(640dpi) which corresponds to all screen sizes. However I tested my app on two devices support 320dpi. I thought that I get the same result but it don't. so don't know how to test my app on all screens. I'm confused.
I used Genymotion for emulators:
one with 720 * 1280 320dpi
screenshot
and other with 1200 * 1920 320dpiscreenshot
Please help me with that or if there's another way to do it let me know.
thanks in advance
(Bunch of explanation about why this is happening, I put my suggestions in the last section)
DPI isn't the same as size, it's just about how many pixels are packed into a certain area. The higher the DPI, the more pixels there are, meaning they're a lot smaller. So you can get fine detail, but it also means you need more of them to cover a physical distance or area on the screen.
Which is why Android uses dp instead of raw pixel sizes most of the time - the standard minimum touch-target size is 48dp, but how many actual pixels that is depends on the pixel density of the display. For mdpi displays it'll actually be 48 pixels, for xxxhdpi it'll be 4x that amount
It also means if you're doing your design work in dp, the pixel density of the screen doesn't matter - elements with a fixed size will always be broadly the same size on every screen (the mdpi etc buckets are like a "close enough" grouping, the devices in each group won't all have exactly the same DPI) because it's getting translated to the equivalent number of actual pixels. What testing does help with is checking your drawable assets look ok on different screen densities
So you have two devices with the same DPI right?
720 x 1280
1200 x 1920
Because they're the same DPI, those dimensions are converted to dp by the same factor. Let's work it out to be precise (but the exact numbers aren't important): 320 DPI is xhdpi according to that link up there, so 1dp = 2px. Let's convert those screen sizes to dp
360dp x 640dp
600dp x 960dp
It's the same situation but hopefully having those sizes expressed in dp helps you see the problem - when you're designing a layout, you're working with dp, right? The available space you have to work with is defined in dp, and one of those has a whole lot more space than the other! Putting a 300 dp-wide TextView in the layout would almost fill the first one horizontally, but it would only cover half of the second. That's gonna look pretty different!
This is why phones and tablets look so different - even if you have a relatively new phone, and an old Nexus 7 with a much lower resolution, the Nexus 7's screen is going to feel "bigger" and more "spacious". It's a physically larger device, so even though it's low-res, it's also low-density which means those pixels are spread across a larger area. Lower DPI means those pixels translate into more inches. And in the density-independent pixel (dp) system, that means you get way more dp to work with, more space for your layout. Which is what you want on a tablet, you don't want it to look and feel like a massive phone!
That's why it's different - basically one of your devices has more space to work with than the other, because it has more pixels, and the same DPI so those pixels aren't just used for finer detail.
As for testing, you need to look at different screen sizes - which is dependent on the resolution and the DPI. Basically pixels / DPI = size in inches. Do that for your two 320 DPI examples and you'll see one is a fair bit larger, physically, while having the same density
Probably the easiest way to do this, really, is to look at your layout in the design view, and change the Preview Device setting at the top. Some of the Phone devices are more "spacious" than others, newer ones are taller, so go through them and see how your layout changes. Try a Tablet one and see what a lot of extra space does. And if you go down to the Generic Phones and Tablets section at the bottom, there are a bunch of reference devices in there, some of which will be very cramped!
Once you've found a few useful ones, you can set up your emulator / virtual devices with each of their screen resolution / density combinations. I don't know about Genymotion, but the built-in AVD manager gives you a lot of those device definitions as templates when you create a new virtual device. You should at least be able to enter those settings yourself
Also when you publish an app on the Play Store, they'll automatically run it on a bunch of reference devices and give you access to a bunch of screenshots, so you can see if there are any problems with certain screen sizes and fix them before you launch

Android DPI independence on devices with same the resolution

I Have a few general questions about Android screen / DPI / resolution indepence.
Basically, I am taking specifically about sprite-based apps, like ones based on Surfaceview for example.
Every guide I've read (including the official one) says that you should only work with the DPI and not the resolution.
However, what happens when two devices have different DPI's/screen size but the same resolution? Take the Galaxy tab 10.1 (1280 x 800 - DPI aprox 150) and the Galaxy Note (1280 x 800 aprox 285 DPI I think??)
When displaying a sprite of say 50 x 50 on each of these, it will appear to be the same size relative to the screen size. However, if Android grabs a difference size sprite because it detects a different DPI (ie, from LDPI, HDPI etc), then the sprite will appear to be bigger on the Note relative to the screen size than it would on the Tab.
Can anyone please set me straight on this as I just cannot work it out!! Thanks all.
A 50 x 50 sprite on a 150dpi screen will appear much larger than a 50 x 50 sprite on a 285dpi screen. Android's resource resolution algorithm is intended to allow you to define a larger (in pixels) image for use on higher density screens.
If you want the sprite to be the same size relative to the screen regardless of the pixel density, then you can put the images in the drawable-nodpi folder and they won't be scaled by the system. You can even decide which size image to use in code after querying the screen size. (As of 3.2, you can have resource folders that depend on screen pixel size, but I think they will still scale with dpi.)
Screen resolution refers to the screen dimension in pixels. Pixel density refers to how many pixels it takes to fill an inch of screen.

Calculate pixels based on DPI and Physical Size

I'm trying to make an Evolus Pencil template for Android. My device has a 1.75x2.5625" screen, and I would like to emulate these exact physical dimensions. From reading this post:
Android multiple screen sizes with same density
I see Physical Size = Pixels / Density. So if I create an image that is 168px wide, on a 96dpi screen, should I not get a physical image of 168/96=1.75" wide?
Because I get one about 1.5" and I'm lost. I am running Ubuntu and confirmed my screen dpi with xdpyinfo as being 96x96. So what is a formula I can use for this? I was thinking one could get the pixels needed by multiplying the inches we want on the screen by the dpi of the screen, but this gives me the 168 mentioned above and obviously gets me no where.
Can anyone point me in the right direction, I'm honestly terrible with numbers and math so my apologies if I'm missing something simple or obvious.
Are you sure that the display is actually 96 ppi? Going by the specs, and my own calculations, your Lenovo S10e actually has a density of ~116.36 ppi, which is probably where your difference is coming in.
Assuming these specs are correct:
10.1" diagonal
1024 x 576 resolution
16:9 screen ratio (taken from above resolution)
Using some geometric formulas, you can get the actual width and height of the monitor as:
Width: 8.8"
Height: 4.95"
Dividing 1024/8.8 and 576/4.95 gives you 116.36 pixels per inch, rather than 96.
Using this instead, a 168 pixel image should display as 168/116.36, or ~1.44", which is consistent with your results. I wouldn't put too much faith in the xdpyinfo results. :)

How do I get around clipping issues with my app in smaller phones?

I have a basic linear layout, with image view that display photos, textviews that show text etc...and when I test my whole app on my android 2, there is never any part of the screen that doesn't show. But when I test it in the QVGA emulator, half the view is off the screen. Now, some of my text is defined to a certain size.
I never use px (only dip) in any of my xml. I use fill_parent, wrap_content where it is needed and never fix a height or length. Could it be with my text, I use say, textSize = 22dip? I couldn't find documentation on why that would not work in all sizes.
Could it be that some apps need to be programmed to those screen sizes? Or am I missing something?
Thanks!
DIP actually doesn't help in fluid layout design. DIP tries to make sure things will looks the same size across different screen density. (imagine the concept of Point in typography)
Without your code and/or screenshot of what happen, it is hard to judge what happens to your program, but 22dip text size is possibly one of the reason which:
22dip text in HDPI will become: 22 * 240 / 160 = 33 pixel
22dip text in LDPI will become: 22 * 120 / 160 = 16.5 pixel
If your setting on QVGA is HDPI, then it is actually 33 pixel tall for a letter, which consumes more than 1/10 of the screen height.
By the way, your 16:9 wide screen (vertical) may fit everything in one screen without scroll, while QVGA is only 3:2 screen, even though everything is in proportion, something would be hidden away for sure.

Categories

Resources