RFO-BASIC / Basic

The Repository for the files the Basic project that creates the BASIC! APK for Google Play
62 stars 42 forks source link

Screen density and system uptime #42

Closed jMarcS closed 11 years ago

jMarcS commented 11 years ago

Forum user lupoman asked about getting the screen density: http://rfobasic.freeforums.org/how-to-query-for-display-dpi-t1240.html

I replied:

Hi Luis. Good idea. BASIC! doesn't have a command like this now. Android is funny about density, but we ought to be able to come up with something.

As far as I know, BASIC! does everything in absolute pixels, not Android's "density pixels". We'd probably want to translate Android's getDisplayMetrics().density(), which is a scale factor relative to density pixels, to an absolute resolution in dpi.

Rather than opening another issue I will add here that another post somewhere mentioned system uptime. I don't think it was a feature request, but I think it's a reasonable thing for BASIC! to provide. A minor variation would be the time since BASIC! started running. Maybe have "time, time.up, time.running" commands.

These items get me wondering if there is other system info that would be useful.

RFO-BASIC commented 11 years ago

The clock() function provides system uptime. VERSION$() returns the BASIC! version number Device Returns information about this Android device in the string variable. The information is the device Model, Device Type and OS.

jMarcS commented 11 years ago

I think the right way to provide display density is to add an optional parameter or two to GR.SCREEN. But is it one or two? The Android designers funny about density; they don't want to nail it down precisely. So DisplayMetrics.density is not a density at all, but a scale factor, relative to the nominal 160 dpi "density-independent pixel". So there are (at least) two approaches:

  1. Google/Android-like approximation: add one optional parameter, dpi, to GR.SCREEN, and assign it the value "DisplayMetrics.density x 160". (Or just use DisplayMetrics.densityDpi, which is the same thing.)
  2. Try to be precise and accurate: add two optional parameters, wdpi and hdpi, the width-density and height-density that give actual density numbers in each dimension.

I like precise, so I tried an implementation with two optional parameters. For values, I took DisplayMetrics.ydpi and DisplayMetrics.xdpi. These are supposed to be the exact, physical densities.

The trouble is, they're not. I tried it on two devices, a Xoom Jellybean tablet and a Samsung SGH-679 Gingerbread phone. It got the tablet right and the phone way wrong. Xoom: nominally 1280x800, 150 dpi; DisplayMetrics reported 1280x752, Density 1.0, and both xdpi and ydpi a little less than 150 (and slightly different from each other). The approximation approach would return 160. SGH-679: nominally 480x800, 240 dpi; DisplayMetrics reported 480x800, Density 1.5 -- so far so good. But it gave xdpi and ydpi as numbers near 160. Furthermore, when the orientation changed, width and height values swapped places, but the xdpi and ydpi numbers did not.

So maybe I'm interpreting xdpi and ydpi wrong -- in spite of what they documentation says, maybe they are really the actual dpi adjusted by the the density scale factor. That is, they could be the exact physical dpi expressed in "density-independent pixels". It looks like what I expected on the tablet because the density is 1.0. If that's the case, then the difference between xdpi (or ydpi) and densityDpi would give you the amount the physical screen differs from the convenient approximation. That's useful. Although it doesn't explain why xdpi and ydpi don't swap when orientation changes. Maybe Google just doesn't expect anyone to use them?

On a related note: GR.java currently gets screen width and height from getDefaultDisplay().getWidth() and .getHeight() in older devices, but those were deprecated in API 13, so it gets the drawView width and height in later levels. Is there some reason we can't use getDefaultDisplay().getMetrics().widthPixels and .heightPixels for all API levels?

RFO-BASIC commented 11 years ago

"they don't want to nail it down precisely"

They probably have their reasons as you are finding out. Tens of thousands of applications have been created with an OS that does not precisely nail this stuff done. Why do we need to?

If you look closely at the code in GR.java, it uses getDefaultDisplay().get.. for all levels of OS. The code at lines at 137 and 451 sees to that. The reason is that drawView.get.... did not work.

If testing shows that .getMetrics()....Pixels works at all level of the OS and provides some additional functionality (such are reliable reporting and/or easier to read code) then there is no reason not to use it.

BTW: It would appear that lines 142, 143, 456, 457 are rather pointless (NPI) and should be removed.

jMarcS commented 11 years ago

If you look closely at the code in GR.java

Oops. Sometimes I am like an NBA official: I see what I think is going to be there, not what is really there. But at least now I know what, "// Until the problem can be fixed" means. :{)}

I agree - everyone seems to agree -- there is no value knowing in the actual, physical pixel size. I'm still not sure about dividing the whole world into only three densities (or four in API 9 or five in API 13). If you want to display a thing "actual size", you need a closer approximation - for the Xoom, "about 150" would be okay, but "about 160" is off by 6.7%. For the vast majority of apps, that really doesn't matter. 1) Do we want to support the few for which it does? 2) Can we?

So, this is me getting real. We add an optional dpi or density parameter to GR.SCREEN, with a clear explanation that it returns one of Android's standardized constants. If somebody asks, or if we feel like it some day, we can always add another optional parameter for the closer approximation.


As for DisplayMetrics.widthPixels and .heightPixels, there is only one certain advantage: they're not deprecated. getWidth() and getHeight() could go away -- doesn't seem likely, and I don't understand why they're deprecated, but they are and they could. But you've nailed the problem: testing all levels of the OS and lots of devices.

The next best thing would be to research the Android community -- surely somebody somewhere has talked about this. Just gotta do my homework. Maybe next year.

Meanwhile, if it ain't broke...