Category Archives: Android Developers Blog

An Open Handset Alliance Project

New Keystore features keep your slice of Android Pie a little safer

Posted by Brian Claire Young and Shawn Willden, Android Security; and Frank Salim, Google Pay

New Android Pie Keystore Features

The Android Keystore provides application developers with a set of cryptographic tools that are designed to secure their users' data. Keystore moves the cryptographic primitives available in software libraries out of the Android OS and into secure hardware. Keys are protected and used only within the secure hardware to protect application secrets from various forms of attacks. Keystore gives applications the ability to specify restrictions on how and when the keys can be used.

Android Pie introduces new capabilities to Keystore. We will be discussing two of these new capabilities in this post. The first enables restrictions on key use so as to protect sensitive information. The second facilitates secure key use while protecting key material from the application or operating system.

Keyguard-bound keys

There are times when a mobile application receives data but doesn't need to immediately access it if the user is not currently using the device. Sensitive information sent to an application while the device screen is locked must remain secure until the user wants access to it. Android Pie addresses this by introducing keyguard-bound cryptographic keys. When the screen is locked, these keys can be used in encryption or verification operations, but are unavailable for decryption or signing. If the device is currently locked with a PIN, pattern, or password, any attempt to use these keys will result in an invalid operation. Keyguard-bound keys protect the user's data while the device is locked, and only available when the user needs it.

Keyguard binding and authentication binding both function in similar ways, except with one important difference. Keyguard binding ties the availability of keys directly to the screen lock state while authentication binding uses a constant timeout. With keyguard binding, the keys become unavailable as soon as the device is locked and are only made available again when the user unlocks the device.

It is worth noting that keyguard binding is enforced by the operating system, not the secure hardware. This is because the secure hardware has no way to know when the screen is locked. Hardware-enforced Android Keystore protection features like authentication binding, can be combined with keyguard binding for a higher level of security. Furthermore, since keyguard binding is an operating system feature, it's available to any device running Android Pie.

Keys for any algorithm supported by the device can be keyguard-bound. To generate or import a key as keyguard-bound, call setUnlockedDeviceRequired(true) on the KeyGenParameterSpec or KeyProtection builder object at key generation or import.

Secure Key Import

Secure Key Import is a new feature in Android Pie that allows applications to provision existing keys into Keystore in a more secure manner. The origin of the key, a remote server that could be sitting in an on-premise data center or in the cloud, encrypts the secure key using a public wrapping key from the user's device. The encrypted key in the SecureKeyWrapper format, which also contains a description of the ways the imported key is allowed to be used, can only be decrypted in the Keystore hardware belonging to the specific device that generated the wrapping key. Keys are encrypted in transit and remain opaque to the application and operating system, meaning they're only available inside the secure hardware into which they are imported.

Secure Key Import is useful in scenarios where an application intends to share a secret key with an Android device, but wants to prevent the key from being intercepted or from leaving the device. Google Pay uses Secure Key Import to provision some keys on Pixel 3 phones, to prevent the keys from being intercepted or extracted from memory. There are also a variety of enterprise use cases such as S/MIME encryption keys being recovered from a Certificate Authorities escrow so that the same key can be used to decrypt emails on multiple devices.

To take advantage of this feature, please review this training article. Please note that Secure Key Import is a secure hardware feature, and is therefore only available on select Android Pie devices. To find out if the device supports it, applications can generate a KeyPair with PURPOSE_WRAP_KEY.

Effective foreground services on Android

Posted by Keith Smyth

This is the fourth in a series of blog posts in which outline strategies and guidance in Android with regard to power.

A process is not forever

Android is a mobile operating system designed to work with constrained memory and battery. For this reason, a typical Android application can have its process killed by the system to recover memory. The process being killed is chosen based on a ranking system of how important that process is to the user at the time. Here, in descending order, is the ranking of each class of process. The higher the rank, the less likely that process is to be killed.

Native Native Linux daemon processes are responsible for running everything (including the process killer itself).
System The system_server process, which is responsible for maintaining this list.
Persistent apps Persistent apps like Phone, Wi-Fi, and Bluetooth are crucial to keeping your device connected and able to provide its most basic features.
Foreground app A foregrounded / top (user visible) app is the app a user is currently using.
Perceptible apps These are apps that the user can perceive are running. For example an app with a foreground service playing audio, or an app set as the preferred voice interaction service will be bound to the system_server, effectively promoting it to Perceptible level.
Service Background services like download manager and sync manager.
Home The Launcher app containing desktop wallpaper
Previous app The previous foreground app the user was using. The previous app lives above the cached apps as it's the most likely app the user will switch to next.
Cached apps These are the remaining apps that have been opened by the user, and then backgrounded. They will be killed first to recover memory, and have the most restrictions applied to them on modern releases. You can read about them on the Behavior Changes pages for Nougat, Oreo and Pie.


The foreground service

There is nothing wrong with becoming a cached app: Sharing the user's device is part of the lifecycle that every app developer must accept to keep a happy ecosystem. On a device with a dead battery, 100% of the apps go unused. And an app blamed for killing the battery could even be uninstalled.

However, there are valid scenarios to promote your app to the foreground: The prerequisites for using a foreground service are that your app is executing a task that is immediate, important (must complete), is perceptible to the user (most often because it was started by the user), and must have a well defined start and finish. If a task in your app meets these criteria, then it can be promoted to the foreground until the task is complete.

There are some guidelines around creating and managing foreground services. For all API levels, a persistent notification with at least PRIORITY_LOW must be shown while the service is created. When targeting API 26+ you will also need to set the notification channel to at least IMPORTANCE_LOW. The notification must have a way for the user to cancel the work, this cancellation can be tied to the action itself: for example, stopping a music track can also stop the music-playback service. Last, the title and description of the foreground service notification must show an accurate description of what the foreground service is doing.

To read more about foreground services, including several important updates in recent releases, see Running a service in the foreground

Foreground service use cases

Some good example usages of foreground services are playing music, completing a purchase transaction, high-accuracy location tracking for exercise, and logging sensor data for sleep. The user will initiate all of these activities, they must happen immediately, have an explicit beginning and end, and all can be cancelled by the user at any time.

Another good use case for a foreground service is to ensure that critical, immediate tasks (e.g. saving a photo, sending a message, processing a purchase) are completed if the user switches away from the application and starts a new one. If the device is under high memory pressure it could kill the previous app while it is still processing causing data loss or unexpected behavior. An elegantly written app will detect being backgrounded and respond by promoting its short, critical task to the foreground to complete.

If you feel you need your foreground service to stay alive permanently, then this is an indicator that a foreground service is not the right answer. Many alternatives exist to both meet the requirements of your use case, and be the most efficient with power.

Alternatives

Passive location tracking is a bad use case for foreground services. If the user has consented to being tracked, use the FusedLocationProvider API to receive bundled location updates at longer intervals, or use the geofencing API to be efficiently notified when a user enters or leaves a specified area. Read more about how to optimize location for battery.

If you wish to pair with a Bluetooth companion device, use CompanionDeviceManager. For reconnecting to the device, BluetoothLeScanner has a startScan method that takes a PendingIntent that will fire when a narrow filter is met.

If your app has work that must be done, but does not have to happen immediately: WorkManager or JobScheduler will schedule the work for the best time for the entire system. If the work must be started immediately, but then can stop if the user stops using the app, we recommend ThreadPools or Kotlin Coroutines.

DownloadManager facilitates handling long running downloads in the background. It will even handle retries over poor connections and system reboots for you.

If you believe you have a use case that isn't handled let us know!

Conclusion

Used correctly, the foreground service is a great way to tell Android that your app is doing something important to the user. Making the right decision on which tool to use remains the best way to provide a premium experience on Android for all users. Use the community and Google to help with these important decisions, and always respect the user first.

Google Play services discontinuing updates for API levels 14 and 15

Posted by Sam Spencer, Technical Program Manager, Google Play

The Android Ice Cream Sandwich (ICS) platform is seven years old and the active device count has been below 1% for some time. Consequently, we are deprecating support for ICS in future releases of Google Play services. For devices running ICS, the Google Play Store will no longer update Play Services APK beyond version 14.7.99.

What does this mean as an Application developer:

The Google Play services SDK contains the interfaces to the functionality provided by the Google Play services APK, running as background services. The functionality required by the current, released SDK versions is already present on ICS devices with Google Play services and will continue to work without change.

With the SDK version changes earlier this year, each library can be independently released and may update its own minSdkVersion. Individual libraries are not required to change based on this deprecation. Newer SDK components may continue to support API levels 14 and 15 but many will update to require the higher API level. For applications that support API level 16 or greater, you will not need to make any changes to your build. For applications that support API levels 14 or 15, you may continue to build and publish your app to devices running ICS, but you will encounter build errors when updating to newer SDK versions. The error will look like this:

Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 14 cannot be smaller than version 16 declared in library [com.google.android.gms:play-services-FOO:16.X.YY]
        Suggestion: use tools:overrideLibrary="com.google.android.gms:play_services" to force usage

Unfortunately, the stated suggestion will not help you successfully run your app on older devices. In order to use the newer SDK, you will need to use one of the following options:

1. Target API level 16 as the minimum supported API level.

This is the recommended course of action. To discontinue support for API levels that will no longer receive Google Play services updates, simply increase the minSdkVersion value in your app's build.gradle to at least 16. If you update your app in this way and publish it to the Play Store, users of devices with less than that level of support will not be able to see or download the update. However, they will still be able to download and use the most recently published version of the app that does target their device.

A very small percentage of all Android devices are using API levels less than 16. You can read more about the current distribution of Android devices. We believe that many of these old devices are not actively being used.

If your app still has a significant number of users on older devices, you can use multiple APK support in Google Play to deliver an APK that uses Google Play services 14.7.99. This is described below.

2. Build multiple APKs to support devices with an API level less than 16.

Along with some configuration and code management, you can build multiple APKs that support different minimum API levels, with different versions of Google Play services. You can accomplish this with build variants in Gradle. First, define build flavors for legacy and newer versions of your app. For example, in your build.gradle, define two different product flavors, with two different compile dependencies for the stand-in example play-services-FOO component:

productFlavors {
    legacy {
        minSdkVersion 14
        versionCode 1401  // Min API level 14, v01
    }
    current {
        minSdkVersion 16
        versionCode 1601  // Min API level 16, v01
    }
}

dependencies {
    legacyCompile 'com.google.android.gms:play-services-FOO:16.0.0'
    currentCompile 'com.google.android.gms:play-services-FOO:17.0.0'
}

In the above situation, there are two product flavors being built against two different versions of play-services-FOO. This will work fine if only APIs are called that are available in the 16.0.0 library. If you need to call newer APIs made available with 17.0.0, you will have to create your own compatibility library for the newer API calls so that they are only built into the version of the application that can use them:

  1. Declare a Java interface that exposes the higher-level functionality you want to perform that is only available in current versions of Play services.
  2. Build two Android libraries that implement that interface. The "current" implementation should call the newer APIs as desired. The "legacy" implementation should no-op or otherwise act as desired with older versions of Play services. The interface should be added to both libraries.
  3. Conditionally compile each library into the app using "legacyCompile" and "currentCompile" dependencies as illustrated for play-services-FOO above.
  4. In the app's code, call through to the compatibility library whenever newer Play APIs are required.

After building a release APK for each flavor, you then publish them both to the Play Store, and the device will update with the most appropriate version for that device. Read more about multiple APK support in the Play Store.

Improve media and messaging app integrations with Android Auto

Posted by John Posavatz, Product Manager, Android Auto

At Google I/O this past May, we provided a sneak preview of several new media and messaging features for Android Auto. We are happy to announce that these features are now ready in our latest version of Android Auto, and we encourage you to update your Android Auto implementations to take advantage of them!

New Media Features

Several new features make it easier for users to find the media content that they're looking for. Check out the full documentation for them on our Android developer site.

Search results

After performing an Assistant-based search (e.g. "OK Google, play [artist / album / playlist / book / song / genre]"), music auto-plays as before, and in addition you can now provide your own list of categorized results. First, you'll need to declare support for onSearch() in your MediaBrowserServiceCompat implementation, and then override it. Android Auto forwards a user's search terms to this method whenever a user invokes the "Show more results" affordance.

Android Auto calls onSearch with the same Bundle of extras as the one defined for Android Auto's playFromSearch() calls. Unlike playFromSearch(), onSearch() includes a Result> that can be used to return multiple MediaItems back to Android Auto for display.

You can then categorize search results using title items. For example, music apps may include categories such as "Artists", "Albums" and "Songs".

Improved browse

Content has been "brought forward" out of the drawer, and now resides within the main view of the media screen. Within this new layout, you now have an option of either displaying your browse trees as a simple list, or you can optionally display large grids of album art / icons. We recommend using lists wherever the text description is most useful in describing content (e.g. a list of track names or podcast episodes), whereas the larger grid view is most appropriate where the album / icon aids in quick identification and selection.

To start applying content styles, you should set a global default for how your media items are displayed by applying specific constants in the BrowserRoot extras bundle returned by the onGetRoot() function. Android Auto reads the extras associated with each item in the browse tree and looks for specific constants (detailed in our documentation), and then use the presence/value of each key to add the appropriate indicator.

In order to change the default behavior for a specific node, the Content Style API supports overriding the default global hint for any browsable node's children. The same extras as above can be supplied as extras in the MediaDescription. If these extras are present, then the children of that browsable node will have the new Content Style hint.

Finally, you can organize content using title items to group media in a list. To do this, every media item in the group needs to declare an extra in their media description with the same string value, which you can localize. This value is used as the group title. You also need to pass the media items together and in the order you want them displayed.

Additional metadata icons

In both browsing and playback views, you are now able to show icons next to media items which have explicit language, have been downloaded to the user's device, and which are unplayed / partially played / completed (e.g. for audiobooks and podcasts).

Android Auto inspects extras for each item in the browse tree and looks for the specific keys for the indicators, and then uses the presence/value of each key to add the appropriate indicator.

You should add these extras to content returned by your MediaBrowse Service. "Explicit" and "Downloaded" are boolean extras (set to true to show the indicator), while "Completion State" is an integer extra set to the appropriate value. Apps should create an extras bundle that includes one or more of these keys and pass that to MediaDescription.Builder.setExtras().

Updates to Messaging

We are deprecating CarExtender, in favor of the more robust and broadly beneficial MessagingStyle API. Migrating to MessagingStyle is very straightforward, and not only extends messaging support beyond Android Auto (for example, to Google Assistant), but it also brings the following immediate benefits for Android Auto:

Group messaging

Formerly, Android Auto's support for group messages was lacking - in most cases, notifications were never shown. MessagingStyle addresses that, so that your users never miss a message.

MMS / RCS support

Android Auto only supports SMS natively through the system SMS broadcast. MessagingStyle allows support for SMS apps that themselves support RCS and MMS.

To enable your app to provide messaging service for Auto devices, your app must do the following:

  1. Build and send NotificationCompat.MessagingStyle objects that contain reply and mark-as-read Action objects.
  2. Handle replying and marking a conversation as read with a Service.
  3. Configure your manifest to indicate the app supports Android Auto.

By moving to MessagingStyle, your app will not only gain automotive support, but also gain a richer mobile notification experience including inline replying, image preview, and conversation history; all within the notification shade.

An in-depth guide to implementing (or updating to) MessagingStyle can be found in our online developer documentation.

Thanks for continuing to support Android Auto!

Android codelab courses are here!

Posted by Jocelyn Becker, Senior Program Manager, Google Developer Training

The Google Developers Training team recently published an updated version of our Android Developer Fundamentals course as a series of Google codelabs.

Android Developer Fundamentals course landing page

Codelabs made their debut as onsite tutorials at Google I/O in 2015, and have skyrocketed in popularity as a way for developers to learn how to use Google technologies, APIs, and SDKs. A codelab is a short, self-contained tutorial that walks you through how to do a specific task. More than 2 million users have worked through Google codelabs this year.

Our Android courses were originally intended as classroom-based courses. However, we found that many people work through the courses on their own, outside of formal teaching programs. So, when we updated the Android Developer Fundamentals course, in addition to supporting classroom-based learning, we made the material available as a sequential series of codelabs.

Android Developer Fundamentals course

The updated Android Developer Fundamentals (V2) course includes lessons on using the Room database and other Architecture Components. All the apps have been updated to reflect that the Empty Activity template in Android Studio uses ConstraintLayout, and we've updated all apps to a later version of Android Studio. For more details on the differences, see the release notes.

Advanced Android course

We've also re-published the Advanced Android Developer course as a series of codelabs. This course provides step-by-step instructions for learning about more advanced topics, and adding features to your app to improve user engagement and delight. Learn how to add maps to your apps, create custom views, use SurfaceView to draw directly to the screen, and much more.

Screenshots for apps that display a customized map marker, a customized fan controller view, and an Android hiding in the dark

Teaching materials for both courses

Android logo wearing graduation cap

If you want to teach either course in the classroom, or use it as the basis of a study jam, the complete package is still available, including slide decks, source code in GitHub, and concept guides, in addition to the step-by-step codelabs.

Celebrating the developers behind the best apps and games of 2018

Posted by Purnima Kochikar, Director, Business Development, Games & Applications

Today, we announced our annual Best of 2018 list, highlighting the best content on Google Play. But ever wonder about the makers behind your favorite apps and games like PUBG MOBILE or Tasty? Well, we wanted to take a moment to celebrate the developers that brought to life the best U.S. apps and games of 2018. And this year was jam packed with entertainment — all thanks to the developers who pushed the envelope and sparked our imaginations.

Check out the full rundown of the developers behind the best apps and games of 2018 on Google Play:

Best App of 2018

Most Entertaining Apps

Best Self Improvement Apps

Best Daily Helper Apps

Best Hidden Gem Apps

Best Game of 2018

Most Competitive Games

Most Innovative Games

Best Indie Games

Most Casual Games

SDK Developers: sign up to stay up to date with latest tips, news and updates

Posted by Parul Soi, Strategic Partner Development Manager, Google Play

Android is fortunate to have an incredibly rich ecosystem of SDKs and libraries to help developers build great apps more efficiently. These SDKs can range from developer tools that simplify complicated feature development to end-to-end services such as analytics, attribution, engagement, etc. All of these tools can help Android developers reduce cost and ship products faster.

For the past few months, various teams at Google have been working together on new initiatives to expand the resources and support we offer for the developers of these tools. Today, SDK developers can sign up and register their SDK with us to receive updates that will keep you informed about Google Play policy changes, updates to the platform, and other useful information.

Our goal is to provide you with whatever you need to better serve your technical and business goals in helping your partners create better apps or games. Going forward we will be sharing further resources to help SDK developers, so stay tuned for more updates.

If you develop an SDK or library for Android, make sure you sign up and register your SDK to receive updates about the latest tools and information to help serve customers better. And, if you're an app developer, share this blogpost with the developers of the SDKs that you use!

How useful did you find this blog post?

Fast Pair Update

Posted by Seang Chau (VP Engineering)

Last year we announced Fast Pair, a set of specs that make it easier to connect Bluetooth headsets and speakers to Android devices.

Today, we're making it easier for people to connect Fast Pair compatible accessories to devices associated with the same Google Account. Fast Pair will connect accessories to a user's current and future Android phones (6.0+), and we're adding support for Chromebooks in 2019.

Fast Pair provides stress-free Bluetooth pairing for your Android phone.

We have been working closely with dozens of manufacturers, many of which are bringing new Fast Pair compatible devices to market over the coming months. This includes Jaybird, who is already selling the Tarah Wireless Sport Headphones, as well as upcoming products from prominent brands such as Anker SoundCore, Bose, and many more.

The Jaybird Tarah, Fast Pair compatible sport headphones already available in the market.

We also want to make it easy for manufacturers to ship compatible products with minimal additional engineering effort. We collaborated with industry leading Bluetooth audio companies such as Airoha Technology Corp., BES and Qualcomm Technologies International, Ltd. (QTIL) to add native Fast Pair support to their software development kits.

If you are a manufacturer interested in creating Fast Pair compatible Bluetooth devices, just head to our Nearby Devices console to register your product and validate that it has correctly implemented the Fast Pair specs.

Wear OS by Google: final API 28 emulator with new redesigned UI

Posted by Hoi Lam, Lead Developer Advocate

Today, we are launching the final API 28 emulator image for developers. This image will also contain the UI redesign we announced in August. You should verify that your app's notification works well with the new notification steam, and that your apps work well against changes previously announced for API 28.

What's new in API 28?

Here are the highlights of the API 28 emulator:

  • New notification stream - You should make sure that your notifications are branded correctly, using color, and that the notification is sufficiently concise to fit into the new layout. Custom notification layout is no longer supported.
  • App Standby Buckets - Wear OS prioritizes app requests for resources based on how recent and how frequently the apps have been used. Developers are advised to follow best practices to ensure that their app behaves well, whichever bucket the apps are in.
  • User input and data privacy - To enhance user privacy, API 28 introduced new changes which limit background apps' access to device sensors. Depending on app requirements, developers may need to use a foreground service to enable continual access to sensor data.

Please note that changes related to the new notification stream are being rolled out to devices supporting API 25 and up. You can test how your notification will behave now, before roll-out is complete, by using the API 28 emulator image.

Keep your feedback coming

Just because we are now in release build does not mean that our work stops here. Please continue to submit all bug / enhancement requests via the Wear OS by Google issue tracker.

Finally, we are grateful for all of your valuable feedback during the developer preview. It played an important role in our decision making process - especially concerning App Standby Buckets. Thank you!

Getting screen brightness right for every user

Posted by Ben Murdoch, Software Engineer and Michael Wright, Android Framework Engineer

The screen on a mobile device is critical to the user experience. The improved Adaptive Brightness feature in Android P automatically manages the display to match your preferences for brightness level so you get the best experience, whatever the current lighting environment.

Screen brightness in Android is managed via Quick Settings or via the settings app

(Settings → Display → Brightness Level).

In Android Pie, Adaptive Brightness is enabled by default (Settings → Display → Adaptive Brightness).

While enabled, Android automatically selects a screen brightness that's suitable for the user's current ambient light conditions. Prior to Android Pie, the brightness slider didn't represent an absolute screen brightness level, but a global adjustment factor for boosting or reducing the device manufacturer's preset screen brightness curve across all ambient light levels:

* Setting the slider to center resulted in the device using the preset.

* Setting the slider to the left of center applied a negative scale factor, making the screen dimmer than the preset.

* Setting the slider to the right of center applied a positive scale factor, making the screen brighter than the preset.

So, under low ambient light conditions, you might prefer a brighter screen than the preset level and move the brightness slider up accordingly. But, because that adjustment would boost the brightness at all ambient light levels, you might find yourself needing to move the brightness slider back down in brighter ambient light. And so on, back and forth.

To improve this experience, we've introduced two important changes to screen brightness in Android Pie:

  1. Better slider control
  2. Personalization of the brightness level

Better slider control

The slider control now represents absolute screen brightness rather than the global adjustment factor. That means that you may see it move on its own while Adaptive Brightness is on. This is expected behavior!

Humans perceive brightness on a logarithmic rather than linear scale1. That means changes in screen brightness are much more noticeable when the screen is dark versus bright. To match this difference in perception, we updated the brightness slider UI in the notification shade and System Settings app to work on a more human-like scale. This means you may need to move the slider farther to the right than you did on previous versions of Android for the same absolute screen brightness, and that when setting a dark screen brightness you have more precise control over exactly which brightness to set.

Personalization of screen brightness

Prior to Android P, when developing a new Android device the device manufacturer would determine a baseline mapping from ambient brightness to screen brightness based on the display manufacturer's recommendation and a bit of experimentation. All users of that device would receive the same baseline mapping and, while using the device, move the brightness slider around to set their global adjustment factor. To determine the final screen brightness, the system would first look at the room brightness and the baseline mapping to find the default screen brightness for that situation, and then apply the global adjustment factor.

What we found is that in many cases this global adjustment factor didn't adequately capture personal preferences - that is, users tended to change the slider often for new lighting environments.

For Android Pie we worked with researchers from DeepMind to build a machine learning model that will observe the interactions that a user makes with the screen brightness slider, and train on-device to personalise the mapping of ambient light level to screen brightness.

This means that Android will learn what screen brightness is comfortable for a user in a given lighting environment. The user teaches it by manually adjusting the slider, and, as the software trains over time, the user should need to make fewer manual adjustments. In testing the feature, we've observed that after a week almost half our test users are making fewer manual adjustments while the total number of slider interactions across all internal test users was reduced by over 10%. The model that we've developed is updatable and will be tuned based on real world usage now that Android Pie has been released. This means that the model will continue to get better over time.

We believe that screen brightness is one of those things that should just work, and these changes in Android Pie are a step towards realizing that. For the best performance no matter where you are models run directly on the device rather than the cloud, and train overnight while the device charges.

The improved Adaptive Brightness feature is now available on Pixel devices and we are working with our OEM partners now to incorporate Adaptive Brightness into Android Pie builds for their devices.

Notes