12 Sep 2024

feedAndroid Developers Blog

Developer Preview: Desktop windowing on Android Tablets

Posted by Francesco Romano - Developer Relations Engineer on Android, and Fahd Imtiaz - Product Manager, Android Developer


To empower tablet users to get more done, we're enhancing freeform windowing, allowing them to run multiple apps simultaneously and resize windows for optimal multitasking. Today, we're excited to share that desktop windowing on Android tablets is available in developer preview.

For app developers, the concept of Android apps running in freeform windows has already existed with solutions like Samsung DeX and ChromeOS. Updating your apps to support adaptive layouts, more robust multitasking, and adaptive inputs will ensure your apps work well on large screens across the Android ecosystem.

Let's explore how to optimize your apps for desktop windowing and deliver the optimal experience to users.

What is desktop windowing?

Desktop windowing allows users to run multiple apps simultaneously and resize app windows, offering a more flexible and desktop-like experience. This, along with a refreshed System UI and new APIs, allows users to be even more productive and creates a more seamless, desktop-like experience on tablets.

In Figure 1, you can see the anatomy of the screen with desktop windowing enabled. Things to make note of:

  • Users can run multiple apps side-by-side, simultaneously
  • Taskbar is fixed and shows the running apps, users can pin apps for quick access
  • New header bar with window controls at the top of each window which apps can customize
Desktop windowing on a Pixel Tablet
Figure 1: Desktop windowing on a Pixel Tablet.
Note: Images are examples and subject to change


How can users invoke desktop windowing?

By default, apps open in full screen on Android tablets. To run the apps as a desktop window on Pixel Tablet, press and hold the window handle at the top in the middle of the screen and drag it within the UI, as seen in Figure 2.

Once you are in the desktop space, all future apps will be launched as desktop windows as well.

A moving image demonstrating what completing the action 'press, hold, and drag the window handle to enter desktop windowing' looks like.
Figure 2. Press, hold, and drag the window handle to enter desktop windowing.
Note: Images are examples and subject to change


You can also invoke desktop windowing from the menu that shows up below the window handle when you tap/click on it or use the keyboard shortcut meta key (Windows, Command, or Search) + Ctrl + Down.

You can exit desktop windowing and display an app as full screen by closing all active windows or by grabbing the window handle at the top of the window and dragging the app to the top of the screen. You can also use the meta + H keyboard shortcut to run apps as full screen again.

To return to the desktop, move a full screen app to the desktop space by using the methods mentioned above, or simply tap on the desktop space tile in the Recents screen.

What does this mean for app developers?

Desktop windowing on Android tablets creates new opportunities for your apps, particularly around productivity and multitasking. The possibility to resize and reposition multiple app windows allows users to easily compare documents, reference information while composing emails, and multitask efficiently.

By optimizing for desktop windowing, you can deliver unique user experiences to match the growing demand for tablet-based productivity. At the same time, you'll enhance the overall user experience on tablets, making your apps more versatile and adaptable to different scenarios.

If your app already meets the Tier 2 (Large Screens optimized) quality bar in the Large screen app quality guidelines, then there is minimal additional optimization required! If your app has not been optimized for large screens yet, updating it according to the Large screen app quality guidelines becomes even more crucial in the context of desktop windowing. Let's see why:

  • Freeform resizing enables users to resize apps to their preference for maximized productivity. Considering this, developers should note:
    • Apps with locked orientation are freely resizable. That means, even if an activity is locked to portrait orientation, users can still resize the app to landscape orientation window. In a future update, apps declared as non-resizable will have their UI scaled while keeping the same aspect ratio.
    • Adaptive layouts: By adapting your UI, apps have an opportunity to effortlessly handle a wide range of window sizes, from compact to expanded screen layouts. In desktop windowing, apps can be resized down to a minimum size of 386dp x 352dp, so make sure to leverage window size classes to adjust your app's layout, content, and interactions to adapt to different window dimensions.
    • State management: With freeform resizing, configuration changes happen each time the window resizes, so your app should either handle these configuration changes gracefully or make sure you are preserving the app state when the OS initiates the re-creation of the app. As a reminder, users can change the screen density while your app is running, so it's best to ensure that your app can handle screen density configuration changes as well.

    A moving image demonstrating how apps are fully resizable
    Figure 3. Apps with locked orientation are freely resizable.

  • Desktop windowing takes productivity on tablets to the next level with multiple apps running simultaneously. Similar to split screen, Desktop windowing encourages users to have multiple windows open. Considering this, developers should note:
    • Multitasking support: For enhanced productivity, users can have two or more apps open simultaneously, and they expect to easily share content between apps, so add support for drag and drop gestures. Also, ensure your app continues to function correctly even when not in focus, and if your app uses exclusive resources like camera or microphone, the app needs to handle resource loss gracefully when other apps acquire the resource.
    • Multi-instance support: Users can run multiple instances of your app side-by-side; for example, a document editor application may allow users to start new documents while still being able to reference the already open documents. Apps can set this new Multi-instance property to declare that System UI should be shown for this app to allow it to be launched as multiple instances. Also note that in desktop windowing, new tasks open in a new window, so double-check the user journey if your app starts multiple tasks.

    A moving image demonstrating how you can start another instance of Chrome by dragging a tab out og the app window.
    Figure 4. Start another instance of Chrome by dragging a tab out of the app window.
    Note: Images are examples and subject to change

    • With desktop windowing, input methods beyond touch and insets handling become even more important for a seamless user experience.
      • More input methods (keyboard, mouse): Users are more likely to use your app with a variety of input methods like external keyboards, mice, and trackpads. Check that users can interact smoothly with your app using keyboard and mouse peripherals or through the emulator. Developers can add support for app shortcuts and publish them using the keyboard shortcuts API, which allows users to easily view the supported app shortcuts through a standardized surface on Android devices.
      • Insets handling: All apps when running in desktop windowing have a header bar, even in immersive mode. Ensure your app's content isn't obscured by this. The new header bar is reported as a caption bar in Compose (androidx.compose.foundation:foundation-layout.WindowInsets.Companion.captionBar) and in Views (android.view.WindowInsets.Type.CAPTION_BAR), which is part of the system bars. API 35 also introduced a new appearance type, to make the header bar transparent, to allow apps to draw custom content inside.

Get hands-on!

Today we're announcing a developer preview that provides you with an early opportunity to experience and test desktop windowing. You can try it out on Pixel Tablet before it's released to AOSP more broadly. The preview is available today. Update your Pixel Tablet to the latest Android 15 QPR1 Beta 2 release to try out desktop windowing. If you don't have a Pixel Tablet handy, access the Pixel Tablet emulator in Android Studio Preview, and select the Android 15.0 (Google APIs Tablet) target. Once your device is set up, select Enable freeform windows option in Developer options to explore the capabilities of desktop windowing and how your app behaves within this new environment.

By optimizing your apps for desktop windowing on Pixel Tablet, you are not only enhancing the app experience on that specific device but also future-proofing your apps for the broader Android ecosystem where freeform windowing will become prevalent. We're excited about the windows of opportunities enabled by desktop windowing, and we look forward to seeing how you adapt your apps for an enhanced user experience.

We're committed to improving the desktop windowing experience through future updates. Make sure to test your app and give us feedback. Say tuned for more developer guides and resources!

12 Sep 2024 6:00pm GMT

11 Sep 2024

feedAndroid Developers Blog

Streamlining Android authentication: Credential Manager replaces legacy APIs

Posted by Diego Zavala and Jason Lucibello - Product Managers


In 2023, we introduced Credential Manager for Android. Credential Manager creates a unified experience for passkeys, Sign in with Google, and passwords, allowing seamless sign-in and eliminating the need for users to type in usernames or passwords.

ALT TEXT
Fig 1. Sample app showing Credential Manager dialog in a sign-in flow with a passkey, a password, and a Sign in with Google options


To bring Credential Manager's benefits to more Android users and simplify developers' integration efforts, APIs that were previously deprecated will continue their phased removals and shutdowns. These APIs include:

Developers with apps that still use these APIs should migrate to Credential Manager as soon as possible. Credential Manager supports all authentication features included in these legacy APIs, as well as streamlined journeys for users and modernizes the experience with passkey support and streamlined user journeys. Developers looking to implement authorization functionality for Google Accounts, such as scoped access to a service like Google Drive, should continue to use the AuthorizationClient API.

Current status of APIs as of September 2024, update plans, and recommended migration guides.

API: Smart Lock for Passwords
Status: Removed
Next Update: Fully shut down in Q1 2025
Migration guide: Migrate from Smart Lock for Passwords to Credential Manager

API: Credential Saving API
Status: Deprecated
Next Update: Removed in H1 2025
Migration guide: Migrate passwords to Credential Manager

API: Sign in with Google button
Status: Deprecated
Next Update: Removed in H1 2025
Migration guide: Migrate to the Sign in with Google button and Credential Manager

API: One Tap Sign-in
Status: Deprecated
Next Update: Removed in H2 2025
Migration guide: Authenticate users with Sign in with Google and Credential Manager

API: Google Sign-In for Android
Status: Deprecated
Next Update: Removed in H2 2025
Migration guide: Migrate from legacy Google Sign-In to Credential Manager

What does each status mean?

  • Deprecated: API is still in the SDK and functional, but will be removed and fully shut down in the future. Developers are recommended to migrate to Credential Manager at this time.
  • Removed: API is still functional for users, but is no longer included in the SDK. New app versions compiled with the most recent SDK would fail in the build process if your code still utilizes the removed API. If your app still relies on any of these APIs, you should migrate to Credential Manager as soon as possible.
  • Fully shut down: API is no longer functional, and it will fail when a request is sent by an app.

Credential Manager offers streamlined, more secure auth journeys

Credential Manager delivers multiple advantages to users and developers over the deprecated APIs:

1. Easier, more secure sign-ins with passkeys: Passkeys are an alternative to passwords that provide an easier and more secure authentication experience, based on industry standards. Credential Manager brings support for passkeys to Android apps.


2. Frictionless, one-tap sign-in: Users select their preferred saved credential from the options offered, without needing to remember or type username or passwords.


3. Unified UI across all credentials: Credential Manager's one-tap sign-in works with passkeys, Sign in with Google, and passwords. It deduplicates methods for the same account, so users no longer need to remember which method they last used, or which one is the "right" method.


4. Extended support for password managers: Users benefit from using the credentials stored in their preferred password manager on Credential Manager flows, and can even enable multiple password managers at the same time! Passwords managers not only protect users' credentials, but they also provide additional action and protections to keep users safe, such as upgrading passwords to passkeys, alerting users to password reuse, and containing usage to affiliated apps and domains.


5. Simplified development: Developers can consolidate their sign-in logic into a single, modern API, reducing development overhead and maintenance efforts. New authentication functionality will be released through Credential Manager going forward.


Adopting Credential Manager is an intuitive upgrade for developers

For developers previously using our deprecated APIs, the transition to Credential Manager is smooth and intuitive. Developers like X (formerly known as Twitter), Pinterest have already experienced the benefits of the upgrade. X shared with us that Credential Manager's unified approach made migration and maintenance effortless, while Pinterest expressed a smooth process for both users and engineers with Credential Manager.

Quote text reads: 'The Credential Manager library allowed us to unify Smart Lock, Sign in with Google, and passkeys under one cohesive umbrella, significantly reducing the amount of code required. The unified process made migration and maintenance effortless, empowering us to enhance security and user experience with ease' Saurabh Arora, Staff SoftwareEngineer, X (formerly Twitter)


Quote text reads: 'Migrartingo ur codebase to Credential Manager on Android was a smooth process for users and engineers, which aallowed us to have more cohesive and simplified process to support and maintain authentication at Pinterest. Our Android users have benfitted from frictionless sign-in and sign-up using Google, currently accounting for over 75% of user authentications.' - Jorge Garmendia Identity Product safety and Compliance Client Engineering Lead, Pinterest

Developers can use the following guides to make adopting Credential Manager even easier:

Share your feedback

Your input is very valuable to us as we continue to refine and improve our authentication services. Please keep providing us feedback on the issue tracker and share your experience integrating Credential Manager!

11 Sep 2024 4:00pm GMT

09 Sep 2024

feedAndroid Developers Blog

Jetpack Compose APIs for building adaptive layouts using Material guidance now stable

Posted by Alex Vanyo - Developer Relations Engineer


The 1.0 stable version of the Compose adaptive APIs with Material guidance is out, ready to be used in production. The library helps you build adaptive layouts that provide an optimized user experience on any window size.

The team at SAP Mobile Start were early adopters of the Compose adaptive APIs. It took their developers only five minutes to integrate the NavigationSuiteScaffold from the new Compose Material 3 adaptive library, rapidly adapting the app's navigation UI to different window sizes.

Each of the new components in the library, NavigationSuiteScaffold, ListDetailPaneScaffold and SupportingPaneScaffold are adaptive: based on the window size and posture, different components are displayed to the user based on which one is most appropriate in the current context. This helps build UI that adapts to a wide variety of window sizes instead of just stretching layouts.

For an overview of the components, check out the dedicated I/O session and our new documentation pages to get started.

In this post, we're going to take a more detailed look at the layering of the new library so you have a better understanding of how customisable it is, to fit a wide variety of use cases you might have.

Similar to Compose itself, the adaptive libraries are layered into multiple dependencies, so that you can choose the appropriate level of abstraction for your application.There are four new artifacts as part of the adaptive libraries:

  • For the core building blocks for building adaptive UI, including computing the window size class and the current posture, add androidx.compose.material3.adaptive:adaptive:1.0.0

  • For implementing multi-pane layouts, add androidx.compose.material3.adaptive:adaptive-layout:1.0.0


  • For standalone navigators for the multi-pane scaffold layouts, add androidx.compose.material3.adaptive:adaptive-navigation:1.0.0

  • For implementing adaptive navigation UI, add androidx.compose.material3:material3-adaptive-navigation-suite:1.3.0

The libraries have the following dependencies:

Flow diagram showing dependencies between material3-adaptive 1.0.0 and material 1.3.0 libraries
New library dependency graph


To explore this layering more, let's start with the highest level example with the most built-in functionality using a NavigableListDetailPaneScaffold from androidx.compose.material3.adaptive:adaptive-navigation:

val navigator = rememberListDetailPaneScaffoldNavigator<Any>()

NavigableListDetailPaneScaffold(
    navigator = navigator,
    listPane = {
        // List pane
    },
    detailPane = {
        // Detail pane
    },
)


This snippet of code gives you all of our recommended adaptive behavior out of the box for a list-detail layout: determining how many panes to show based on the current window size, hiding and showing the correct pane when the window size changes depending on the previous state of the UI, and having the back button conditionally bring the user back to the list, depending on the window size and the current state.

A list layout adapting to and from a list detail layout depending on the window size


This encapsulates a lot of behavior - and this might be all you need, and you don't need to go any deeper!

However, there may be reasons why you may want to tweak this behavior, or more directly manage the state by hoisting parts of it in a different way.

Remember, each layer builds upon the last. This snippet is at the outermost layer, and we can start unwrapping the layers to customize it where we need.

Let's go one level deeper with NavigableListDetailPaneScaffold and drop down one layer. Behavior won't change at all with these direct inlinings, since we are just inlining the default behavior at each step:

(Fun fact: You can follow along with this directly in Android Studio and for any other component you desire. If you choose Refactor > Inline function, you can directly replace a component with its implementation. You can't delete the original function in the library of course.)

val navigator = rememberListDetailPaneScaffoldNavigator<Any>()

BackHandler(
    enabled = navigator.canNavigateBack(BackNavigationBehavior.PopUntilContentChange)
) {
    navigator.navigateBack(BackNavigationBehavior.PopUntilContentChange)
}
ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        // List pane
    },
    detailPane = {
        // Detail pane
    },
)


With the first inlining, we see the BackHandler that NavigableListDetailPaneScaffold includes by default. If using ListDetailPaneScaffold directly, back handling is left up to the developer to include and hoist to the appropriate place.

This also reveals how the navigator provides two pieces of state to control the ListDetailPaneScaffold:

  • directive -- how the panes should be arranged in the ListDetailPaneScaffold, and
  • value -- the current state of the panes, as calculated from the directive and the current navigation state.

These are both controlled by the navigator, and the next unpeeling shows us the default arguments to the navigator for directive and the adapt strategy, which is used to calculate value:

val navigator = rememberListDetailPaneScaffoldNavigator<Any>(
    scaffoldDirective = calculatePaneScaffoldDirective(currentWindowAdaptiveInfo()),
    adaptStrategies = ListDetailPaneScaffoldDefaults.adaptStrategies(),
)

BackHandler(
    enabled = navigator.canNavigateBack(BackNavigationBehavior.PopUntilContentChange)
) {
    navigator.navigateBack(BackNavigationBehavior.PopUntilContentChange)
}
ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        // List pane
    },
    detailPane = {
        // Detail pane
    },
)


The directive controls the behavior for how many panes to show and the pane spacing, based on currentWindowAdaptiveInfo, which contains the size and posture of the window.

This can be customized with a different directive, to show two panes side-by-side at a smaller medium width:

val navigator = rememberListDetailPaneScaffoldNavigator<Any>(
    scaffoldDirective = calculatePaneScaffoldDirectiveWithTwoPanesOnMediumWidth(currentWindowAdaptiveInfo()),
    adaptStrategies = ListDetailPaneScaffoldDefaults.adaptStrategies(),
)


By default, showing two panes at a medium width can result in UI that is too narrow, especially for complex content. However, this can be a good option to use the window space more optimally by showing two panes for less complex content.

The AdaptStrategy controls what happens to panes when there isn't enough space to show all of them. Right now, this always hides panes for which there isn't enough space.

This directive is used by the navigator to drive its logic and, combined with the adapt strategy to determine the scaffold value, the resulting target state for each of the panes.

The scaffold directive and the scaffold value are then passed to the ListDetailPaneScaffold, driving the behavior of the scaffold.

This layering allows hoisting the scaffold state away from the display of the scaffold itself. This layering also allows custom implementations for controlling how the scaffold works and for hoisting related state. For example, if you are using a custom navigation solution instead of the navigator, you could drive the ListDetailPaneScaffold directly with state derived from your custom navigation solution.

The layering is enforced in the library with the different artifacts:

  • androidx.compose.material3.adaptive:adaptive contains the underlying methods to calculate the current window adaptive info
  • androidx.compose.material3.adaptive:adaptive-layout contains the layouts ListDetailPaneScaffold and SupportingPaneScaffold
  • androidx.compose.material3.adaptive:adaptive-navigation contains the navigator APIs (like rememberListDetailPaneScaffoldNavigator)

Therefore, if you aren't going to use the navigator and instead use a custom navigation solution, you can skip using androidx.compose.material3.adaptive:adaptive-navigation and depend on androidx.compose.material3.adaptive:adaptive-layout directly.

When adding the Compose Adaptive library to your app, start with the most fully featured layer, and then unwrap if needed to tweak behavior. As we continue to work on the library and add new features, we'll keep adding them to the appropriate layer. Using the higher-level layers will mean that you will be able to get these new features most easily. If you need to, you can use lower layers to get more fine-grained control, but that also means that more responsibility for behavior is transferred to your app, just like the layering in Compose itself.

Try out the new components today, and send us your feedback for bugs and feature requests.

09 Sep 2024 5:01pm GMT