Jetpack Window Manager for Xamarin beta

Important

This article describes functionality and guidance that is in public preview and may be substantially modified before it's generally available. Microsoft makes no warranties, express or implied, with respect to the information provided here.

Tip

Xamarin.Forms users should reference the Xamarin.Forms.DualScreen NuGet for Surface Duo support, with its DualScreenInfo and TwoPaneView classes.

Window Manager is intended for developers working with Xamarin.Android projects.

Jetpack Window Manager (currently in beta) provides a standard API for working with all foldable devices. It contains two important classes:

  • DisplayFeature - Identifies disruptions in the continuous flat screen surface such as hinges or folds. Window Manager will return a collection of display features from a layout change callback.
  • FoldingFeature - Provides information about a specific feature of the device - while the Surface Duo only has one folding feature, it's possible that other devices might have more. The FoldingFeature class provides information about the state of that part of the device, with properties for Bounds and IsSeparating, and methods for OcclusionType, Orientation, and State.

Samples using the Window Manager beta are available in the surface-duo-sdk-xamarin-samples repo.

Note

The Xamarin.AndroidX.Window.WindowJava NuGet is intended to replace the need to add the Xamarin.DuoSDK NuGet to Xamarin.Android apps.

Instead of using the ScreenHelper class to determine IsDualMode or to GetHingeBoundsDip(), you can use the methods and properties on WindowInfoRepository directly.

To use the WindowInfoRepository in your code, follow the instructions below (from the Xamarin.Android Window Manager sample app):

Add dependency

To add the Window Manager NuGet:

  1. Right-click on your Xamarin.Android project and choose Manage NuGet Packages...

  2. Ensure that Include prerelease is checked, and search for Xamarin.AndroidX.Window.WindowJava.

  3. Choose the highest version number to add to your project (currently 1.0.0.1-beta01).

Note

The library name includes "beta" - the Window Manager APIs are currently still in preview.

Use Window Manager in your code

  1. In the MainActivity class, declare a variable for the window information repository:

    public class MainActivity : AppCompatActivity, IConsumer
    {
        WindowInfoRepositoryCallbackAdapter wir;
    

    Ensure that the correct using AndroidX.Window.Layout; and using AndroidX.Window.Java.Layout; statements are added to the top of the file.

    Note

    The activity also implements IConsumer, see step 4 below for the code for the Accept method required by this interface.

  2. Initialize the window manager in your activity's OnCreate:

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            wir = new WindowInfoRepositoryCallbackAdapter(WindowInfoRepository.Companion.GetOrCreate(this));
    
  3. Now create function that returns an IExecutor implementation so we provide it to the callback as the first parameter and it will be invoked using it. We are going to create one that runs on the UI thread, you can create a different one that doesn’t run on the UI thread if required.

    IExecutor runOnUiThreadExecutor()
    {
        return new MyExecutor();
    }
    class MyExecutor : Java.Lang.Object, IExecutor
    {
        Handler handler = new Handler(Looper.MainLooper);
        public void Execute(IRunnable r)
        {
            handler.Post(r);
        }
    }
    
  4. Define an inner class to handle the callback when the layout needs to change. The activity should have a TextView called layoutChange so that this method can update the displayed text:

    public void Accept(Java.Lang.Object newLayoutInfo)  // Object will be WindowLayoutInfo
    {
        var newLayoutInfo = (newLayoutInfo as WindowLayoutInfo); // have to cast before use
    
        layoutChange.Text = newLayoutInfo.ToString();
    
        configurationChanged.Text = "One logic/physical display - unspanned";
    
        foreach (var displayFeature in newLayoutInfo.DisplayFeatures)
        {
            var foldingFeature = displayFeature.JavaCast<IFoldingFeature>();
    
            if (foldingFeature != null)
            {
                alignViewToDeviceFeatureBoundaries(newLayoutInfo);
    
                if (foldingFeature.GetOcclusionType() == FoldingFeatureOcclusionType.None)
                {
                    configurationChanged.Text = "App is spanned across a fold";
                }
                if (foldingFeature.GetOcclusionType() == FoldingFeatureOcclusionType.Full)
                {
                    configurationChanged.Text = "App is spanned across a hinge";
                }
                configurationChanged.Text += "\nIsSeparating: " + foldingFeature.IsSeparating
                        + "\nOrientation: " + foldingFeature.Orientation  // FoldingFeatureOrientation.Vertical or Horizontal
                        + "\nState: " + foldingFeature.State; // FoldingFeatureState.Flat or State.HalfOpened
            }
            else
            {
                Log.Info(TAG, "DisplayFeature is not a fold/hinge");
            }
        }
    }
    

    Note

    The WindowLayoutInfo class has a collection of DisplayFeature items, one or more of which could be instances of FoldingFeature. Folding feature instances have properties for Boundsand IsSeparating, and methods for OcclusionType, Orientation, and State that you can query to make decisions about how to adjust your layout for the new state.

  5. In an OnStart override, register the AddWindowLayoutInfoListener handler and pass the executor and a reference to the activity (because it implements IConsumer).

    protected override void OnStart()
    {
        base.OnStart();
        wir.AddWindowLayoutInfoListener(runOnUiThreadExecutor(), this); // `this` is the IConsumer implementation
    }
    
  6. Remember to remove the listener:

    protected override void OnStop()
    {
        base.OnStop();
        wir.RemoveWindowLayoutInfoListener(this);
    }
    
  7. When this code is run, the activity will update with the current device posture and display features (if spanned across the fold or hinge). Add additional code to the callback to check for additional information in the FoldingFeature object.

Sample

The Window Manager sample shows device information on the screen as shown in this screenshot:

Surface Duo showing Window Manager sample running, and showing device info on the screen

Resources