Essentials: Brightness API

Created on 17 Jun 2018  路  20Comments  路  Source: xamarin/Essentials

Description of the Feature

Adjust the Screen Brightness of the Device. Useful for apps that require full screen brightness, for example when displaying a QR- or barcode.

API Declaration

Task SetBrightnessAsync(double brightnessLevel);

brightnessLevel
Brightness of the screen. Value should be in the range of 0.0 and 1.0, where 1.0 is for 100% brightness.

Documentation links for supported platforms

VS bug #735667

feature-request needs-more-discussion proposal

Most helpful comment

Okay I have a working implementation for iOS, Android and UWP. The problem I see is restoring the brightness to its previous state. We would probably want to handle that in the library, as this would minimise bugs and duplicate code in the code using essentials. Furthermore, on UWP the brightness is an override which you are supposed to stop after you need it - simply setting the brightness to the old value might be problematic because you could not differentiate between reset calls and new overrides. My solution would be to return an abstract class/an interface implementing IDisposable to dispose and reset the brightness once you dont need the override anymore. If we could reach a solution here I can have a PR up instantly :)

All 20 comments

Is there a reason why it should be an async method?

On Android, you can set the field screenBrightness on the static class WindowManager.LayoutParams.

On iOS, you can set the field brightness on the UIScreen of the current window which you can probably get from UIScreen.Main.

On UWP, you can use the method BrightnessOverride.GetForCurrentView().SetBrightnessLevel().

All of the above are either fields or methods that return void, so I don't think async is needed. You could even replace it with a property.

I would enjoy seeing a brightness api. I could see several usage scenario, such as PDF/EBook readers and everything else requiring staring at a display for a prolonged time. The uniformity of the api makes it easy to implement. I would like to see this implemented

On UWP there's a way to resume 'auto' brightness. On iOS, this basically happens when the device screen is locked or app is closed. On Android it's unclear if/when this happens.

We could add an api into DeviceDisplay:

partial class DeviceDisplay {
    double Brightness { get; set; }
}

It's unclear on UWP if we must call a method to return to default/auto (stop override) or if this will naturally happen anyway at some point.

More research needs to be done.

@Redth on UWP the brightness override stops if you configure it, e.g. you want the override to stop when you have low battery. You can also return to auto override by passing null into SaveForSystemAsync. UWP also has support to be notified if your brightness override gets removed, as it is up to the system to decide to honor your request.
On Android you can resume auto brightness as well by passing a value < 0 in their setBrightness method. They also offer notification support when your brightness level changes.

What's the lowest common denominator for an API here across platforms? Keep in mind we need to consider behavior differences.

Is it still your original API spec proposal? Again I want to be sure we're minimizing behavioral differences between platforms. Perhaps we should consider the use case for this. Any sort of app like an airline app displaying a QR code comes to mind here, where they'd want to set brightness to max while their page is displayed. In this case I could imagine as a developer overriding 'auto' brightness with a max value on my page appearing, and resuming auto brightness on page disappearing. If the user closes the app and my brightness is overridden, it should in theory come back when my page appears again.

Are there other use cases you can think of I'm not aware of?

Okay I have a working implementation for iOS, Android and UWP. The problem I see is restoring the brightness to its previous state. We would probably want to handle that in the library, as this would minimise bugs and duplicate code in the code using essentials. Furthermore, on UWP the brightness is an override which you are supposed to stop after you need it - simply setting the brightness to the old value might be problematic because you could not differentiate between reset calls and new overrides. My solution would be to return an abstract class/an interface implementing IDisposable to dispose and reset the brightness once you dont need the override anymore. If we could reach a solution here I can have a PR up instantly :)

Is there an update for this? I recently went through all of my branches for Essentials and saw this ticket number in there. I will need this functionality for an upcoming project as well so any message would be appreciated. At least reading brightness values should be unambigious on all platforms, which would be a step in the right direction without involving many complicated design choices

@jamesmontemagno @Redth

Yeah we will revisit this for 1.6

Yeah we will revisit this for 1.6

@Redth is there an ETA for the 1.6 release?

@Redth @jamesmontemagno

Hi. Is there any progress on this issue? I could take that up.

Not at this time. I don't believe there is a PR open but if someone is willing to do the work that would be great!

I did not realise this was open for implementation. I have a nearly two year old branch I could use as a basis for this implementation. I will work on adapting the changes in a new branch with the current state of Essentials

I think the most important thing is ensuring we can have consistent behaviour across platforms with the API. I think we need to answer a few questions:

  • Can the brightness be reverted on each platform, and can we know on each platform when this happens?
  • How can the API express when setting the brightness on each platform is rejected by the underlying platform?

@Redth @Mrnikbobjeff @LuckyDucko
stealing is very bad, but we can just watch this code
https://github.com/LuckyDucko/BrightnessService

@Mrnikbobjeff, @dimonovdd I'd be happy to help with an implementation on this.

@Redth I have the beginnings of some functionality that reads from the Android Light sensor/Lux sensor directly. would that be an interesting addition to this API, this would allow for users to make adjustments in context to the surrounding light readout.

This could result in fun little additions being made available for apps, such as 'Glow in the dark' for a silly example

@LuckyDucko I think the light sensor is a different api that will still be useful. Maybe open an issue /PR with what you have, any research and comments. Then we can review and see if it is possible to add.

Add any notes for all the other platforms as you come across them.

@LuckyDucko If you check we already had a ticket including discussion of luminosity sensors. This is not possible on iOS, even though they have a light sensor any use of it will result in the app not being accepted to the app store.
Edit on mobile, photometer issue thread: https://github.com/xamarin/Essentials/issues/407
In my essentials fork I have a branch named luminosity which contains a reference implementation for all platforms of the photometer, using undocumented iOS functions if you really want that feature for a private application
@Redth the common denominator across platforms is knowing when the brightness override ends (supported on main platforms, since my investigation we also support tizen so I would have to check there). I have not heard of a case where the brightness override is rejected, but I assume this could happen on Android in forced low battery mode. This merits further investigation, but it is such an edge case that I would not see it as a blocker if it might be rejected in certain situations.

Brightness overrides may be rejected by uwp, we would have to wrap the event firing in a task completion source to monitor whether our override is applied. In which circumstances the device rejects the brightness is not detailed in the documentation. This seems to be the only platforms where this is possible. Tizen supports this as well, we might have to pinvoke a but for that though. I see no problems going forward, the solution for uwp would be to simply throw when applying the override does not work.
@Redth

If you think it will be useful and the API is simple enough, then maybe open a draft PR with what you have in the research. Throw some comments in the description.

If it is just iOS that does not support it, it might still be a bit hard as the real base platform support is iOS and Android. However, there are a few thumbs up on this so it does seem wanted.

Maybe start a PR with your API design, and then we can comment, the community can provide feedback and then maybe we get it in for the next release.

@mattleibow recommended i duplicate the following post here instead of on the closed photometer API issue tracker.

@Mrnikbobjeff mentioned that he had a working version of this API, minus iOS due to private headers.

To get around this limitation, others have used the EXIF data from a Video/Photo Stream(?). With this data, run through a simple enough calculation, we are able to get an approximation for lux on iOS.

Below is me explaining how I worked about getting the EXIF data, along with explanation on why its shoddy code 馃槅

First off, I would like to mention that this is the first time I have delved into this level of complexity within my code, so there is a lot to improve upon, and I may be missing something key. However, I managed to create an approximation of 'Brightness sensor' for iOS use that _shouldn't_ get booted for using iOS private API's.

I made a very ramshackle example using the Xamarin iOS manual camera controls repo as boilerplate for my tinkering. I did a very small addition to what is 90% their work, and without it I was going to drop this attempt entirely.

This is how I got the brightness values
Note: again, this is code I hacked away at haphazardly and doesn't represent anything close to what I imagine the proper code to look like

private double GetBrightness(CMSampleBuffer sampleBuffer)
{
    try
    {
        var metaData = sampleBuffer.GetAttachments(CMAttachmentMode.ShouldPropagate);
        var exif = metaData.ValueForKey(new NSString("{Exif}"));
        var fNumber = exif.ValueForKey(new NSString("FNumber"));
        var exposureTime = exif.ValueForKey(new NSString("ExposureTime"));
        var ISOSpeed = Regex.Replace(exif.ValueForKey(new NSString("ISOSpeedRatings")).ToString(), "[^.0-9]", "");
        var brightness = (50.0 * (Double.Parse(fNumber.ToString()) * (Double.Parse(fNumber.ToString())) / (Double.Parse(exposureTime.ToString()) * Double.Parse(ISOSpeed))));
        return brightness / 15000.0;
    }
    catch (Exception)
    { }
    return 0.5;
}

For a full context, I recommend looking at the below attached zip to see how this falls in with everything else.

This approach has some downsides

  1. Its not a _real_ lux meter
  2. The 15000.0 value is based off my testing by putting the camera under direct bright LED lights
  3. There is a BrightnessValue part in this EXIF data, it may be more reliable. (I created a version using this, however, I couldn't work out the ranges fully (-9 to, 20?) and it may change about in the future, or perhaps that was just a hiccup)
  4. It requires video access permissions (as far as i'm aware), this is the real bummer of this approach, making it alot less seamless than the lux meters on other platforms.

Link to my example.
Xamarin_iOS___Manual_Camera_Controls.zip

Shoddy iOS code over

This API has potential for fine tuning apps that are designed for a specific audience/Scenario.

For one, it allows app developers to control the 'Brightness' of their app independent of screen brightness.

An example I was interested in would be where an app that would be used on a car mount.
When in direct sunlight (Bright situation) 'Unimportant' interaction UI elements would 'dull' and 'important' visual readout elements become more vivid.

Was this page helpful?
0 / 5 - 0 ratings