Marlon López
Marlon López

Reputation: 480

How to handle device fold postures using the emulator in android studio

I'm trying to apply the Jetpack WindowManager library’s WindowLayoutInfo class, which provides information about foldable displays (flat, half_opened, etc), im following the codelab for adaptative uis (url 01), in android studio, i created an instance of the emulator for a resizable device (this is experimental feature of last stable ide), but, when testing the app, the foldable states are the normal ones, checking the following function, it always returning the default posture (Normal):

I need some ideas for configuring the emulator for this feature. While unit testing is ok, the testing in the ui isnt checking the foldable state.

Thanks in advance.

Url 01: https://developer.android.com/codelabs/android-window-manager-dual-screen-foldables?hl=es-419#5

-- Kotlin code:

sealed interface DevicePosture {
  object NormalPosture : DevicePosture

  data class BookPosture(
    val hingePosition: Rect
  ) : DevicePosture

  data class Separating(
    val hingePosition: Rect, var orientation: FoldingFeature.Orientation
  ) : DevicePosture
}

@OptIn(ExperimentalContracts::class)
fun isBookPosture(foldFeature: FoldingFeature?): Boolean {
  contract { returns(true) implies (foldFeature != null) }
  return foldFeature?.state == FoldingFeature.State.HALF_OPENED && foldFeature.orientation == FoldingFeature.Orientation.VERTICAL
}

@OptIn(ExperimentalContracts::class)
fun isSeparating(foldFeature: FoldingFeature?): Boolean {
  contract { returns(true) implies (foldFeature != null) }
  return foldFeature?.state == FoldingFeature.State.FLAT && foldFeature.isSeparating
}

/* ... */
val devicePostureFlow = WindowInfoTracker.getOrCreate(this).windowLayoutInfo(this)
  .flowWithLifecycle(this.lifecycle)
  .map { layoutInfo ->
    val foldingFeature = layoutInfo.displayFeatures.filterIsInstance().firstOrNull()
    when {
      isBookPosture(foldingFeature) -> DevicePosture.BookPosture(foldingFeature.bounds)
      isSeparating(foldingFeature) -> DevicePosture.Separating(foldingFeature.bounds, foldingFeature.orientation)
      else -> DevicePosture.NormalPosture
    }
  }
  .stateIn(
    scope = lifecycleScope,
    started = SharingStarted.Eagerly,
    initialValue = DevicePosture.NormalPosture
  )

-- I'm also following this tutorial from web: Large Screens & Foldables Tutorial for Android

Upvotes: 1

Views: 1950

Answers (2)

Paul Lammertsma
Paul Lammertsma

Reputation: 38282

I would suggest taking the code snippet from the developer guide on Make your app fold aware. The essential section is "Features of foldable displays", that consists of two parts:

  1. Inside the lifecycleScope, we use lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) to ensure that the block is executed when the lifecycle is started and is cancelled when the lifecycle is stopped, and executed when the lifecycle is started again, etc.
  2. That block then executes WindowInfoTracker.getOrCreate(this@MainActivity) to collect displayFeatures information. By placing it in that block, it's executed and cancelled at the right time together with the lifecycle.

Upvotes: 0

khalp
khalp

Reputation: 71

For the resizable emulator, you can uncheck the Launch in the Running Devices tool window option in Settings > Tools > Emulator. Emulator settings in Android Studio

Then, you will have access to Change posture button in the sidebar. Change posture option in emulator sidebar

However, it may be easier to just use a dedicated foldable emulator, like the 6.7 horizontal fold-in, 7.6 fold-in with outer display, 8 fold-out, or Pixel Fold. These will all have controls in the Extended Controls three-dot menu under Virtual sensors to change the device's posture. Extended controls for foldable emulator

Upvotes: 4

Related Questions