How many lines of code will it take to let your users say Ok Google, and search for something in your app? Hardly any. Starting today, all you need is a small addition to your AndroidManifest.xml in order to connect the Google Now SEARCH_ACTION with your searchable activity:
AndroidManifest.xml
SEARCH_ACTION
<activity android:name=".SearchableActivity"> <intent-filter> <action android:name="com.google.android.gms.actions.SEARCH_ACTION"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
Once you make these changes, your app can receive the SEARCH_ACTION intent containing the SearchManager.QUERY extra with the search expression.
SearchManager.QUERY
At Google, we always look for innovative ways to help you improve mobile search and drive user engagement back to your app. For example, users can now say to the Google app: “Ok Google, search pizza on Eat24” or “Ok Google, search for hotels in Maui on TripAdvisor.”
This feature is available on English locale Android devices running Jelly Bean and above with the Google app v3.5 or greater. Last but not least, users can enable the Ok Google hot-word detection from any screen, which offers them the fastest route between their search command and your app!
Since we published this post in 2014, we’ve made a lot of updates to the Google Sign-In APIs, deprecating much of this information.
Check out these posts instead:
API Updates for Google Sign-In
Updates on the contents of this post are found here: Using Google Sign-In on your Server
Using Credentials between your Server and Google Services
Happy Tuesday! We've had a few questions come in recently regarding Google Accounts on Android, so we've put this post together to show you some of our best practices. The tips today will focus on Android-based authentication, which is easily achieved through the integration of Google Play services. Let's get started.
A common confusion happens when developers use the account name (a.k.a. email address) as the primary key to a Google Account. For instance, when using GoogleApiClient to sign in a user, a developer might use the following code inside of the onConnected callback for a registered GoogleApiClient.ConnectedCallbacks listener:
String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient); // createLocalAccount() is specific to the app's local storage strategy. createLocalAccount(accountName);
While it is OK to store the email address for display or caching purposes, it is possible for users to change the primary email address on a Google Account. This can happen with various types of accounts, but these changes happen most often with Google Apps For Work accounts.
So what's a developer to do? Use the Google Account ID (as opposed to the Account name) to key any data for your app that is associated to a Google Account. For most apps, this simply means storing the Account ID and comparing the value each time the onConnected callback is invoked to ensure the data locally matches the currently logged in user. The API provides methods that allow you to get the Account ID from the Account Name. Here is an example snippet you might use:
String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient); String accountID = GoogleAuthUtil.getAccountId(accountName); createLocalAccount(accountID);
Person currentUser = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient); String accountID = currentUser.getID(); createLocalAccount(accountID);
This will key the local data against a Google Account ID, which is unique and stable for the user even after changing an email address.
So, in the above scenario, if your data was keyed on an ID, you wouldn’t have to worry if your users change their email address. When they sign back in, they’ll still get the same ID, and you won’t need to do anything with your data.
If your app supports multiple account connections simultaneously (like the Gmail user interface shown below), you are calling setAccountName on the GoogleApiClient.Builder when constructing GoogleApiClients. This requires you to store the account name as well as the Google Account ID within your app. However, the account name you’ve stored will be different if the user changes their primary email address. The easiest way to deal with this is to prompt the user to re-login. Then, update the account name when onConnected is called after login. Any time a login occurs you, can use code such as this to compare Account IDs and update the email address stored locally for the Account ID.
String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient); String accountID = GoogleAuthUtil.getAccountId(accountName); // isExistingLocalAccount(), createLocalAccount(), // getLocalDataAccountName(), and updateLocalAccountName() // are all specific to the app's local storage strategy. boolean existingLocalAccountData = isExistingLocalAccount(accountID); if (!existingLocalAccountData) { // New Login. createLocalAccount(accountID, accountName); } else { // Existing local data for this Google Account. String cachedAccountName = getLocalDataAccountName(accountID); if (!cachedAccountName.equals(accountName)) { updateLocalAccountName(accountID, accountName); } }
This scenario reinforces the importance of using the Account ID to store data all data in your app.
The same best practices above apply to storing data for Google Accounts in web servers for your app. If you are storing data on your servers in this manner and treating the email address as the primary key:
ID [Primary Key] Field 1 Field 2 Field 3 user1@gmail.com Value 1 Value 2 Value 3
You need to migrate to this model where the primary key is the Google Account ID.:
ID [Primary Key] Email Field 1 Field 2 Field 3 108759069548186989918 user1@gmail.com Value 1 Value 2 Value 3
If you don't make Google API calls from your web server, you might be able to depend on the Android application to notify your web server of changes to the primary email address when implementing the updateLocalAccountName method referenced in the multiple accounts sample code above. If you make Google API calls from your web server, you likely implemented it using the Cross-client authentication and can detect changes via the OAuth2 client libraries or REST endpoints on your server as well.
When using Google Account authentication for your app, it’s definitely a best practice to use the account ID, as opposed to the account name to distinguish data for the user. In this post, we saw three scenarios where you may need to make changes to make your apps more robust. With the growing adoption of Google for Work, users who are changing their email address, but keeping the same account ID, may occur more frequently, so we encourage all developers to make plans to update their code as soon as possible.
By Roman Nurik, Design Advocate
Android 5.0 brings in material design as the new design system for the platform and system apps. Consumers will soon start getting Android 5.0 and they’re already seeing glimpses of material design with apps like Google Play Newsstand, Inbox by Gmail and Tumblr. Meanwhile, developers now have the Android 5.0 SDK, along with AppCompat for backward compatibility. And designers now have access to Photoshop, Illustrator and Sketch templates. All this means that now—yes now!—is the time to start implementing material design in your Android apps. Today, let’s talk about what implementing material design really boils down to.
Below, you’ll find a material design checklist that you can use to mark progress as you implement the new design system. The checklist is divided into 4 key sections based on the 4 key aspects of material design.
If you include a good chunk of the items in the checklist below, especially the ones indicated as signature elements, and follow traditional Android design best practices (i.e. these, these, and things we discussed on ADiA), you’ll be well on your way to material design awesomeness!
android:elevation
android:translationZ
android:clipToPadding=false
ListView
ScrollView
android:colorPrimary
android:colorAccent
android
android:colorPrimaryDark
android:statusBarColor
Window.setStatusBarColor
Toolbar
FragmentTransaction
android:selectableItemBackground
android:selectableItemBackgroundBorderless
RippleDrawable
<ripple>
ViewAnimationUtils
AnimatedStateListDrawable
android.support.v7.widget.Toolbar
android:contentInsetStart
ViewPager
DrawerLayout
More and more apps from Google and across the Google Play ecosystem will be updating with material design soon, so expect Winter 2014 to be a big quarter for design on Android. For more designer resources on material design, check out the DesignBytes series. For additional developer resources, check the Creating Apps with Material Design docs!
Material design is a comprehensive approach to visual, interaction and motion design for the multi-screen world. Android 5.0 Lollipop and the updated support libraries help you to create material UIs. Here’s a rundown of some of the major elements of material design and the APIs and widgets that you can use to implement them in your app.
In material design, UIs are composed of pieces of digital paper & ink. The surfaces and the shadows they cast provide visual cues to the structure of the application, what you can touch and how it will move. This digital material can move, expand and reform to create flexible UIs.
A surface’s position and depth result in subtle changes in lighting and shadows. The new elevation property lets you specify a view’s position on the Z-axis and the framework then casts a real-time dynamic shadow on items behind it. You can set the elevation declaratively in your layouts, defined in dips:
<ImageView … android:elevation="8dp" />
You can also set this from code using getElevation()/setElevation() (with shims in ViewCompat). The shadow a view casts is defined by its outline, which by default is derived from its background. For example if you set a circular shape drawable as the background for a floating action button, then it would cast an appropriate shadow. If you need finer control of a view’s shadow, you can set a ViewOutlineProvider which can customise the Outline in getOutline().
getElevation()/setElevation()
ViewOutlineProvider
Outline
getOutline()
Cards are a common pattern for creating surfaces holding a distinct piece of information. The new CardView support library allows you to create them easily, providing outlines and shadows for you (with equivalent behaviour on prior platforms).
<android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content"> <!-- Your card content --> </android.support.v7.widget.CardView>
CardView extends FrameLayout and provides default elevation and corner radius for you so that cards have a consistent appearance across the platform. You can customise these via the cardElevation and cardCornerRadius attributes, if required. Note that Cards are not the only way of achieving dimensionality and you should be wary of over-cardifying your UI!
CardView
FrameLayout
cardElevation
cardCornerRadius
Material utilises classic principles from print design to create clean, simple layouts that put your content front and center. Bold deliberate color choices, intentional whitespace, tasteful typography and a strong baseline grid create hierarchy, meaning and focus.
Android 5.0 updates the system font Roboto to beautifully and clearly display text no matter the display size. A new medium weight has been added (android:fontFamily=”sans-serif-medium”) and new TextAppearance styles implement the recommended typographic scale for balancing content density and reading comfort. For instance you can easily use the ‘Title’ style by setting android:textAppearance=”@android:style/TextAppearance.Material.Title”. These styles are available on older platforms through the AppCompat support library, e.g. “@style/TextAppearance.AppCompat.Title”.
android:fontFamily=”sans-serif-medium”
android:textAppearance=”@android:style/TextAppearance.Material.Title”
@style/TextAppearance.AppCompat.Title
Your application’s color palette brings branding and personality to your app so we’ve made it simple to colorize UI controls by using the following theme attributes:
colorPrimary
colorAccent
colorPrimaryDark
Further attributes give fine grained control over colorizing controls, see: colorControlNormal, colorControlActivated, colorControlHighlight, colorButtonNormal, colorSwitchThumbNormal, colorEdgeEffect, statusBarColor and navigationBarColor.
colorControlNormal
colorControlActivated
colorControlHighlight
colorButtonNormal
colorSwitchThumbNormal
colorEdgeEffect
statusBarColor
navigationBarColor
AppCompat provides a large subset of the functionality above, allowing you to colorize controls on pre-Lollipop platforms.
Material Design encourages dynamic use of color, especially when you have rich images to work with. The new Palette support library lets you extract a small set of colors from an image to style your UI controls to match; creating an immersive experience. The extracted palette will include vibrant and muted tones as well as foreground text colors for optimal legibility. For example:
Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { Palette.Swatch vibrant = palette.getVibrantSwatch(); if (swatch != null) { // If we have a vibrant color // update the title TextView titleView.setBackgroundColor( vibrant.getRgb()); titleView.setTextColor( vibrant.getTitleTextColor()); } } });
Tangible surfaces don’t just appear out of nowhere like a jump-cut in a movie; they move into place helping to focus attention, establish spatial relationships and maintain continuity. Materials respond to touch to confirm your interaction and all changes radiate outward from your touch point. All motion is meaningful and intimate, aiding the user’s comprehension.
By declaring ‘shared elements’ that are common across two screens you can create a smooth transition between the two states.
album_grid.xml … <ImageView … android:transitionName="@string/transition_album_cover" /> album_details.xml … <ImageView … android:transitionName="@string/transition_album_cover" /> AlbumActivity.java Intent intent = new Intent(); String transitionName = getString(R.string.transition_album_cover); … ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, albumCoverImageView, // The view which starts the transition transitionName // The transitionName of the view we’re transitioning to ); ActivityCompat.startActivity(activity, intent, options.toBundle());
Here we define the same transitionName in two screens. When starting the new Activity and this transition is animated automatically. In addition to shared elements, you can now also choreograph entering and exiting elements.
transitionName
Materials respond to users’ touch with an ink ripple surface reaction. Interactive controls such as Buttons exhibit this behaviour by default when you use or inherit from Theme.Material (as will ?android:selectableItemBackground). You can add this feedback to your own drawables by simply wrapping them in a ripple element:
Theme.Material
?android:selectableItemBackground
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/accent_dark"> <item> <shape android:shape="oval"> <solid android:color="?android:colorAccent" /> </shape> </item> </ripple>
Custom views should propagate touch location down to their drawables in the View#drawableHotspotChanged callback so that the ripple can start from the touch point.
View#drawableHotspotChanged
Materials also respond to touch by raising up to meet your finger, like a magnetic attraction. You can achieve this effect by animating the translationZ attribute which is analogous to elevation but intended for transient use; such that Z = elevation + translationZ. The new stateListAnimator attribute allows you to easily animate the translationZ on touch (Buttons do this by default):
Z = elevation + translationZ
stateListAnimator
translationZ
layout/your_layout.xml <ImageButton … android:stateListAnimator="@anim/raise" /> anim/raise.xml <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="true" android:state_pressed="true"> <objectAnimator android:duration="@android:integer/config_shortAnimTime" android:propertyName="translationZ" android:valueTo="@dimen/touch_raise" android:valueType="floatType" /> </item> <item> <objectAnimator android:duration="@android:integer/config_shortAnimTime" android:propertyName="translationZ" android:valueTo="0dp" android:valueType="floatType" /> </item> </selector>
A hallmark material transition for showing new content is to reveal it with an expanding circular mask. This helps to reinforce the user’s touchpoint as the start of all transitions, with its effects radiating outward radially. You can implement this using the following Animator:
Animator reveal = ViewAnimationUtils.createCircularReveal( viewToReveal, // The new View to reveal centerX, // x co-ordinate to start the mask from centerY, // y co-ordinate to start the mask from startRadius, // radius of the starting mask endRadius); // radius of the final mask reveal.start();
Motion should be deliberate, swift and precise. Unlike typical ease-in-ease-out transitions, in Material Design, objects tend to start quickly and ease into their final position. Over the course of the animation, the object spends more time near its final destination. As a result, the user isn’t left waiting for the animation to finish, and the negative effects of motion are minimized. A new fast-in-slow-out interpolator has been added to achieve this motion.
For elements entering and exiting the screen (which should do so at peak velocity), check out the linear-out-slow-in and fast-out-linear-in interpolators respectively.
Our final core concept of material is creating a single adaptive design that works across devices of all sizes and shapes, from watches to giant TVs. Adaptive design techniques help us realize the vision that each device reflects a different view of the same underlying system. Each view is tailored to the size and interaction appropriate for that device. Colors, iconography, hierarchy, and spatial relationships remain constant. The material design system provides flexible components and patterns to help you build a design that scales.
The toolbar is a generalization of the action bar pattern, providing similar functionality, but much more flexibility. Unlike the standard action bar, toolbar is a view in your hierarchy just like any other, so you can place instances wherever you like, interleave them with the rest of your views, animate, react to scroll events and so on. You can make the Toolbar act as your Activity’s Action Bar by calling Activity.setActionBar().
In this example, the blue toolbar is an extended height, overlaid by the screen content and provides the navigation button. Note that two further toolbars are used in the list and detail views.
For details of implementing toolbars, see this post.
Material Design helps you to build understandable, beautiful and adaptive apps, which are alive with motion. Hopefully, this post has inspired you to apply these principles to your app and signposted some of the new (and compatibility) APIs to achieve this.
By Katherine Kuan, Developer Advocate
Updated material design Tumblr app on Nexus 6.
Last week, we unveiled the Nexus 6 and Nexus 9, the newest additions to our Nexus family that will ship with Android 5.0 Lollipop. Together, they deliver a pure Google experience, showcasing fresh visual styles with material design, improved performance, and additional features.
Let’s make sure your apps and games are optimized to give your users the best mobile experience on these devices. We’ve outlined some best practices below.
The Nexus 6 boasts an impressive 5.96” Quad HD screen display at a resolution of 2560 x 1440 (493 ppi). This translates to ~ 730 x 410 dp (density independent pixels).
It has a quantized density of 560 dpi, which falls in between the xxhdpi and xxxhdpi primary density buckets. For the Nexus 6, the platform will scale down xxxhdpi assets, but if those aren’t available, then it will scale up xxhdpi assets.
xxhdpi
xxxhdpi
Provide at least an xxxhdpi app icon because devices can display large app icons on the launcher. It’s best practice to place your app icons in mipmap- folders (not the drawable- folders) because they are used at resolutions different from the device’s current density. For example, an xxxhdpi app icon can be used on the launcher for an xxhdpi device.
mipmap-
drawable-
res/ mipmap-mdpi/ ic_launcher.png mipmap-hdpi/ ic_launcher.png mipmap-xhdpi/ ic_launcher.png mipmap-xxhdpi/ ic_launcher.png mipmap-xxxhdpi/ ic_launcher.png # App icon used on Nexus 6 device launcher
Choosing to add xxxhdpi versions for the rest of your assets will provide a sharper visual experience on the Nexus 6, but does increase apk size, so you should make an appropriate decision for your app.
res/ drawable-mdpi/ ic_sunny.png drawable-hdpi/ ic_sunny.png drawable-xhdpi/ ic_sunny.png drawable-xxhdpi/ # Fall back to these if xxxhdpi versions aren’t available ic_sunny.png drawable-xxxhdpi/ # Higher resolution assets for Nexus 6 ic_sunny.png
If you are using the <compatible-screens> element in the AndroidManifest.xml file, you should stop using it because it’s not scalable to re-compile and publish your app each time new devices come out. However, if you must use it, make sure to update the manifest to add the configuration for these devices (by screen size and density). Otherwise your app may be excluded from Google Play search results on these devices.
<compatible-screens>
The Nexus 9 is a premium 8.9” tablet with a screen size of 2048 x 1536 pixels (288 ppi), which translates to 1024 x 768 dip. This is a 4:3 aspect ratio, which is unique compared to earlier tablets. The Nexus 9 falls into the xhdpi density bucket, and you should already have assets in the drawable-xhdpi folder.
xhdpi
drawable-xhdpi
Updated Material Design Wall Street Journal app on Nexus 9.
The Nexus 9 runs on a 64-bit Dual Core processor, which makes it the first Android device to ship with a 64-bit ARM instruction set. Support for 64-bit processors was just added in Android 5.0, so if you have an NDK app, enable it by updating the APP_ABI value in your Application.mk file:
APP_ABI
Application.mk
APP_ABI := armeabi armeabi-v7a arm64-v8a x86 x86_64 mips mips64
More detailed instructions are provided in the developer site. You can test your 64-bit enabled app on a physical device with a 64-bit processor running Android 5.0, or take advantage of the recently announced 64-bit emulator in Android Studio.
The Nexus 9 Keyboard Folio will be available as an accessory in Google Play. It’s very important that you don’t lock your app to a single orientation. The Nexus 9’s natural orientation is portrait mode, while it’s used in landscape mode with the keyboard. If you lock to the device’s natural orientation, the app may appear sideways for devices with keyboards.
Users should be able to navigate around the main content of the app with the keyboard, while relying on touch input or keyboard shortcuts for toolbar actions and button bars. Therefore, ensure that your app has proper keyboard navigation and shortcuts for primary actions. Keyboard shortcuts that are invoked with Ctrl + [shortcut] combo can be defined via menu items using:
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_create" android:title="@string/menu_create" android:alphabeticShortcut="c” /> </menu/>
Alternatively, shortcuts can be defined using Activity#onKeyShortcut or View#onKeyShortcut. Learn more about keyboard actions here.
Activity#onKeyShortcut
View#onKeyShortcut
In MainActivity.java: @Override public boolean onKeyShortcut(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_R: Toast.makeText(this, "Reply", Toast.LENGTH_SHORT).show(); return true; default: return super.onKeyShortcut(keyCode, event); } }
In order to take advantage of the screen real estate on the Nexus 6 and Nexus 9, we emphasize the importance of responsive design. In the past, if you assumed that landscape mode is significantly wider than portrait mode, you may run into problems on a device like the Nexus 9, which has an aspect ratio of 4:3. Instead of declaring layouts using the layout-land or layout-port resource folder qualifiers, we strongly recommend switching to the w<N>dp width resource folder qualifier so that content is laid out based on available screen width.
layout-land
layout-port
w<N>dp
Think about content first and foremost. Decide on min and max screen real estate that your content requires, and determine cutoff points at different screen widths where you can modify the layout composition for your app (# of grid columns, multi-pane layout, etc…).
For example, a single pane layout for your main activity on phones can be defined in:
res/layout/activity_main.xml
On larger screen devices, where the current orientation is at least 600dp in width, a new two-pane layout with a list alongside a detail pane could be declared in:
res/layout-w600dp/activity_main.xml
On even larger screen devices, where the current orientation is at least 720dp in width, a new multi-pane layout where the detail pane requires even more horizontal space could be declared in:
res/layout-w720dp/activity_main.xml
As for attributes based on form factor, instead of declaring them in values-large or values-xlarge resource directories, use the sw<N>dp smallest width qualifier. For example, you could style your TextViews to have a medium font size on phones.
sw<N>dp
In res/values/styles.xml: <style name="DescriptionTextStyle"> <item name="android:textAppearance">?android:attr/textAppearanceMedium</item> </style>
Meanwhile, TextViews could have a large font size when the smallest width of the device (taking the minimum of the landscape and portrait widths) is 600dp or wider. This ensures the font size of your app doesn’t change when you rotate this large screen device.
In res/values-sw600dp/styles.xml: <style name="DescriptionTextStyle"> <item name="android:textAppearance">?android:attr/textAppearanceLarge</item> </style>
Set your android:targetSdkVersion to "21". Take note of the important behavior changes in Android 5.0 Lollipop including ART, the new Android runtime, to ensure that your app continues to run well. You can also leverage new platform APIs like richer notifications.
android:targetSdkVersion
"21"
Nexus 6 and Nexus 9 users will be immersed in the new world of material design, and they’ll expect the same seamless transitions, bold colors, and delightful details from your app. As you invest time in bringing your app up to date with our latest design language, there’s a whole host of resources to help you make the leap, including important new updates to the support library, videos, and a getting started guide. Good luck and we can’t wait to see your apps!
By Wayne Piekarski, Developer Advocate
With the latest release of Android Wear, wearables with built-in GPS like the Sony Smartwatch 3 can now give you a GPS location update directly from the wearable, without a paired phone nearby. You can now build an app like MyTracks that lets a user track their run even when they leave their phone at home. For wearable devices that do not have built-in GPS, a software solution has always existed in Google Play Services that automatically uses the GPS from your connected phone.
The Golfshot wearable app uses built-in GPS to calculate your distance to the next hole, even when you don’t have your phone with you.
Implementing GPS location updates for Android Wear is simple. On the wearable, use the FusedLocationProviderApi from Google Play services to request location updates. This is the same API that has been available on mobile, so you can easily reuse your existing code and samples.
FusedLocationProviderApi
FusedLocationProviderApi automatically makes the most power-efficient decision about where to get location updates. If the phone is connected to the wearable, it uses the GPS on the phone and sends the updates to the wearable. If the phone is not connected to the wearable and the wearable has a built-in GPS, then it uses the wearable’s GPS.
One case you’ll need to handle is if the phone is not connected to the wearable and the wearable does not have built-in GPS. You will need to detect this and provide a graceful recovery mechanism, such as a message telling the user to bring their phone with them. However, for the most part, deciding which GPS to use, and sending the position from the phone to the wearable, is handled automatically. You do not need to deal with the low-level implementation details yourself.
When writing an app that runs on the wearable, you will eventually want to synchronize the data it collects with the paired phone. When the wearable is being taken out for a run, especially with the built-in GPS, there may not be a phone present. So you will want to store your location data using the Data Layer API, and when the phone reconnects with the wearable later, the data will be automatically synchronized.
For more details about how to use the location API, check out the extensive documentation and sample here.
Also, as a heads up, starting on November 3 with the public release of Android 5.0, you will be able to submit your apps for clearer designation as Android Wear apps on Google Play. If your apps follow the criteria in the Wear App Quality checklist and are accepted as Wear apps on Play, it will be easier for Android Wear users to discover your apps. Stay tuned for more information about how to submit your apps for Android Wear review through the Google Play Developer Console.
By Chris Banes, Android Developer Relations
The Android 5.0 SDK was released last Friday, featuring new UI widgets and material design, our visual language focused on good design. To enable you to bring your latest designs to older Android platforms we have expanded our support libraries, including a major update to AppCompat, as well as new RecyclerView, CardView and Palette libraries.
In this post we'll take a look at what’s new in AppCompat and how you can use it to support material design in your apps.
AppCompat (aka ActionBarCompat) started out as a backport of the Android 4.0 ActionBar API for devices running on Gingerbread, providing a common API layer on top of the backported implementation and the framework implementation. AppCompat v21 delivers an API and feature-set that is up-to-date with Android 5.0
In this release, Android introduces a new Toolbar widget. This is a generalization of the Action Bar pattern that gives you much more control and flexibility. Toolbar is a view in your hierarchy just like any other, making it easier to interleave with the rest of your views, animate it, and react to scroll events. You can also set it as your Activity’s action bar, meaning that your standard options menu actions will be display within it.
You’ve likely already been using the latest update to AppCompat for a while, it has been included in various Google app updates over the past few weeks, including Play Store and Play Newsstand. It has also been integrated into the Google I/O Android app, pictured above, which is open-source.
If you’re using Gradle, add appcompat as a dependency in your build.gradle file:
dependencies { compile "com.android.support:appcompat-v7:21.0.+" }
If you are not currently using AppCompat, or you are starting from scratch, here's how to set it up:
Theme.AppCompat
Light
NoActionBar
SpinnerAdapter
getSupportActionBar().getThemedContext()
MenuItemCompat
MenuItem
For more information, see the Action Bar API guide which is a comprehensive guide on AppCompat.
For most apps, you now only need one theme declaration, in values/:
values/
values/themes.xml: <style name="Theme.MyTheme" parent="Theme.AppCompat.Light"> <!-- Set AppCompat’s actionBarStyle --> <item name="actionBarStyle">@style/MyActionBarStyle</item> <!-- Set AppCompat’s color theming attrs --> <item name="colorPrimary">@color/my_awesome_red</item> <item name="colorPrimaryDark">@color/my_awesome_darker_red</item> <!-- The rest of your attributes --> </style>
You can now remove all of your values-v14+ Action Bar styles.
values-v14+
AppCompat has support for the new color palette theme attributes which allow you to easily customize your theme to fit your brand with primary and accent colors. For example:
values/themes.xml: <style name="Theme.MyTheme" parent="Theme.AppCompat.Light"> <!-- colorPrimary is used for the default action bar background --> <item name="colorPrimary">@color/my_awesome_color</item> <!-- colorPrimaryDark is used for the status bar --> <item name="colorPrimaryDark">@color/my_awesome_darker_color</item> <!-- colorAccent is used as the default value for colorControlActivated, which is used to tint widgets --> <item name="colorAccent">@color/accent</item> <!-- You can also set colorControlNormal, colorControlActivated colorControlHighlight, and colorSwitchThumbNormal. --> </style>
When you set these attributes, AppCompat automatically propagates their values to the framework attributes on API 21+. This automatically colors the status bar and Overview (Recents) task entry.
On older platforms, AppCompat emulates the color theming where possible. At the moment this is limited to coloring the action bar and some widgets.
When running on devices with Android 5.0, all of the widgets are tinted using the color theme attributes we just talked about. There are two main features which allow this on Lollipop: drawable tinting, and referencing theme attributes (of the form ?attr/foo) in drawables.
AppCompat provides similar behaviour on earlier versions of Android for a subset of UI widgets:
EditText
Spinner
CheckBox
RadioButton
Switch
android.support.v7.widget.SwitchCompat
CheckedTextView
You don’t need to do anything special to make these work, just use these controls in your layouts as usual and AppCompat will do the rest (with some caveats; see the FAQ below).
Toolbar is fully supported in AppCompat and has feature and API parity with the framework widget. In AppCompat, Toolbar is implemented in the android.support.v7.widget.Toolbar class. There are two ways to use Toolbar:
ActionBarDrawerToggle
To use Toolbar as an Action Bar, first disable the decor-provided Action Bar. The easiest way is to have your theme extend from Theme.AppCompat.NoActionBar (or its light variant).
Theme.AppCompat.NoActionBar
Second, create a Toolbar instance, usually via your layout XML:
<android.support.v7.widget.Toolbar android:id=”@+id/my_awesome_toolbar” android:layout_height=”wrap_content” android:layout_width=”match_parent” android:minHeight=”?attr/actionBarSize” android:background=”?attr/colorPrimary” />
The height, width, background, and so on are totally up to you; these are just good examples. As Toolbar is just a ViewGroup, you can style and position it however you want.
ViewGroup
Then in your Activity or Fragment, set the Toolbar to act as your Action Bar:
Activity
Fragment
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.blah); Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar); setSupportActionBar(toolbar); }
From this point on, all menu items are displayed in your Toolbar, populated via the standard options menu callbacks.
The difference in standalone mode is that you do not set the Toolbar to act as your action bar. For this reason, you can use any AppCompat theme and you do not need to disable the decor-provided Action Bar.
In standalone mode, you need to manually populate the Toolbar with content/actions. For instance, if you want it to display actions, you need to inflate a menu into it:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.blah); Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar); // Set an OnMenuItemClickListener to handle menu item clicks toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { // Handle the menu item return true; } }); // Inflate a menu to be displayed in the toolbar toolbar.inflateMenu(R.menu.your_toolbar_menu); }
There are many other things you can do with Toolbar. For more information, see the Toolbar API reference.
Styling of Toolbar is done differently to the standard action bar, and is set directly onto the view.
Here's a basic style you should be using when you're using a Toolbar as your action bar:
<android.support.v7.widget.Toolbar android:layout_height="wrap_content" android:layout_width="match_parent" android:minHeight="?attr/actionBarSize" app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />
The app:theme declaration will make sure that your text and items are using solid colors (i.e 100% opacity white).
app:theme
You can style Toolbar instances directly using layout attributes. To achieve a Toolbar which looks like 'DarkActionBar' (dark content, light overflow menu), provide the theme and popupTheme attributes:
theme
popupTheme
<android.support.v7.widget.Toolbar android:layout_height=”wrap_content” android:layout_width=”match_parent” android:minHeight=”@dimen/triple_height_toolbar” app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
AppCompat offers Lollipop’s updated SearchView API, which is far more customizable and styleable (queue the applause). We now use the Lollipop style structure instead of the old searchView* theme attributes.
SearchView
searchView*
Here’s how you style SearchView:
values/themes.xml: <style name=”Theme.MyTheme” parent=”Theme.AppCompat”> <item name=”searchViewStyle”>@style/MySearchViewStyle</item> </style> <style name=”MySearchViewStyle” parent=”Widget.AppCompat.SearchView”> <!-- Background for the search query section (e.g. EditText) --> <item name="queryBackground">...</item> <!-- Background for the actions section (e.g. voice, submit) --> <item name="submitBackground">...</item> <!-- Close button icon --> <item name="closeIcon">...</item> <!-- Search button icon --> <item name="searchIcon">...</item> <!-- Go/commit button icon --> <item name="goIcon">...</item> <!-- Voice search button icon --> <item name="voiceIcon">...</item> <!-- Commit icon shown in the query suggestion row --> <item name="commitIcon">...</item> <!-- Layout for query suggestion rows --> <item name="suggestionRowLayout">...</item> </style>
You do not need to set all (or any) of these, the defaults will work for the majority of apps.
Hopefully this post will help you get up and running with AppCompat and let you create some awesome material apps. Let us know in the comments/G+/Twitter if you’re have questions about AppCompat or any of the support libraries, or where we could provide more documentation.
The widget tinting in AppCompat works by intercepting any layout inflation and inserting a special tint-aware version of the widget in its place. For most people this will work fine, but I can think of a few scenarios where this won’t work, including:
new EditText()
The special tint-aware widgets are currently hidden as they’re an unfinished implementation detail. This may change in the future.
android:windowContentOverlay
getSupportActionBar().setElevation(0)
PreferenceFragment
ActionBarActivity
By Ankur Kotwal, Developer Advocate
Android 5.0 Lollipop is the biggest update of Android to date, introducing an all new visual style, improved performance, and much more. Android 5.0 Lollipop also extends across screens big and small, including phones, tablets, wearables, TVs and cars, to give your users access to information when they need it most.
To get you started on developing and testing on Android 5.0 Lollipop, here are some of the developer highlights with links to related videos and documentation.
You can get started developing and testing on Android 5.0 right away by downloading the Android 5.0 Platform (API level 21), as well as the SDK Tools, Platform Tools, and Support Package from the Android SDK Manager.
Check out the DevByte video below for more of what’s new in Lollipop!