July 2nd, 2020

Hinge Angle on Microsoft Surface Duo

Joy Liu
Senior Software Engineer

Hello Surface Duo developers!

In our previous blog post, we mentioned how to adjust the hinge angle in the Surface Duo emulator. Today we are going to present some ideas about how to take advantage of this unique behavior of the Surface Duo device.

As we discussed in How to Bring Your Android Apps to Surface Duo, your Android apps will work on Surface Duo just as it does on any Android device. But how can your app benefit from the dual-screen and the special hinge posture? To give you a visible picture, we created a Hinge Angle Sample in Kotlin, which contains a draw board supporting Microsoft Surface Pen with some cool features only available in the Surface Duo device.

Project Setup

If you follow our blogs or read our documentation, we walk you through the steps of how to use the Surface Duo SDK to optimize your app for dual-screen devices. Since we are building a sample from the scratch, let’s start from the beginning and follow the steps below to get started:

  1. Download the Surface Duo SDK
  2. Install the latest emulator
  3. Set up DualScreen-Layout

Once you have completed the steps above, you will be able to view your app in dual-screen mode in Design Preview of Android Studio:

Android Studio design preview with color palette

Figure 1: Dual-landscape mode in Design Preview in Android Studio

Now let’s see how we can leverage the dual-screen.

Mirror Drawing

There are two types of draw mirroring included in the sample; mirror drawing when spanned, and live draw mirroring.

Animated painting with reflection over the hinge

Figure 2: Mirroring the drawing when spanned

In this example, the app starts from the single screen and features a color picker and a clear button as the basic tools to use while drawing. You can do some random drawing on this screen to test it out. When you span the single screen to dual-screen mode, your drawing will be mirrored on the second screen.

The basic idea is to create two fragments to manage the mirror function. While spanning, the second fragment is created and goes through the same life cycle when the device is rotated. Since the single screen fragment will be re-created as a fragment on the dual-screen, the ViewModel is used to retain the previous drawing and copy the drawing to the second screen. The drawing is captured with Bitmap which makes it easy to flip with Matrix.

Animated painting with reflection over the hinge

Figure 3: Live draw mirroring in HingeAngle sample

For the live draw mirroring while in dual-screen mode, when you are drawing in the main screen, the second screen will show the reflected image.

The trick here is the ViewTreeObserver setting which observes the onDraw function in the “View” and with LiveData settings, the second screen can respond accordingly.

Hinge Angle Detect

Animation of stroke width changing

Figure 4: Drawing render when folding/unfolding

You can see in the sample that there is a label showing the number which is used to represent the current hinge angle of the device. As discussed in the Hinge Angle Sensor API documentation, we can detect the hinge angle with the SensorEventListener. Here is some sample code in Kotlin for reference:

private val hingeAngleSensorListener = object : SensorEventListener {
    override fun onSensorChanged(event: SensorEvent) {
        if (event.sensor == hingeAngleSensor) {
            val angle = event.values[0].toInt()
            val viewModel = ViewModelProvider(requireActivity()).get(ViewModel::class.java)
            viewModel.setHingeAngleLiveData(angle)
        }
    }

    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
    }
}

private fun setupSensors() {
    sensorManager = requireActivity().getSystemService(Service.SENSOR_SERVICE) as SensorManager?
    sensorManager?.let {
        val sensorList: List = it.getSensorList(Sensor.TYPE_ALL)
        for (sensor in sensorList) {
            if (sensor.name.contains(HINGE_ANGLE_SENSOR_NAME)) {
                hingeAngleSensor = sensor
            }
        }
    }
}

You can see ViewModel and LiveData are used here again to save the hinge angle returning from SensorEventListener. This enables the app to observe these values and implement features accordingly. In the sample, we render the drawing based on the hinge angle to achieve the gradient effect.

To test it in the emulator, go to the Extended controls window, select Virtual Sensors > Additional sensors and slide the Pressure control between 0 and 360 as mentioned in our Surface Duo testing tips and tricks blog post. When adjusting the hinge angle in the emulator, or when you fold or unfold the device, you will see the drawing changing gradually. We are still working on implementing additional methods to enable more visible control, so stay tuned to future blog posts for more tips!

Adjusting pen stroke width using pressure setting

In previous blogs, we also talked about Pen Events with Microsoft Surface Pen. In our sample below, we have also used the pen pressure setting (which usually falls between 0 to 1) to modify the stroke width of Paint class used in the drawing.

Screenshot of reflected painting on both screens

Figure 5: Drawing render in HingeAngle sample

Feedback

I hope this sample provides you with some additional ways to enhance the user experience in your app to take advantage of the distinctive features of the Microsoft Surface Duo device.

All of our sample code is open sourced and we welcome your contributions directly in our GitHub repo to evolve the sample into an awesome Rorschach Painter! We’d love to hear from you so please leave us feedback using our feedback forum, or message me on Twitter or GitHub.

Author

Joy Liu
Senior Software Engineer

Works on the Surface Duo dual-screen SDK, emulator, Jetpack Compose, samples, and customer engagement.

0 comments

Discussion are closed.