The latest Android and Google Play news for app and game developers.
We hope you're enjoying the first developer preview of Android P. We wanted to specifically call out some backward-incompatible changes we plan to make to the cryptographic capabilities in Android P, which you can see in the developer preview.
Starting in Android P, we plan to deprecate some functionality from the BC provider that's duplicated by the AndroidOpenSSL (also known as Conscrypt) provider. This will only affect applications that specify the BC provider explicitly when calling getInstance() methods. To be clear, we aren't doing this because we are concerned about the security of the implementations from the BC provider, rather because having duplicated functionality imposes additional costs and risks while not providing much benefit.
getInstance()
If you don't specify a provider in your getInstance() calls, no changes are required.
If you specify the provider by name or by instance—for example, Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC") or Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"))—the behavior you get in Android P will depend on what API level your application targets. For apps targeting an API level before P, the call will return the BC implementation and log a warning in the application log. For apps targeting Android P or later, the call will throw NoSuchAlgorithmException.
Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC")
Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"))
NoSuchAlgorithmException
To resolve this, you should stop specifying a provider and use the default implementation.
In a later Android release, we plan to remove the deprecated functionality from the BC provider entirely. Once removed, any call that requests that functionality from the BC provider (whether by name or instance) will throw NoSuchAlgorithmException.
In a previous post, we announced that the Crypto provider was deprecated beginning in Android Nougat. Since then, any request for the Crypto provider by an application targeting API 23 (Marshmallow) or before would succeed, but requests by applications targeting API 24 (Nougat) or later would fail. In Android P, we plan to remove the Crypto provider entirely. Once removed, any call to SecureRandom.getInstance("SHA1PRNG", "Crypto") will throw NoSuchProviderException. Please ensure your apps have been updated.
SecureRandom.getInstance("SHA1PRNG", "Crypto")
NoSuchProviderException
Last week at Mobile World Congress we saw that Android's ecosystem of developers, device makers, and silicon partners continues to bring amazing experiences to users worldwide.
Looking ahead, today we're sharing the first developer preview of Android P, the newest version of Android. It's an early baseline build for developers only -- you're our most trusted reviewers and testers ;-) Early feedback from our developer community is crucial in helping us evolve the platform to meet your needs. We'd love to get you started exercising the new features and APIs in P, and as always, we depend on your early feedback and ideas, so please give us your input!
This first developer preview of Android P is just the start - we'll have lots more to share at Google I/O in May, stay tuned!
Here's a look at some of the cool features in this first preview of Android P that we want you to try and give feedback on.
Accurate indoor positioning has been a long-standing challenge that opens new opportunities for location-based services. Android P adds platform support for the IEEE 802.11mc WiFi protocol -- also known as WiFi Round-Trip-Time (RTT) -- to let you take advantage of indoor positioning in your apps.
On Android P devices with hardware support, location permission, and location enabled, your apps can use RTT APIs to measure the distance to nearby WiFi Access Points (APs). The device doesn't need to connect to the APs to use RTT, and to maintain privacy, only the phone is able to determine the distance, not the APs.
Knowing the distance to 3 or more APs, you can calculate the device position with an accuracy of 1 to 2 meters. With this accuracy, you can build new experiences like in-building navigation; fine-grained location-based services such as disambiguated voice control (e.g.,'Turn on this light'); and location-based information (e.g., 'Are there special offers for this product?').
Now apps can take full advantage of the latest device screens with fullscreen content. We've added display cutout into the platform, along with APIs that you can use to manage how your content is displayed.
Cutout support works seamlessly for apps, with the system managing status bar height to separate your content from the cutout. If you have critical, immersive content, you can also use new APIs to check the cutout shape and request full-screen layout around it. You can check whether the current device has a cutout by calling getDisplayCutout(), and then determine the location and shape of the cutout area using DisplayCutout. A new window layout attribute, layoutInDisplayCutoutMode, lets you tell the system how and when lay out your content relative to the cutout area. Details are here.
To make it easier to build and test cutout support in your app, we've added a Developer Option that simulates a cutout on any device. We recommend testing your existing apps with display cutout enabled to ensure that your content displays properly.
Apps with immersive content can display content fullscreen on devices with a display cutout.
In Android P we've put a priority on improving visibility and function in notifications. Try the new MessagingStyle notification style -- it highlights who is messaging and how you can reply. You can show conversations, attach photos and stickers, and even suggest smart replies. See the details here.
In MessagingStyle notifications you can now show conversations and smart replies [left] and even attach images and stickers [right].
You can now access streams simultaneously from two or more physical cameras on devices running Android P. On devices with either dual-front or dual-back cameras, you can create innovative features not possible with just a single camera, such as seamless zoom, bokeh, and stereo vision. The API also lets you call a logical or fused camera stream that automatically switches between two or more cameras. We're looking forward to seeing your new and exciting creations as Android P devices supporting multiple cameras reach the market in the year ahead.
Other improvements in camera include new Session parameters that help to reduce delays during initial capture, and Surface sharing that lets camera clients handle various use-cases without the need to stop and start camera streaming. We've also added APIs for display-based flash support and access to OIS timestamps for app-level image stabilization and special effects.
Android P gives you an easier way to decode images to bitmaps or drawables -- ImageDecoder, which deprecates BitmapFactory. ImageDecoder lets you create a bitmap or drawable from a byte buffer, file, or URI. It offers several advantages over BitmapFactory, including support for exact scaling, single-step decoding to hardware memory, support for post-processing in decode, and decoding of animated images.
You can decode and scale to an exact size just by calling setResize() with the target dimensions. You can also call getSampledSize() to get the image dimensions at a specific sample rate, then scale to those dimensions. If you want post-process an image -- such as applying rounded corners for circle masks or more complicated effects -- you can pass ImageDecoder any android.graphics.PostProcessor. You can also create Drawables directly, with ImageDecoder.decodeDrawable(). If the encoded image is an animated GIF or WebP, the Drawable will be an instance of the new AnimatedImageDrawable.
Android P adds built-in support for HDR VP9 Profile 2, so you can now deliver HDR-enabled movies to your users from YouTube, Play Movies, and other sources on HDR-capable devices.
We're excited to add HEIF (heic) image encoding to the platform. HEIF is a popular format for photos that improves compression to save on storage and network data. With platform support on Android P devices, it's easy to send and utilize HEIF images from your backend server. Once you've made sure that your app is compatible with this data format for sharing and display, give HEIF a try as an image storage format in your app. You can do a jpeg-to-heic conversion using ImageDecoder or BitmapFactory to obtain a bitmap from jpeg, and you can use HeifWriter in the new Support Library alpha to write HEIF still images from YUV byte buffer, Surface, or Bitmap.
We're also in the process of enhancing and refactoring the media APIs to make them easier to develop and integrate with -- watch for details coming later this year.
JobScheduler is Android's central service to help you manage scheduled tasks or work across Doze, App Standby, and Background Limits changes. In Android P, JobScheduler handles network-related jobs better for the user, coordinating with network status signals provided separately by carriers.
Jobs can now declare their estimated data size, signal prefetching, and specify detailed network requirements—carriers can report networks as being congested or unmetered. JobScheduler then manages work according to the network status. For example, when a network is congested, JobScheduler might defer large network requests. When unmetered, it can run prefetch jobs to improve the user experience, such as by prefetching headlines.
When you are adding jobs, try using setEstimatedNetworkBytes(), setIsPrefetch() and setRequiredNetwork() to let JobScheduler handle the work properly. When your job executes, be sure to use the Network object returned by JobParameters.getNetwork(), otherwise you'll implicitly use the device's default network which may not meet your requirements, causing unintended data usage.
We introduced the Neural Networks API in Android 8.1 to accelerate on-device machine learning on Android. In Android P we're expanding and improving this API, adding support for nine new ops -- Pad, BatchToSpaceND, SpaceToBatchND, Transpose, Strided Slice, Mean, Div, Sub, and Squeeze. If you have a Pixel 2 device, the DP1 build now includes an Qualcomm Hexagon HVX driver with acceleration for quantized models.
In Android P we're continuing to improve the Autofill Framework based on feedback from users and developers. Along with key bugfixes, this release includes new APIs that allow password managers to improve the Autofill user experience, such as better dataset filtering, input sanitization, and compatibility mode. Compatibility mode in particular has a high impact on end users because it lets password managers take the accessibility-based approach in apps that don't yet have full Autofill support, but without impacts on performance or security. See all the details on what's new here.
Android P adds an implementation of the GlobalPlatform Open Mobile API to Android. On supported devices, apps can use the OMAPI API to access secure elements (SE) to enable smart-card payments and other secure services. A hardware abstraction layer (HAL) provides the underlying API for enumerating a variety of Secure Elements (eSE, UICC, and others) available.
In Android P we're continuing our long-term investment to make Android the best platform for developers.
In Android P we're moving to a more consistent UI for fingerprint authentication across apps and devices. Android now provides a standard system dialog to prompt the user to touch the fingerprint sensor, managing text and placement as appropriate for the device. Apps can trigger the system fingerprint dialog using a new FingerprintDialog API. We recommend switching to the new system dialog as soon as possible.
As part of a larger effort to move all network traffic away from cleartext (unencrypted HTTP) to TLS, we're also changing the defaults for Network Security Configuration to block all cleartext traffic. You'll now need to make connections over TLS, unless you explicitly opt-in to cleartext for specific domains.
To better ensure privacy, Android P restricts access to mic, camera, and all SensorManager sensors from apps that are idle. While your app's UID is idle, the mic reports empty audio and sensors stop reporting events. Cameras used by your app are disconnected and will generate an error if the app tries to use them. In most cases, these restrictions should not introduce new issues for existing apps, but we recommend removing these requests from your apps.
We will also enable encryption of Android backups with a client-side secret. This feature is still in active development and will be launched in a future Android P preview release.
Longer term we're working to bring support for per-network randomization of associated MAC addresses to the platform. On supported devices running Android P, you can enable this experimentally for testing as a new developer option.
Android P also gives the user control over access to the platform's build.serial identifier by putting it behind the READ_PHONE_STATE permission. Direct access to this identifier has been deprecated since Android 8.0. In order to access the build.serial identifier, you should use the Build.getSerial() method.
Build.getSerial()
We're working to bring performance and efficiency improvements to all apps through the ART runtime. We've expanded ART's use of execution profiles to optimize apps and reduce in-memory footprint of compiled app code. ART now uses profile information for on-device rewriting of DEX files, with reductions up to 11% across a range of popular apps. We expect these to correlate closely with reductions in system DEX memory usage and faster startup times for your apps.
Kotlin is a first-class language on Android, and if you haven't tried it yet, you should! We've made an enduring commitment to Kotlin in Android and continue to expand support including optimizing the performance of Kotlin code. In P you'll see the first results of this work -- we've improved several compiler optimizations, especially those that target loops, to extract better performance. We're also continuing to work in partnership with JetBrains to optimize Kotlin's generated code. You can get all of the latest Kotlin performance improvements just by keeping Android Studio's Kotlin plugin up-to-date.
In Android P we continue to refine Doze, App Standby, and Background Limits to further improve battery life; please be sure to try your apps with these and send feedback.
Android P is shaped by our longer-term initiatives to modernize the foundations of Android and the apps that run on it. As we announced recently, Google Play will require all app updates to target Android Oreo (targetSdkVersion 26 or higher) by November 2018, with support for 64-bit hardware on the horizon for 2019.
In line with these changes, Android P will warn users with a dialog when they install an app that targets a platform earlier than Android 4.2 (targetSdkVersion less than 17), and future platform versions will continue to increment that lower bound. We're encouraging every Android developer to start planning the migration to target API 26 now, and to start the migration work as soon as possible. Here's a checklist of resources for help and support -- we're looking forward to seeing your apps getting the most from modern Android.
A key issue for users and developers is app compatibility -- making sure that apps are ready for new platform versions as they arrive, without risk of crashes for users and emergency rollouts for developers. Apps that use Android's public APIs from the SDK or NDK are in a good position to be compatible, but apps that use private Android interfaces and libraries are not.
So with Android P we're starting a gradual process to restrict access to selected non-SDK interfaces, asking developers -- including app teams inside Google -- to use the public equivalents instead. In cases where there is no public equivalent for your use-case, please let us know -- we want to make sure that this process is as smooth as possible for developers, so we'll use your feedback to ensure the initial rollout only affects APIs where developers can easily migrate to public alternatives. More about the restrictions is here.
First, make your app compatible to give your users a seamless transition to Android P. Just download a device system image or emulator system image, install your current app, and test -- the app should run and look great, and handle behavior changes properly. After you've made any necessary updates, we recommend publishing to Google Play right away without changing the app's platform targeting.
Remember, you don't need a supported Pixel device to test or develop on Android P. For most uses we highly recommend setting up an Android Virtual Device on the Android Emulator as a test environment instead. If you haven't tried the emulator recently, you'll find that it's incredibly fast , boots in under 6 seconds, convenient to use, and you can even model next-gen screens -- such as long screens and screens with camera cutout.
Next, change your app's targeting to "P" and run it with the full Android P experience. Set your app's targetSdkVersion to 'P' and compileSdkVersion to android-P, build, and test. Make sure to read the behavior changes for apps targeting P to find areas you will want to test and might need to adjust.
When you're ready, dive into Android P and learn about the many new features and APIs you can take advantage of in your app. To make it easier to explore the new APIs, take a look at the API diff report, along with the Android P API reference. Visit the P Developer Preview site for details on the preview timeline and support resources. Also check out this video highlighting what's new in Android P for developers.
To get started building with Android P, download the P Developer Preview SDK and tools into Android Studio 3.1 or use the latest Android Studio 3.2 canary version. We're also releasing an alpha version of the 28.0.0 support library for you to try.
The Android P Developer Preview includes an updated SDK with system images for testing on the official Android Emulator and on Pixel, Pixel XL Pixel 2, and Pixel 2 XL devices.
We plan to update the preview system images and SDK regularly throughout the preview. This initial release is for developers only and not intended for daily or consumer use, so we're making it available by manual download and flash only. Downloads and instructions are 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 P.
As always, your feedback is critical, so please let us know what you think — the sooner we hear from you, the more of your feedback we can integrate. When you find issues, please report them here. We have separate hotlists for filing platform issues, app compatibility issues, and third-party SDK issues.
Today we're releasing Developer Preview 7 (DP7) of Android Things, Google's platform that enables Android developers to create Internet of Things (IoT) devices. The platform also supports powerful applications such as video and audio processing and on-board machine learning with TensorFlow.
The latest preview is based on Android 8.1 and is updated to support version 11.8.0 of Google Play Services. For all the details of what's included in DP7, see the release notes. Here are some of the highlights:
New features are also available in the Android Things Console to enhance product management from prototype to production:
Devices can subscribe to different update channels using new APIs added to UpdateManager. See the updated Device Updates API guide and console documentation to learn more about configuring update channel subscriptions.
UpdateManager
We've received tons of amazing feedback from developers so far, and focused heavily on addressing many of the top reported issues in this release:
Android mobile devices expose controls to users for pairing with and connecting to Bluetooth devices through the Settings app. IoT devices running Android Things need to programmatically perform these same operations. The new BluetoothConnectionManager API enables apps to take control of the pairing and connection process. See the new Bluetooth API guide for more details.
BluetoothConnectionManager
Last year at Google I/O, we demonstrated building an app using Kotlin on Android Things. For developers using Kotlin, we have started publishing Kotlin versions of the Android Things samples. Today you can download the Button and LED sample in both Kotlin and Java, with more samples to follow very soon.
We have also migrated the TensorFlow Image Classifier sample app to use the TensorFlow Lite library, reducing the size of the pre-trained TensorFlow model by over 90% and the time required to classify the images by approximately 50%.
Please send us your feedback by filing bug reports and feature requests, as well as asking any questions on Stack Overflow. You can also join Google's IoT Developers Community on Google+, a great resource to get updates and discuss ideas. We look forward to seeing what you build with Android Things!
In Android, we're always looking for ways to improve the user and developer experience by making those experiences as stable as possible. In this spirit, we've been working to ensure that apps don't use non-SDK interfaces, since doing so risks crashes for users and emergency rollouts for developers. In Android N, we restricted the set of symbols that C/C++ code could use. This change ensured that apps using C++ rely on stable NDK interfaces rather than incur the incremental crashes caused by reliance on unstable, non-NDK interfaces. Starting in the next release of Android, we will further increase stability by expanding these restrictions to cover the Java language interfaces of the SDK.
Starting in the next release of Android, some non-SDK methods and fields will be restricted so that you cannot access them -- either directly, via reflection, or JNI. If you try, you can see errors such as NoSuchFieldException or NoSuchMethodException.
Initially, this restriction will impact interfaces with low or no usage. It is an explicit goal of our planning and design to respect our developer community and create the absolute minimum of change while addressing app stability issues flagged by our users and device manufacturers. In cases where a migration to SDK methods will be possible but is likely to be technically challenging, we'll allow continued usage until your app is updated to target the latest API level. We plan to broaden these restrictions in future platform versions, giving developers time to migrate with long advance warning, and also giving us time to gather feedback about any needed SDK interfaces. We have always said that using non-SDK interfaces is always risky -- they might change in any release as we refactor code to add features or fix bugs. So if your app currently relies on non-SDK interfaces, you should begin planning a migration to SDK alternatives.
Because the Java language has different features from C++, this restriction will take a slightly different form than the previous symbol restriction. You should not access classes that are not part of our SDK, but you also need to be sure that you are only using the officially documented parts of each class. In particular, this means that you should not plan to access methods or fields that are not listed in the SDK when you interact with a class via semantics such as reflection.
We know that some apps may be using non-SDK interfaces in ways that do not have an SDK alternative. We value your feedback about where and how we need to expand and improve the public APIs for you. If you feel that you'll need the SDK API expanded before you can stop using non-SDK ones, please tell us via our bug tracker. We will be monitoring this list closely and using this valuable feedback to prioritize. It is critical for us to get this feedback in a timely manner so that we can continue to both tune the blacklist to minimize developer impact and also begin developing any needed alternatives for future platforms.
In the next Android developer preview, you'll be able to run your existing apps and see warnings when you use a non-SDK interface that will be subject to blacklist or greylist in the final release. It's always a best practice to make sure your app runs on the developer preview, but you should pay specific attention to the interface compatibility warnings if you are concerned that you may be impacted.
In conjunction with the next developer preview and the new bug tracker category, we'll be monitoring usage of non-SDK interfaces. In cases where official SDK alternatives already exist, we'll publish official guidance on how to migrate away from commonly used non-SDK interfaces.
Transitions in Material Design apps provide visual continuity. As the user navigates the app, views in the app change state. Motion and transformation reinforce the idea that interfaces are tangible, connecting common elements from one view to the next.
This post aims to provide guidelines and implementation for a specific continuous transition between Android Fragments. We will demonstrate how to implement a transition from an image in a RecyclerView into an image in a ViewPager and back, using 'Shared Elements' to determine which views participate in the transition and how. We will also handle the tricky case of transitioning back to the grid after paging to an item that was previously offscreen.
This is the result we are aiming for:
If you wish to skip the explanation and go straight to the code, you can find it here.
A shared element transition determines how views that are present in two fragments transition between them. For example, an image that is displayed on an ImageView on both Fragment A and Fragment B transitions from A to B when B becomes visible.
ImageView
A
B
There are numerous previously published examples which explain how shared elements work and how to implement a basic Fragment transition. This post will skip most of the basics and will walk through the specifics on how to create a working transition into a ViewPager and back. However, if you'd like to learn more about transitions, I recommend starting by reading about transitions at the Android's developers website, and take the time to watch this 2016 Google I/O presentation.
We would like to support a seamless back and forth transition. This includes a transition from the grid to the pager, and then a transition back to the relevant image, even when the user paged to a different image.
To do so, we will need to find a way to dynamically remap the shared elements in order to provide the Android's transition system what it needs to do its magic!
Shared element transitions are powerful, but can be tricky when dealing with elements that need to be loaded before we can transition to them. The transition may simply not work as expected when views at the target fragment are not laid out and ready.
In this project, there are two areas where a loading time affects the shared element transition:
ViewPager
RecyclerView
Before we dive into the juicy transitions, here is a little bit about how the demo app is structured.
The MainActivity loads a GridFragment to present a RecyclerView of images. The RecyclerView adapter loads the image items (a constant array that is defined at the ImageData class), and manages the onClick events by replacing the displayed GridFragment with an ImagePagerFragment.
GridFragment
ImageData
onClick
ImagePagerFragment
The ImagePagerFragment adapter loads the nested ImageFragments to display the individual images when paging happens.
ImageFragments
Note: The demo app implementation uses Glide, which loads images into views asynchronously. The images in the demo app are bundled with it. However, you may easily convert the ImageData class to hold URL strings that point to online images.
To communicate the selected image position between the fragments, we will use the MainActivity as a place to store the position.
MainActivity
When an item is clicked, or when a page is changed, the MainActivity is updated with the relevant item's position.
The stored position is later used in several places:
As mentioned above, we will need to find a way to dynamically remap the shared elements in order to give the transition system what it needs to do its magic.
Using a static mapping by setting up transitionName attributes for the image views at the XML will not work, as we are dealing with an arbitrary amount of views that share the same layout (e.g. views inflated by the RecyclerView adapter, or views inflated by the ImageFragment).
transitionName
ImageFragment
To accomplish this, we'll use some of what the transition system provides us:
setTransitionName
onCreateView
SharedElementCallbacks
onMapSharedElements
The first thing we set up to initiate a transition for a fragment replacement is at the FragmentManager transaction preparation. We need to inform the system that we have a shared element transition.
FragmentManager
fragment.getFragmentManager() .beginTransaction() .setReorderingAllowed(true) // setAllowOptimization before 26.1.0 .addSharedElement(imageView, imageView.getTransitionName()) .replace(R.id.fragment_container, new ImagePagerFragment(), ImagePagerFragment.class.getSimpleName()) .addToBackStack(null) .commit();
The setReorderingAllowed is set to true. It will reorder the state changes of fragments to allow for better shared element transitions. Added fragments will have onCreate(Bundle) called before replaced fragments have onDestroy() called, allowing the shared view to get created and laid out before the transition starts.
setReorderingAllowed
true
onCreate(Bundle)
onDestroy()
To define how the image transitions when it animates to its new location, we set up a TransitionSet in an XML file and load it at the ImagePagerFragment.
TransitionSet
<ImagePagerFragment.java>
Transition transition = TransitionInflater.from(getContext()) .inflateTransition(R.transition.image_shared_element_transition); setSharedElementEnterTransition(transition);
<image_shared_element_transition.xml>
<?xml version="1.0" encoding="utf-8"?> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:duration="375" android:interpolator="@android:interpolator/fast_out_slow_in" android:transitionOrdering="together"> <changeClipBounds/> <changeTransform/> <changeBounds/> </transitionSet>
We'll start by adjusting the shared element mapping when leaving the GridFragment. For that, we will call the setExitSharedElementCallback() and provide it with a SharedElementCallback which will map the element names to the views we'd like to include in the transition.
setExitSharedElementCallback()
SharedElementCallback
It's important to note that this callback will be called while exiting the Fragment when the fragment-transaction occurs, and while re-entering the Fragment when it's popped out of the backstack (on back navigation). We will use this behavior to remap the shared view and adjust the transition to handle cases where the view is changed after paging the images.
Fragment
In this specific case, we are only interested in a single ImageView transition from the grid to the fragment the view-pager holds, so the mapping only needs to be adjusted for the first named element received at the onMapSharedElements callback.
<GridFragment.java>
setExitSharedElementCallback( new SharedElementCallback() { @Override public void onMapSharedElements( List<String> names, Map<String, View> sharedElements) { // Locate the ViewHolder for the clicked position. RecyclerView.ViewHolder selectedViewHolder = recyclerView .findViewHolderForAdapterPosition(MainActivity.currentPosition); if (selectedViewHolder == null || selectedViewHolder.itemView == null) { return; } // Map the first shared element name to the child ImageView. sharedElements .put(names.get(0), selectedViewHolder.itemView.findViewById(R.id.card_image)); } });
We also need to adjust the shared element mapping when entering the ImagePagerFragment. For that, we will call the setEnterSharedElementCallback().
setEnterSharedElementCallback()
setEnterSharedElementCallback( new SharedElementCallback() { @Override public void onMapSharedElements( List<String> names, Map<String, View> sharedElements) { // Locate the image view at the primary fragment (the ImageFragment // that is currently visible). To locate the fragment, call // instantiateItem with the selection position. // At this stage, the method will simply return the fragment at the // position and will not create a new one. Fragment currentFragment = (Fragment) viewPager.getAdapter() .instantiateItem(viewPager, MainActivity.currentPosition); View view = currentFragment.getView(); if (view == null) { return; } // Map the first shared element name to the child ImageView. sharedElements.put(names.get(0), view.findViewById(R.id.image)); } });
The images we would like to transition are loaded into the grid and the pager and take time to load. To make it work properly, we will need to postpone the transition until the participating views are ready (e.g. laid out and loaded with the image data).
To do so, we call a postponeEnterTransition() in our fragments' onCreateView(), and once the image is loaded, we start the transition by calling startPostponedEnterTransition().
postponeEnterTransition()
onCreateView()
startPostponedEnterTransition()
Note: postpone is called for both the grid and the pager fragments to support both forward and backward transitions when navigating the app.
Since we are using Glide to load the images, we set up listeners that trigger the enter transition when images are loaded.
This is done in two places:
Here is how the ImageFragment loads an image and notifies its parent when it's ready.
Note that the postponeEnterTransition is made at the the ImagePagerFragment, while the startPostponeEnterTransition is called from the child ImageFragment that is created by the pager.
postponeEnterTransition
startPostponeEnterTransition
<ImageFragment.java>
Glide.with(this) .load(arguments.getInt(KEY_IMAGE_RES)) // Load the image resource .listener(new RequestListener<Drawable>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { getParentFragment().startPostponedEnterTransition(); return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { getParentFragment().startPostponedEnterTransition(); return false; } }) .into((ImageView) view.findViewById(R.id.image));
As you may have noticed, we also call to start the postponed transition when the loading fails. This is important to prevent the UI from hanging during failure.
To make our transitions even smoother, we would like to fade out the grid items when the image transitions to the pager view.
To do that, we create a TransitionSet that is applied as an exit transition for the GridFragment.
setExitTransition(TransitionInflater.from(getContext()) .inflateTransition(R.transition.grid_exit_transition));
<grid_exit_transition.xml>
<?xml version="1.0" encoding="utf-8"?> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:duration="375" android:interpolator="@android:interpolator/fast_out_slow_in" android:startDelay="25"> <fade> <targets android:targetId="@id/card_view"/> </fade> </transitionSet>
This is what the transition looks like after this exit transition is set up:
As you may have noticed, the transition is still not completely polished with this setup. The fade animation is running for all the grid's card views, including the card that holds the image that transitions to the pager.
To fix it, we exclude the clicked card from the exit transition before commiting the fragment transaction at the GridAdapter.
GridAdapter
// The 'view' is the card view that was clicked to initiate the transition. ((TransitionSet) fragment.getExitTransition()).excludeTarget(view, true);
After this change, the animation looks much better (the clicked card doesn't fade out as part of the exit transition, while the rest of the cards fade out):
As a final touch, we set up the GridFragment to scroll and reveal the card we transition to when navigating back from the pager (done at the onViewCreated):
onViewCreated
recyclerView.addOnLayoutChangeListener( new OnLayoutChangeListener() { @Override public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { recyclerView.removeOnLayoutChangeListener(this); final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); View viewAtPosition = layoutManager.findViewByPosition(MainActivity.currentPosition); // Scroll to position if the view for the current position is null (not // currently part of layout manager children), or it's not completely // visible. if (viewAtPosition == null || layoutManager.isViewPartiallyVisible(viewAtPosition, false, true)){ recyclerView.post(() -> layoutManager.scrollToPosition(MainActivity.currentPosition)); } } });
Wrapping up
In this article, we implemented a smooth transition from a RecyclerView to a ViewPager and back.
We showed how to postpone a transition and start it after the views are ready. We also implemented shared element remapping to get the transition going when shared views are changing dynamically while navigating the app.
These changes transformed our app's fragment transitions to provide better visual continuity as users interact with it.
The code for the demo app can be found here.
Promotions can be a valuable tool to increase user engagement or attract new users by offering content or features to a limited number of users free of charge.
We are happy to share an improvement in the Google Play Developer API that makes it easier to track your promotions from your own backend. Starting today, the API for Purchases.products will return "Promo" as a new value for the field purchaseType when the user redeems a promo code. Now, the possible values are:
Promo"
purchaseType
0. Test
1. Promo
For purchases made using the standard in-app billing flow, the field will continue to not be set in the API response.
Please note: This state is only returned by the Purchases.products API. For subscriptions you may use Free Trials to offer free of charge subscription periods.
For more details about how to create and redeem promo codes, check the In-app Promotions documentation. For more details about the server-side API, check the Google Play Developer API documentation.
We have just wrapped up the second edition of the Google Play Indie Games Contest in Europe! The iconic Saatchi Gallery in London welcomed 20 developers, from 12 countries, who showcased their games to the audience of gamers, industry experts, and journalists.
The finalists' games were on show to the public, who spent three hours trying out their games and voting for their favourites, alongside the Google Play team. The top 10 finalists were then selected, and went on to pitch their games, and compete for the big prizes in front of our jury.
Please join us in congratulating the winners! They will be bringing home a well-deserved diploma, along with a prize package that will help them reach more gamers worldwide; including premium placement on the Google Play Store, marketing campaigns of up to 100,000 EUR and influencer campaigns of up to 50,000 EUR, the latest Google hardware, tickets to Google I/O, and much more.
It's really inspiring to see the excitement around this second edition, and great to see the new wave of indie games coming from Europe. We are already looking forward to playing the games that will be developed in 2018!
Check out the main winners and the other finalists on the Google Play Store!
Bury me, my love
Playdius
France
A reality-inspired interactive fiction designed for mobile phones. It tells the story of Nour, a Syrian woman trying to reach Europe in hope of a better life.
Old Man's Journey
Broken Rules Interactive Media GmbH
Austria
A story game about life's precious moments, broken dreams, and changed plans.
Yellow
Bart Bonte
Belgium
A puzzle game for you! A love letter to a marvelous colour and to the little wonder called touchscreens. Warning: very yellow!
Captain Tom Galactic Traveler
Picodongames
An open world platformer and space exploration game. Embark on an exploratory mission, discover planets, collect oxygen, play with gravity.
I Love Hue
Zut!
United Kingdom
A minimalist, ambient puzzle game influenced by mindfulness apps and abstract art. Players arrange shuffled mosaics of coloured tiles into perfectly ordered palettes.
Jodeo
Gamebra.in
Turkey
Jodeo is a 2D jelly critter. There's something it's curious about: what if 3D objects and 2D physics are in the same game? How can 2D objects interact with 3D objects?
Kami 2
State of Play
The calming yet addictive puzzle game is back! With over 100 handcrafted puzzles, it takes you on a mind-twisting journey that combines logic and problem-solving.
Kenshō
FIFTYTWO
Russia
A tile sliding puzzle with a wonderful soundtrack. Mysterious things happen in a ruined room. Doors inside that room lead to different worlds and beautiful landscapes.
No More Buttons
Tommy Søreide Kjær
Norway
A hand-drawn platformer where the buttons are part of the environment.
The Big Journey
Catfishbox
Ukraine
Designed for kids and adults alike, this a beautiful, casual adventure. Tilt to roll around and explore a beautiful world with Mr. Whiskers.
How useful did you find this blogpost?
★ ★ ★ ★ ★