Posted by The Jetpack Compose Team
In less than 24 hours, we're giving you a backstage pass to Jetpack Compose, Android's modern toolkit for building native UIs, on #TheAndroidShow. Hosted by Kari Byron, you'll hear the latest on Jetpack Compose from the people who built it, plus a fireside interview with Android's Dave Burke.
Broadcasting live on February 24th at 9AM PT, you’ll be able to watch the show at goo.gle/TheAndroidShow, where you’ll also be able to find more information and links to all of the things we covered in the show. Or if you prefer, you can watch directly on YouTube or Twitter.
Got a burning Jetpack Compose question? Want to learn about annotating a function type with @ Composable? Or how to add a static parameter to Composable functions at the compiler level? Tweet us your Jetpack Compose questions now, using #TheAndroidShow. We’ve assembled a team of experts, ready to answer your questions live on #TheAndroidShow; tune in on February 24 to see if we cover your question!
Posted by Dave Burke, VP of Engineering
Every day, Android apps help billions of people work, play, communicate, and create on a wide range of devices from phones and laptops to tablets, TVs, and cars. As more people come to rely on the experiences you build, their expectations can rise just as fast. It’s one of the reasons we share Android releases with you early: your feedback helps us build a better platform for your apps and all of the people who use them. Today, we’re releasing the first Developer Preview of Android 12, the next version of Android, for your testing and feedback.
With each version, we’re working to make the OS smarter, easier to use, and better performing, with privacy and security at the core. In Android 12 we’re also working to give you new tools for building great experiences for users. Starting with things like compatible media transcoding, which helps your app to work with the latest video formats if you don’t already support them, and easier copy/paste of rich content into your apps, like images and videos. We’re also adding privacy protections and optimizing performance to keep your apps responsive.
Today’s first preview is just the start for Android 12, and we’ll have lots more to share as we move through the release. Read on for a taste of what’s new in Android 12, and visit the Android 12 developer site for details on downloads for Pixel and release timeline. As always, it’s crucial to get your feedback early, to help us incorporate it into the final product, so let us know what you think!
Alongside the work we’re doing in Android 12, later this month we’ll have more to share on another important tool that helps you create great user experiences more easily: Jetpack Compose, our modern toolkit for building native UI. Join us on #TheAndroidShow for a behind-the-scenes look at Jetpack Compose, livestreamed on February 24 at 9AM PT, and tweet your Jetpack Compose questions using #TheAndroidShow to have them answered live on the show.
Privacy is at the heart of everything we do, and in Android 12 we’re continuing to focus on giving users more transparency and control while keeping their devices and data secure. In today’s release we’ve added new controls over identifiers that can be used for tracking, safer defaults for app components, and more. These changes may affect your apps, so we recommend testing as soon as possible. Watch for more privacy and security features coming in later preview releases.
Modern SameSite cookie behaviors in WebView - In line with changes to Chrome and other browsers, WebView includes new SameSite cookie behaviors to provide additional security and privacy and give users more transparency and control over how cookies can be used across sites. More here.
Safer exporting of components - To prevent apps from inadvertently exporting activities, services, and receivers, we’re changing the default handling of the android:exported attribute to be more explicit. With this change, components that declare one or more intent filters must now explicitly declare an android:exported attribute. You should inspect your components in the manifest in order to avoid installation errors related to this change. More here.
Safer handling of Intents - To make handling PendingIntents more secure, Android 12 requires apps to explicitly declare a mutability flag, either FLAG_MUTABLE or the new FLAG_IMMUTABLE, for each PendingIntent. More here.
You can read more about these and other privacy and security changes here.
In Android 12 we’re investing in key areas to help deliver a polished experience and better performance for users. Here are some of the updates so far.
Compatible media transcoding - With the prevalence of HEVC hardware encoders on mobile devices, camera apps are increasingly capturing in HEVC format, which offers significant improvements in quality and compression over older codecs. Most apps should support HEVC, but for apps that can’t, we’re introducing compatible media transcoding.
With this feature, an app that doesn’t support HEVC can have the platform automatically transcode the file into AVC, a format that is widely compatible. The transcoding process takes time, depending on the video and hardware properties of the device. As an example, a one minute 1080p video at 30fps takes around 9 seconds to transcode on a Pixel 4. You can opt-in to use the transcoding service by just declaring the media formats that your apps don't support. For developers, we strongly recommend that your apps support HEVC, and if that’s not possible, enable compatible media transcoding. The feature will be active on all devices using HEVC format for video capture. We'd love to hear your feedback on this feature. More here.
AVIF image support - To give you higher image quality with more efficient compression, Android 12 introduces platform support for AV1 Image File Format (AVIF). AVIF is a container format for images and sequences of images encoded using AV1. Like other modern image formats, AVIF takes advantage of the intra-frame encoded content from video compression. This dramatically improves image quality for the same file size when compared to older image formats, such as JPEG.
AVIF (18.2kB)
JPEG (20.7kB)
Credit: Image comparison from AVIF has landed by Jake Archibald
Foreground service optimizations - Foreground services are an important way for apps to manage certain types of user-facing tasks, but when overused they can affect performance and even lead to app kills. To ensure a better experience for users, we will be blocking foreground service starts from the background for apps that are targeting the new platform. To make it easier to transition away from this pattern, we’re introducing a new expedited job in JobScheduler that gets elevated process priority, network access, and runs immediately regardless of power constraints like Battery Saver or Doze. For back-compatibility, we’ve also built expedited jobs into the latest release of Jetpack WorkManager library. Also, to reduce distraction for users, we’re now delaying the display of some foreground service notifications by up to 10 seconds. This gives short-lived tasks a chance to complete before their notifications are shown. More here.
Rich content insertion - Users love images, videos and other expressive content, but inserting and moving this content in apps is not always easy. To make it simple for your apps to receive rich content, we’re introducing a new unified API that lets you accept content from any source: clipboard, keyboard, or drag and drop. You can attach a new interface, OnReceiveContentListener, to UI components and get a callback when content is inserted through any mechanism. This callback becomes the single place for your code to handle insertion of all content, from plain and styled text to markup, images, videos, audio files, and more. For back-compatibility, we’ve added the unified API to AndroidX. More here.
Audio-coupled haptic effect - In Android 12 apps can provide audio-coupled haptic feedback through the phone's vibrator. The vibration strength and frequency are derived from an audio session, allowing you to create more immersive game and audio experiences. For example, a video calling app could use custom ringtones to identify the caller through haptic feedback, or you could simulate rough terrain in a racing game. More here.
Notification UI updates - We’re refreshing notification designs to make them more modern, easier to use, and more functional. In this first preview you’ll notice changes from the drawer and controls to the templates themselves. We’re also optimizing transitions and animations across the system to make them more smooth. As part of the updates, for apps targeting Android 12 we’re decorating notifications with custom content with icon and expand affordances to match all other notifications. More here.
Faster, more responsive notifications - When users tap a notification, they expect to jump immediately into the app - the faster the better. To meet that expectation, developers should make sure that notification taps trigger Activity starts directly, rather than using “trampolines” - an intermediary broadcast receiver or service - to start the Activity. Notification trampolines can cause significant delays and affect the user experience. To keep notifications responsive, Android 12 will block notification trampolines by preventing them from launching their target Activities, and we’re asking developers to migrate away from this pattern. The change applies only to apps targeting the new platform, but for all apps we’ll display a toast to make trampolines visible to you and to users. More here.
Improved Binder IPC calls - As part of our work on performance, we’ve put a focus on reducing system variability. We’ve taken a look at latency and workload distribution, and made optimizations that reduce the median experience from the tail end, or 99% percentile use case. In doing so, we’ve targeted improvements to system binder calls adding lightweight caching strategies and focusing on removing lock contention to improve latency distribution. This has yielded roughly a 2x performance increase on Binder calls overall, with significant improvements in specific calls, for example a 47x improvement in refContentProvider(), 15x in releaseWakeLock(), and 7.9x in JobScheduler.schedule().
refContentProvider()
releaseWakeLock()
JobScheduler.schedule()
We’re working to make updates faster and smoother by prioritizing app compatibility as we roll out new platform versions. In Android 12 we’ve made most app-facing changes opt-in to give you more time, and we’ve updated our tools and processes to help you get ready sooner. We’ve also added new functionality to Google Play system updates to give your apps a better environment on Android 12 devices.
More of Android updated through Google Play - We’re continuing to expand our investment in Google Play system updates (Project Mainline) to give apps a more consistent, secure environment across devices. In Android 12 we’ve added the Android Runtime (ART) module that lets us push updates to the core runtime and libraries on devices running Android 12. We can improve runtime performance and correctness, manage memory more efficiently, and make Kotlin operations faster - all without requiring a full system update. We’ve also expanded the functionality of existing modules - for example, we’re delivering our compatible media transcoding feature inside an updatable module.
Optimizing for tablets, foldables, and TVs - With more people than ever using apps on large-screen devices like foldables, tablets, and TVs, now is a great time to make sure your app or game is ready. Get started by optimizing for tablets and building apps for foldables. And, for the biggest screen in the home, the first Android 12 preview for Android TV is also available. In addition to bringing the latest Android features to the TV with this preview, you will also be able to test your apps on the all-new Google TV experience. Learn more on the Android TV Developers site and get started with your ADT-3 developer kit.
Updated lists of non-SDK interfaces - We’ve restricted additional non-SDK interfaces, and as always your feedback and requests for public API equivalents are welcome.
Easier testing and debugging of changes - To make it easier for you to test the opt-in changes that can affect your app, we’ve made many of them toggleable. WIth the toggles you can force-enable or disable the changes individually from Developer options or adb. Check out the details here.
App compatibility toggles in Developer Options.
Platform stability milestone - Like last year, we’re letting you know our Platform Stability milestone well in advance, to give you more time to plan for app compatibility work. At this milestone we’ll deliver not only final SDK/NDK APIs, but also final internal APIs and app-facing system behaviors. We’re expecting to reach Platform Stability by August 2021, and you’ll have several weeks before the official release to do your final testing. The release timeline details are here.
The Developer Preview has everything you need to try the Android 12 features, test your apps, and give us feedback. You can get started today by flashing a device system image to a Pixel 3 / 3 XL, Pixel 3a / 3a XL, Pixel 4 / 4 XL, Pixel 4a / 4a 5G, or Pixel 5 device. If you don’t have a Pixel device, you can use the 64-bit system images with the Android Emulator in Android Studio.
When you’re set up, here are some of the things you should do:
We’ll update the preview system images and SDK regularly throughout the Android 12 release cycle. This initial preview release is for developers only and not intended for daily or consumer use, so we're making it available by manual download only. You can flash a factory image to your Pixel device, or you can sideload an OTA image to a Pixel device running Android 11, in which case you won’t need to unlock your bootloader or wipe data. Either way, once you’ve manually installed a preview build, you’ll automatically get future updates over-the-air for all later previews and Betas. More here.
As we get closer to a final product, we'll be inviting consumers to try it out as well, and we'll open up enrollments through Android Beta at that time. Stay tuned for details, but for now please note that Android Beta is not currently available for Android 12.
For complete information, visit the Android 12 developer site.
Posted by Sameer Samat, Vice President, Platforms & Ecosystems
From day one, we designed Android to be a flexible, adaptive platform.
Most people picture a smartphone when they think of Android, but Android also powers an amazing number of large-screen devices. In fact, there are more than 175 million Android tablets with the Google Play store,1 making Android tablets a vital form factor for Google and our OEM partners today. Android apps also run on Chrome OS laptops, and the number of monthly active users who enabled Android apps grew 250% in just the last year.2
Here at Google, we’re excited to see how you can take advantage of large-screen formats - including Samsung’s new Galaxy Tab S6, the upcoming Lenovo™ Smart Tab M8 with Google Assistant, the upcoming Samsung Galaxy Fold, and other devices launching this week at IFA. Our OEM partners are building experiences that help users every day:
From the start, Android was designed as a platform that could handle multiple screen sizes. Over the years, we’ve continued to add functionality for developers to accommodate new devices and form factors.
Android’s layout system helps applications smoothly resize and adjust their layout interactively.
By optimizing your app to take advantage of different form factors, developers have an opportunity to deliver richer, more engaging experiences to millions of users on larger screens. And if you don’t have access to physical devices, the Android Emulator supports all of the form factors mentioned above, from Chrome OS to phones and tablets.
Developers of apps like Mint, Evernote, and Asphalt are just a few who have seen success from taking their existing APK to larger screens.
To learn more about optimizing your Android apps for richer experiences on tablets, Chrome OS laptops, foldables, and more, join us at the Android Developer Summit on October 23-24 — either in person or via the livestream — or check out our recap videos on YouTube.
Sources:
[1] The number of tablets only accounts for devices that have the Google Play Store installed (for example, this excludes tablets in China); the actual number of tablets capable of running Android applications is much larger.
[2] Google Internal Data, March 2018 to March 2019.
Since announcing ConstraintLayout at Google I/O last year, we've continued to improve the layout's stability and layout editor support. We've also added new features specific to ConstraintLayout that help you build various type of layouts, such as introducing chains and setting size as a ratio. In addition to these features, there is a notable performance benefit by using ConstraintLayout. In this post, we'll walk through how you can benefit from these performance improvements.
ConstraintLayout
To better understand the performance of ConstraintLayout, let's take a step back and see how Android draws views.
When a user brings an Android view into focus, the Android framework directs the view to draw itself. This drawing process comprises 3 phases:
The system completes a top-down traversal of the view tree to determine how large each ViewGroup and View element should be. When a ViewGroup is measured, it also measures its children.
ViewGroup
Another top-down traversal occurs, with each ViewGroup determining the positions of its children using the sizes determined in the measure phase.
The system performs yet another top-down traversal. For each object in the view tree, a Canvas object is created to send a list of drawing commands to the GPU. These commands include the ViewGroup and View objects' sizes and positions, which the system determined during the previous 2 phases.
Canvas
View
Each phase within the drawing process requires a top-down traversal of the view tree. Therefore, the more views you embed within each other (or nest) into the view hierarchy, the more time and computation power it takes for the device to draw the views. By keeping a flat hierarchy in your Android app layouts, you can create a fast and responsive user interface for your app.
With that explanation in mind, let's create a traditional layout hierarchy that uses LinearLayout and RelativeLayout objects.
LinearLayout
RelativeLayout
Let's say we want to build a layout like the image above. If you build it with traditional layouts, the XML file contains an element hierarchy similar to the following (for this example, we've omitted the attributes):
<RelativeLayout> <ImageView /> <ImageView /> <RelativeLayout> <TextView /> <LinearLayout> <TextView /> <RelativeLayout> <EditText /> </RelativeLayout> </LinearLayout> <LinearLayout> <TextView /> <RelativeLayout> <EditText /> </RelativeLayout> </LinearLayout> <TextView /> </RelativeLayout> <LinearLayout > <Button /> <Button /> </LinearLayout> </RelativeLayout>
Although there's usually room for improvement in this type of view hierarchy, you'll almost certainly still need to create a hierarchy with some nested views.
As discussed before, nested hierarchies can adversely affect performance. Let's take a look at how the nested views actually affect the UI performance using Android Studio's Systrace tool. We called the measure and layout phases for each ViewGroup (ConstraintLayout and RelativeLayout) programmatically and triggered Systrace while the measure and layout calls are executing. The following command generates an overview file that contains key events, such as expensive measure/layout passes, that occur during a 20-second interval:
python $ANDROID_HOME/platform-tools/systrace/systrace.py --time=20 -o ~/trace.html gfx view res
For more details about how you can use Systrace, see the Analyzing UI Performance with Systrace guide.
Systrace automatically highlights the (numerous) performance problems with this layout, as well as suggestions for fixing them. By clicking the "Alerts" tab, you will find that drawing this view hierarchy requires 80 expensive passes through the measure and layout phases!
Triggering that many expensive measure and layout phases is far from ideal; such a large amount of drawing activity could result in skipped frames that users notice. We can conclude that the layout has poor performance due to the nested hierarchy as well as the characteristic of RelativeLayout, which measures each of its children twice.
You can check the entire code on how we performed these measurements in our GitHub repository.
If you create the same layout using ConstraintLayout, the XML file contains an element hierarchy similar to the following (attributes again omitted):
<android.support.constraint.ConstraintLayout> <ImageView /> <ImageView /> <TextView /> <EditText /> <TextView /> <TextView /> <EditText /> <Button /> <Button /> <TextView /> </android.support.constraint.ConstraintLayout>
As this example shows, the layout now has a completely flat hierarchy. This is because ConstraintLayout allows you to build complex layouts without having to nest View and ViewGroup elements.
For example, let's look at the TextView and EditText in the middle of the layout:
TextView
EditText
<LinearLayout android:id="@+id/camera_area" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_below="@id/title" > <TextView android:text="@string/camera" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:id="@+id/cameraLabel" android:labelFor="@+id/cameraType" android:layout_marginStart="16dp" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/cameraType" android:ems="10" android:inputType="textPersonName" android:text="@string/camera_value" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginTop="8dp" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" /> </RelativeLayout> </LinearLayout>
By using ConstraintLayout instead, you can achieve the same effect just by adding a constraint from the baseline of the TextView to the baseline of the EditText without creating another ViewGroup:
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_creator="1" app:layout_constraintBaseline_creator="1" app:layout_constraintLeft_toLeftOf="@+id/activity_main_done" app:layout_constraintBaseline_toBaselineOf="@+id/cameraType" />
When running the Systrace tool for the version of our layout that uses ConstraintLayout, you see far fewer expensive measure/layout passes during the same 20-second interval. This improvement in performance makes sense, now that we're keeping the view hierarchy flat!
On a related note, we built the ConstraintLayout variant of our layout using just the layout editor instead of editing the XML by hand. To achieve the same visual effect using RelativeLayout, we probably would have needed to edit the XML by hand.
We analyzed how long every measure and layout pass took for two type of layouts, ConstraintLayout and RelativeLayout, by using OnFrameMetricsAvailableListener, which was introduced in Android 7.0 (API level 24). This class allows you to collect frame-by-frame timing information about your app's UI rendering.
OnFrameMetricsAvailableListener
By calling the following code, you can start recording per-frame UI actions:
window.addOnFrameMetricsAvailableListener( frameMetricsAvailableListener, frameMetricsHandler);
After timing information becomes available, the app triggers the frameMetricsAvailableListener() callback. We are interested in the measure/layout performance, so we call FrameMetrics.LAYOUT_MEASURE_DURATION when retrieving the actual frame duration.
frameMetricsAvailableListener()
FrameMetrics.LAYOUT_MEASURE_DURATION
Window.OnFrameMetricsAvailableListener { _, frameMetrics, _ -> val frameMetricsCopy = FrameMetrics(frameMetrics); // Layout measure duration in nanoseconds val layoutMeasureDurationNs = frameMetricsCopy.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION);
To learn more about the other types of duration information that FrameMetrics can receive, see the FrameMetrics API reference.
FrameMetrics
Our performance comparison shows that ConstraintLayout performs about 40% better in the measure/layout phase than RelativeLayout:
As these results show, ConstraintLayout is likely to be more performant than traditional layouts. Moreover, ConstraintLayout has other features that help you build complex and performant layouts, as discussed in the benefits of a ConstraintLayout object section. For details, see the Build a Responsive UI with ConstraintLayout guide. We recommend that you use ConstraintLayout when designing your app's layouts. In almost all cases when you would have previously need a deeply-nested layout, ConstraintLayout should be your go-to layout for optimal performance and ease of use.
All the measurements above were performed in the following environment.
Check out the developer guide, the API reference documentation, and the article on Medium to fully understand what ConstraintLayout can provide for you. And once again, thank you to all who submitted feedback and issues over the months since our alpha release of ConstraintLayout. We're truly grateful that we were able to release the production-ready 1.0 version of ConstraintLayout earlier this year. As we continue to improve ConstraintLayout, please continue to send us feedback using the Android issue tracker.
Posted by Hoi Lam, Android Wear Developer Advocate
Android Wear is about choice. From the beginning, users could choose the style they wanted, including watches with circular screens. With Android Wear API 23, we have enabled even better developer support so that you can code delightful experiences backed by beautiful code. The key component of this is the new round resource identifier which helps you separate resource files such as layouts, dimens between round and square devices. In this blog post, I will lay out the options that developers have and why you should consider dimens.xml! In addition, I will outline how best to deal with devices which have a chin.
If all your content can fit into a single square screen, use the BoxInsetLayout. This class has been included in the Wearable Support Library from the start and helps you put all the content into the middle square area of the circular screen and is ignored by square screens. For details on how to use the BoxInsetLayout, refer to the Use a Shape-Aware Layout section in our developer guide.
Developers have been able to specify different layouts for square and round watches using WatchViewStub from the beginning. With Android Wear API 23, this has become even easier. Developers can put different layouts into layout-round and layout folders. Previously with WatchViewStub, developers needed to wait until the layout was inflated before attaching view elements, this added significant complexity to the code. This is eliminated using the -round identifier:
Pre Android Wear API 23 - WatchViewStub (4 files)
<?xml version="1.0" encoding="utf-8"?> <android.support.wearable.view.WatchViewStub xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/watch_view_stub" android:layout_width="match_parent" android:layout_height="match_parent" app:rectLayout="@layout/rect_activity_main" app:roundLayout="@layout/round_activity_main" tools:context="com.android.example.watchviewstub.MainActivity" tools:deviceIds="wear"></android.support.wearable.view.WatchViewStub>
2. layout/rect_activity_main.xml - layout for square watches
3. layout/round_activity_main.xml - layout for round watches
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { @Override public void onLayoutInflated(WatchViewStub stub) { mTextView = (TextView) stub.findViewById(R.id.text); } }); }
After Android Wear API 23 - layout-round (3 files)
1. layout-notround/activity_main.xml - layout for square watches
2. layout-round/activity_main.xml - layout for round watches
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.text); }
That said, since WatchViewStub is part of the Android Wear Support Library, if your current code uses it, it is not a breaking change and you can refactor your code at your convenience. In addition to the -round identifier, developers also use the -notround idenifier to separate resources. So why would you want to use it in place of the default layout? It’s a matter of style. If you have a mixture of layouts, you might consider organising layouts in this way:
Maintaining multiple layout files is potentially painful. Each time you add a screen element, you need to go to all the layout files and add this. With mobile devices, you will usually only do this to specify different layouts for phones and tablets and rarely for different phone resolutions. For watches, unless your screen layout is significantly different between round and square (which is rare based on the applications I have seen thus far), you should consider using different dimens.xml instead.
As I experimented with the -round identifier, I found that the easiest way to build for round and square watches is actually by specifying values/dimens.xml and values-round/dimens.xml. By specifying different padding settings, I am able to create the following layout with the same layout.xml file and two dimens files - one for square and one for round. The values used suits this layout, you should experiment with different values to see what works best:
<dimen name="header_start_padding">36dp</dimen> <dimen name="header_end_padding">22dp</dimen> <dimen name="list_start_padding">36dp</dimen> <dimen name="list_end_padding">22dp</dimen>
<dimen name="header_start_padding">16dp</dimen> <dimen name="header_end_padding">16dp</dimen> <dimen name="list_start_padding">10dp</dimen> <dimen name="list_end_padding">10dp</dimen>
Before API 23, to do the same would have involved a significant amount of boilerplate code manually specifying the different dimensions for all elements on the screen. With the -round identifier, this is now easy to do in API 23 and is my favourite way to build round / square layouts.
Some watches have an inset (also know as a “chin”) in an otherwise circular screen. So how should you can you build a beautiful layout while keeping your code elegant? Consider this design:
activity_main.xml
<FrameLayout ...> <android.support.wearable.view.CircledImageView android:id="@+id/androidbtn" android:src="@drawable/ic_android" .../> <ImageButton android:id="@+id/lovebtn" android:src="@drawable/ic_favourite" android:paddingTop="5dp" android:paddingBottom="5dp" android:layout_gravity="bottom" .../> </FrameLayout>
If we are to do nothing, the heart shape button will disappear into the chin. Luckily, there’s an easy way to fix this with fitsSystemWindows:
<ImageButton android:id="@+id/lovebtn" android:src="@drawable/ic_favourite" android:paddingTop="5dp" android:paddingBottom="5dp" android:fitsSystemWindows="true" .../>
For the eagle-eyed (middle image of the screen shown below under “fitsSystemWindows=”true””), you might noticed that the top and bottom padding that we have put in is lost. This is one of the main side effect of using fitsSystemWindows. This is because fitsSystemWindows works by overriding the padding to make it fits the system window. So how do we fix this? We can replace padding with InsetDrawables:
inset_favourite.xml
<inset xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_favourite" android:insetTop="5dp" android:insetBottom="5dp" />
<ImageButton android:id="@+id/lovebtn" android:src="@drawable/inset_favourite" android:paddingTop="5dp" android:paddingBottom="5dp" android:fitsSystemWindows="true" .../>
Although the padding setting in the layout will be ignored, the code is tidier if we remove this redundant code.
If you require more control than what is possible declaratively using xml, you can also programmatically adjust your layout. To obtain the size of the chin you should attach a View.OnApplyWindowInsetsListener to the outermost view of your layout. Also don’t forget to call v.onApplyWindowInsets(insets). Otherwise, the new listener will consume the inset and inner elements which react to insets may not react.
How to obtain the screen chin size programmatically
MainActivity.java
private int mChinSize; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // find the outermost element final View container = findViewById(R.id.outer_container); // attach a View.OnApplyWindowInsetsListener container.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @Override public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { mChinSize = insets.getSystemWindowInsetBottom(); // The following line is important for inner elements which react to insets v.onApplyWindowInsets(insets); return insets; } }); }
Last but not least, remember to test your code! Since last year, we have included several device images for Android Wear devices with a chin to make testing easier and faster:
Android Wear has always been about empowering users to wear what they want. A major part in enabling this is the round screen. With API 23 and the -round resource identifier, it is easier than ever to build for both round and square watches - delightful experiences backed by beautiful code!
Why would I want to fitsSystemWindows? by Ian Lake - Best practice for using this powerful tool including its limitations. ScreenInfo Utility by Wayne Piekarski - Get useful information for your display including DPI, chin size, etc.
[This post is by Android designer Alex Faaborg, on behalf of the entire User Experience team. —Tim Bray]
When we initially released Android Design, by far the number one request we received was for us to release stencils as well. The fine folks on the Android User Experience team are pleased today to release some official Android Design stencils for your mockup-creating pleasure.
With these stencils you can now drag and drop your way to beautifully designed Ice Cream Sandwich (Android 4.0) applications, with grace and ease. The stencils feature the rich typography, colors, interactive controls, and icons found throughout Ice Cream Sandwich, along with some phone and tablet outlines to frame your meticulously crafted creations.
Currently we have stencils available for those venerable interactive design powerhouses Adobe® Fireworks®, and Omni® OmniGraffle® and we may expand to other applications® in the future. The source files for the various icons and controls are also available, created in Adobe® Photoshop®, and Adobe® Illustrator®. Here are the downloads.
We’ll be updating these stencils over time so, as always, please send in your feedback!
Happy mockup making, — Your friendly Android Design Droids
Android 4.0 showcases the Holo theme family, further refined since its debut in Android 3.0. But as most developers know, a new system theme for some Android devices isn’t a new or uncommon event. For developers new system themes mean more design targets for their apps. Using system themes means developers can take advantage of a user’s existing expectations and it can save a lot of production time, but only if an app designer can reliably predict the results. Before Android 4.0 the variance in system themes from device to device could make it difficult to design an app with a single predictable look and feel. We set out to improve this situation for the developer community in Ice Cream Sandwich and beyond.
In Android 4.0, Holo is different. We’ve made the inclusion of the unmodified Holo theme family a compatibility requirement for devices running Android 4.0 and forward. If the device has Android Market it will have the Holo themes as they were originally designed.
This standardization goes for all of the public Holo widget styles as well. The Widget.Holo styles will be stable from device to device, safe for use as parent styles for incremental customizations within your app.
The Holo theme family in Android 4.0 consists of the themes Theme.Holo, Theme.Holo.Light, and Theme.Holo.Light.DarkActionBar. Examples of these themes in action are shown in the screenshots lining this post.
To use a Holo theme, explicitly request one from your manifest on your activity or application element, e.g. android:theme="@android:style/Theme.Holo". Your app will be displayed using the unmodified theme on all compatible Android 4.0 devices. The Holo themes may also be used as stable parent themes for app-level theme customizations.
android:theme="@android:style/Theme.Holo"
We have no desire to restrict manufacturers from building their own themed experience across their devices. In fact we’ve gone further to make this even easier. In Android 4.0’s API (level 14) we’ve added a new public theme family to complement the Holo family introduced in Android 3.0: DeviceDefault. DeviceDefault themes are aliases for the device’s native look and feel. The DeviceDefault theme family and widget style family offer ways for developers to target the device’s native theme with all customizations intact.
Formally separating these theme families will also make future merges easier for manufacturers updating to a new platform version, helping more devices update more quickly. Google’s Nexus devices alias DeviceDefault to the unmodified Holo themes.
We’ve added a number of theme attributes to report common metrics and color palette info to apps that want to fit in with a theme. These include highlight colors, default padding and margins for common UI elements such as list items, and more. Apps that wish to integrate with their chosen theme (both Holo and DeviceDefault included) can refer to these theme attributes as in the examples below:
<ImageButton android:id="@+id/my_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/button_icon" android:background="?android:attr/selectableItemBackground" />
<MyWidget android:layout_width="wrap_content" android:layout_height="wrap_content" myapp:pressedHighlightColor="?android:attr/colorPressedHighlight" />
<LinearLayout android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" android:paddingRight="?android:attr/listPreferredItemPaddingRight"> <TextView android:id="@+id/text" android:textAppearance="?android:attr/textAppearanceListItem" /> <!-- Other views here --> </LinearLayout>
If an app does not explicitly request a theme in its manifest, Android 4.0 will determine the default theme based on the app’s targetSdkVersion to maintain the app’s original expectations: For values less than 11, @android:style/Theme; between 11 and 13 @android:style/Theme.Holo; and for 14 and higher @android:style/Theme.DeviceDefault.
@android:style/Theme
@android:style/Theme.Holo
@android:style/Theme.DeviceDefault
Most Android developers will still want to support 2.x devices for a while as updates and new devices continue to roll out. This doesn’t stop you from taking advantage of newer themes on devices that support them though. Using Android’s resource system you can define themes for your app that are selected automatically based on the platform version of the device it’s running on.
Theme.Holo and Theme.Holo.Light have been available since API level 11, but Theme.Holo.Light.DarkActionBar is new in API level 14.
<resources> <style name="MyTheme" parent="@android:style/Theme"> <!-- Any customizations for your app running on pre-3.0 devices here --> </style> </resources>
<resources> <style name="MyTheme" parent="@android:style/Theme.Holo"> <!-- Any customizations for your app running on devices with Theme.Holo here --> </style> </resources>
<!-- [...] --> <application android:name="MyApplication" android:label="@string/application_label" android:icon="@drawable/app_icon" android:hardwareAccelerated="true" android:theme="@style/MyTheme"> <!-- [...] -->
You can go as far with this idea as you like, up to and including defining your own theme attributes with different values across configurations for use in your other resources. To learn more about Android’s resource system, see Application Resources.
Android apps running on 4.0 and forward can use the Holo themes and be assured that their look and feel will not change when running on a device with a custom skin. Apps that wish to use the device’s default styling can do so using the DeviceDefault themes that are now in the public API. These changes let you spend more time on your design and less time worrying about what will be different from one device to another. Finally, Android’s resource system allows you to support features from the latest platform version while offering graceful fallback on older devices.
[This post is by Philip Milne, who is part of the Android framework team. — Tim Bray]
Ice Cream Sandwich (ICS) sports two new widgets that have been designed to support the richer user interfaces made possible by larger displays: Space and GridLayout.
The most commonly used class for layout in Android is LinearLayout, which allows its children to be aligned in the usual ways: along either the horizontal or vertical axes. It’s often possible to take a complicated layout and break it down into a set of nested linear layouts and, provided this nesting doesn’t get too deep, this is still a good choice for many simple layouts.
A number of posts and articles (e.g. Android Layout Tricks #1, Flattening The Stack) have highlighted drawbacks of nested layouts; which fall into three basic categories:
Inability to control alignment along both axes simultaneously
Performance problems in hierarchies that are too deep
Unsuitability for design tools that support free-form editing
A simple example of the first problem is the following form:
As the font and the text of the “Email address” label change, we want the label to remain aligned with the baseline of the component to its right, and aligned with the right edge of the label below it. It’s not possible to do this with nested LinearLayouts because the label needs to be aligned with other components both horizontally and vertically.
These problems aren’t new to Android, or UI toolkits in general, but we’ve used them to drive our work in enriching platform support for flatter hierarchies.
To provide better support for layouts like these we have added a new layout to the Android framework: GridLayout, which can be used to solve the above problems by dividing the container’s real estate into rows and columns:
Now the “Email address” label can belong both to a row that is baseline-aligned, and a column that is right-aligned.
GridLayout uses a grid of infinitely-thin lines to separate its drawing area into: rows, columns, and cells. It supports both row and column spanning, which together allow a widget to occupy a rectangular range of cells that are next to each other. We’ll use the words row, column, and cell in the text below as shorthand for row group, column group and cell group respectively, where groups have one or more contiguous elements.
Wherever possible, GridLayout uses the same conventions as LinearLayout for all its XML API — so it should be easy to start using GridLayout if you’ve already used LinearLayout. In fact, the APIs are so similar that changing a tag name from LinearLayout to GridLayout in an XML file that uses LinearLayout will often produce a similar UI without requiring any other changes. When it doesn’t, you’ll still generally end up with a good starting point for a two-dimensional layout.
Two examples in the samples area of the Android 4.0 SDK show typical use of the programmatic and XML APIs respectively:
samples/ApiDemos/src/com/example/android/apis/view/GridLayout0.java
samples/ApiDemos/res/layout/grid_layout_1.xml
[Both examples produce the same UI.]
Here’s a slightly simpler version of the above XML layout.
<?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:useDefaultMargins="true" android:alignmentMode="alignBounds" android:columnOrderPreserved="false" android:columnCount="4" > <TextView android:text="Email setup" android:textSize="32dip" android:layout_columnSpan="4" android:layout_gravity="center_horizontal" /> <TextView android:text="You can configure email in just a few steps:" android:textSize="16dip" android:layout_columnSpan="4" android:layout_gravity="left" /> <TextView android:text="Email address:" android:layout_gravity="right" /> <EditText android:ems="10" /> <TextView android:text="Password:" android:layout_column="0" android:layout_gravity="right" /> <EditText android:ems="8" /> <Space android:layout_row="4" android:layout_column="0" android:layout_columnSpan="3" android:layout_gravity="fill" /> <Button android:text="Next" android:layout_row="5" android:layout_column="3" /> </GridLayout>
The first difference you’ll notice in these examples is the absence of the WRAP_CONTENT and MATCH_PARENT constants that normally adorn Android layout resources. You don’t normally need to use these with GridLayout, for reasons that are described in the API doc for GridLayout.LayoutParams.
The second thing you may notice in the XML resources is that widgets don’t always explicitly define which cells they are to be placed in. Each widget’s layout parameters have row and column indices that together define where the widget should be placed but when either or both of these values are not specified, GridLayout supplies default values rather than throwing an exception.
As children are added to a GridLayout, it maintains a cursor position and a “high-water mark” that it uses to place widgets in cells that don’t yet have anything in them.
When GridLayout’s orientation property is horizontal and a columnCount has been set (to 8 in this example) the high-water mark (shown above in red) is maintained as a separate height value for each column. When indices need to be created, GridLayout first determines the size of the cell group (by looking at the rowSpan and columnSpan parameters of the new widget) and then, starting at the cursor, goes through the available locations from: left to right, top to bottom, so as to find the row and column indices of the first location that’s free.
horizontal
When GridLayout’s orientation is vertical, all of the same principles apply, except that the roles of the horizontal and vertical axes are exchanged.
vertical
If you want multiple views to be placed in the same cell, you have to define the indices explicitly, as the default allocation procedure above is designed to place widgets in separate cells.
In GridLayout, specifying sizes and margins is done just as with a LinearLayout. Alignment/gravity also works just like gravity in LinearLayout and uses the same constants: left, top, right, bottom, center_horizontal, center_vertical, center, fill_horizontal, fill_vertical and fill.
Unlike most grids in other toolkits, GridLayout does not associate data with rows or columns. Instead, everything to do with alignment and flexibility is associated with the components themselves. GridLayout departs from the norm here to provide a more general system that allows subtle relationships between ancestors in deeply nested layouts to be accommodated in a single layout configuration.
The flexibility of columns is inferred from the gravity of the components inside the column. If every component defines a gravity, the column is taken as flexible, otherwise the column is considered inflexible. Full details are in GridLayout’s API docs.
GridLayout does not incorporate all of the features of every layout in the Android platform but it has a rich enough feature set that idiomatic use of other layouts can normally be emulated from inside a single GridLayout.
Although LinearLayout can be considered a special case of a GridLayout, for the degenerate case when a set of views are aligned in a single row or column, LinearLayout is the better choice when this is all that is required as it clarifies the purpose of the container and may have some (relatively small) performance advantages.
TableLayout configurations are normally straightforward to accommodate, as GridLayout supports both row and column spanning. TableRows can be removed, as they are not required by GridLayout. For the same UI, a GridLayout will generally be faster and take less memory than than a TableLayout.
Simple RelativeLayout configurations can be written as grids simply by grouping the views that are related to each other into rows and columns. Unlike conventional grids, GridLayout uses a constraints solver to do the heavy lifting of the layout operation. By using GridLayout’s rowOrderPreserved and columnOrderPreserved properties it’s possible to free GridLayout from the confines of traditional grid systems and support the majority of RelativeLayout configurations — even ones that require grid lines to pass over each other as children change size.
Simple FrameLayout configurations can be accommodated within the cells of a GridLayout because a single cell can contain multiple views. To switch between two views, place them both in the same cell and use the visibility constant GONE to switch from one to the other from code. As with the LinearLayout case above, if all you need is the functionality described above, FrameLayout is the better choice and may have some small performance advantages.
One key feature that GridLayout lacks is the ability to distribute excess space between rows or columns in specified proportions — a feature that LinearLayout provides by supporting the principle of weight. This omission and possible ways around it are discussed in GridLayout’s API docs.
It’s useful to distinguish the allocation phase for cell indices discussed above from the layout operation itself. Normally the phase that allocates indices happens once, if at all, when a UI is initialized. The index-allocation phase only applies when indices have been left unspecified, and is responsible for ensuring that all views have a defined set of cells in which they are to be placed at layout time.
The layout operation happens after this and is recalculated each time a view changes size. GridLayout measures the size of each child during the layout operation so it can calcuate the heights and widths of the rows and columns in the grid. The layout phase completes by using gravity to place each of the components in its cell.
Although index allocation normally only happens once, GridLayout is technically a dynamic layout, meaning that if you change its orientation property or add or remove children after components have been laid out, GridLayout will repeat the above procedure to reallocate indices in a way that is right for the new configuration.
From a performance standpoint, it is worth knowing that the GridLayout implementation has been optimized for the common case, when initialization happens once and layout happens frequently. As a result, the initialization step sets up internal data structures so that the layout operation can complete quickly and without allocating memory. Put another way, changes either to GridLayout’s orientation or the number of children it has are much more expensive than an ordinary layout operation.
GridLayout’s feature set incorporates much of the functionality of the Android framework’s existing general-purpose layouts: LinearLayout, FrameLayout, TableLayout and RelativeLayout. As such, it provides a way to replace many deeply nested view hierarchies with a single highly optimized layout implementation.
If you are starting a UI from scratch and are not familiar with Android layouts, use a GridLayout — it supports most of the features of the other layouts and has a simpler and more general API than either TableLayout or RelativeLayout.
We anticipate that the combination of FrameLayout, LinearLayout and GridLayout together will provide a feature set that’s rich enough to allow most layout problems to be solved without writing layout code by hand. It’s worth spending some time deciding which of these layouts is right for the top of your tree; a good choice will minimize the need for intermediate containers and result in a user interface that is faster and uses less memory.