Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemGroup
import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemModel
import io.github.sds100.keymapper.base.utils.ui.showDialog
import io.github.sds100.keymapper.common.utils.Orientation
import io.github.sds100.keymapper.common.utils.PhysicalOrientation
import io.github.sds100.keymapper.common.utils.State
import io.github.sds100.keymapper.system.camera.CameraLens
import javax.inject.Inject
Expand Down Expand Up @@ -157,6 +158,34 @@ class ChooseConstraintViewModel @Inject constructor(
ConstraintData.OrientationCustom(orientation = Orientation.ORIENTATION_270),
)

ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT ->
returnResult.emit(
ConstraintData.PhysicalOrientationConstraint(
physicalOrientation = PhysicalOrientation.PORTRAIT,
),
)

ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE ->
returnResult.emit(
ConstraintData.PhysicalOrientationConstraint(
physicalOrientation = PhysicalOrientation.LANDSCAPE,
),
)

ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED ->
returnResult.emit(
ConstraintData.PhysicalOrientationConstraint(
physicalOrientation = PhysicalOrientation.PORTRAIT_INVERTED,
),
)

ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED ->
returnResult.emit(
ConstraintData.PhysicalOrientationConstraint(
physicalOrientation = PhysicalOrientation.LANDSCAPE_INVERTED,
),
)

ConstraintId.FLASHLIGHT_ON -> {
val lens = chooseFlashlightLens() ?: return@launch
returnResult.emit(ConstraintData.FlashlightOn(lens = lens))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.sds100.keymapper.base.constraints

import io.github.sds100.keymapper.common.utils.Orientation
import io.github.sds100.keymapper.common.utils.PhysicalOrientation
import io.github.sds100.keymapper.common.utils.getKey
import io.github.sds100.keymapper.common.utils.valueOrNull
import io.github.sds100.keymapper.data.entities.ConstraintEntity
Expand Down Expand Up @@ -87,6 +88,18 @@ sealed class ConstraintData {
}
}

@Serializable
data class PhysicalOrientationConstraint(
val physicalOrientation: PhysicalOrientation,
) : ConstraintData() {
override val id: ConstraintId = when (physicalOrientation) {
PhysicalOrientation.PORTRAIT -> ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT
PhysicalOrientation.LANDSCAPE -> ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE
PhysicalOrientation.PORTRAIT_INVERTED -> ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED
PhysicalOrientation.LANDSCAPE_INVERTED -> ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED
}
}

@Serializable
data class FlashlightOn(val lens: CameraLens) : ConstraintData() {
override val id: ConstraintId = ConstraintId.FLASHLIGHT_ON
Expand Down Expand Up @@ -316,6 +329,15 @@ object ConstraintEntityMapper {
ConstraintEntity.ORIENTATION_PORTRAIT -> ConstraintData.OrientationPortrait
ConstraintEntity.ORIENTATION_LANDSCAPE -> ConstraintData.OrientationLandscape

ConstraintEntity.PHYSICAL_ORIENTATION_PORTRAIT ->
ConstraintData.PhysicalOrientationConstraint(PhysicalOrientation.PORTRAIT)
ConstraintEntity.PHYSICAL_ORIENTATION_LANDSCAPE ->
ConstraintData.PhysicalOrientationConstraint(PhysicalOrientation.LANDSCAPE)
ConstraintEntity.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED ->
ConstraintData.PhysicalOrientationConstraint(PhysicalOrientation.PORTRAIT_INVERTED)
ConstraintEntity.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED ->
ConstraintData.PhysicalOrientationConstraint(PhysicalOrientation.LANDSCAPE_INVERTED)

ConstraintEntity.SCREEN_OFF -> ConstraintData.ScreenOff
ConstraintEntity.SCREEN_ON -> ConstraintData.ScreenOn

Expand Down Expand Up @@ -499,6 +521,25 @@ object ConstraintEntityMapper {
ConstraintEntity.ORIENTATION_PORTRAIT,
)

is ConstraintData.PhysicalOrientationConstraint -> when (constraint.data.physicalOrientation) {
PhysicalOrientation.PORTRAIT -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.PHYSICAL_ORIENTATION_PORTRAIT,
)
PhysicalOrientation.LANDSCAPE -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.PHYSICAL_ORIENTATION_LANDSCAPE,
)
PhysicalOrientation.PORTRAIT_INVERTED -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED,
)
PhysicalOrientation.LANDSCAPE_INVERTED -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED,
)
}

is ConstraintData.ScreenOff -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.SCREEN_OFF,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ enum class ConstraintDependency {
CONNECTED_BT_DEVICES,
SCREEN_STATE,
DISPLAY_ORIENTATION,
PHYSICAL_ORIENTATION,
FLASHLIGHT_STATE,
WIFI_SSID,
WIFI_STATE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ enum class ConstraintId {
ORIENTATION_180,
ORIENTATION_270,

PHYSICAL_ORIENTATION_PORTRAIT,
PHYSICAL_ORIENTATION_LANDSCAPE,
PHYSICAL_ORIENTATION_PORTRAIT_INVERTED,
PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED,

FLASHLIGHT_ON,
FLASHLIGHT_OFF,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.media.AudioManager
import android.os.Build
import io.github.sds100.keymapper.base.system.accessibility.IAccessibilityService
import io.github.sds100.keymapper.common.utils.Orientation
import io.github.sds100.keymapper.common.utils.PhysicalOrientation
import io.github.sds100.keymapper.common.utils.firstBlocking
import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo
import io.github.sds100.keymapper.system.camera.CameraAdapter
Expand Down Expand Up @@ -43,6 +44,7 @@ class LazyConstraintSnapshot(
devicesAdapter.connectedBluetoothDevices.value
}
private val orientation: Orientation by lazy { displayAdapter.cachedOrientation }
private val physicalOrientation: PhysicalOrientation by lazy { displayAdapter.cachedPhysicalOrientation }
private val isScreenOn: Boolean by lazy { displayAdapter.isScreenOn.firstBlocking() }
private val appsPlayingMedia: List<String> by lazy {
mediaAdapter.getActiveMediaSessionPackages()
Expand Down Expand Up @@ -117,6 +119,9 @@ class LazyConstraintSnapshot(
orientation == Orientation.ORIENTATION_0 ||
orientation == Orientation.ORIENTATION_180

is ConstraintData.PhysicalOrientationConstraint ->
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Just call it ConstraintData.PhysicalOrientation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in f1a7566. Renamed ConstraintData.PhysicalOrientationConstraint to ConstraintData.PhysicalOrientation.

physicalOrientation == constraint.data.physicalOrientation

is ConstraintData.ScreenOff -> !isScreenOn
is ConstraintData.ScreenOn -> isScreenOn
is ConstraintData.FlashlightOff -> !cameraAdapter.isFlashlightOn(constraint.data.lens)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import io.github.sds100.keymapper.base.R
import io.github.sds100.keymapper.base.utils.ui.ResourceProvider
import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo
import io.github.sds100.keymapper.common.utils.Orientation
import io.github.sds100.keymapper.common.utils.PhysicalOrientation
import io.github.sds100.keymapper.common.utils.TimeUtils
import io.github.sds100.keymapper.common.utils.handle
import io.github.sds100.keymapper.common.utils.valueIfFailure
Expand Down Expand Up @@ -82,6 +83,21 @@ class ConstraintUiHelper(
is ConstraintData.OrientationPortrait ->
getString(R.string.constraint_choose_orientation_portrait)

is ConstraintData.PhysicalOrientationConstraint -> {
val resId = when (constraint.data.physicalOrientation) {
PhysicalOrientation.PORTRAIT ->
R.string.constraint_choose_physical_orientation_portrait
PhysicalOrientation.LANDSCAPE ->
R.string.constraint_choose_physical_orientation_landscape
PhysicalOrientation.PORTRAIT_INVERTED ->
R.string.constraint_choose_physical_orientation_portrait_inverted
PhysicalOrientation.LANDSCAPE_INVERTED ->
R.string.constraint_choose_physical_orientation_landscape_inverted
}

getString(resId)
}

is ConstraintData.ScreenOff ->
getString(R.string.constraint_screen_off_description)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ object ConstraintUtils {
ConstraintId.ORIENTATION_90,
ConstraintId.ORIENTATION_180,
ConstraintId.ORIENTATION_270,
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT,
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE,
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED,
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED,
-> ConstraintCategory.DISPLAY

ConstraintId.FLASHLIGHT_ON,
Expand Down Expand Up @@ -142,6 +146,14 @@ object ConstraintUtils {
Icons.Outlined.StayCurrentPortrait,
)

ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT,
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED,
-> ComposeIconInfo.Vector(Icons.Outlined.StayCurrentPortrait)

ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE,
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED,
-> ComposeIconInfo.Vector(Icons.Outlined.StayCurrentLandscape)

ConstraintId.SCREEN_OFF -> ComposeIconInfo.Vector(Icons.Outlined.MobileOff)
ConstraintId.SCREEN_ON -> ComposeIconInfo.Vector(Icons.Outlined.StayCurrentPortrait)

Expand Down Expand Up @@ -200,6 +212,14 @@ object ConstraintUtils {
ConstraintId.ORIENTATION_90 -> R.string.constraint_choose_orientation_90
ConstraintId.ORIENTATION_180 -> R.string.constraint_choose_orientation_180
ConstraintId.ORIENTATION_270 -> R.string.constraint_choose_orientation_270
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT ->
R.string.constraint_choose_physical_orientation_portrait
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE ->
R.string.constraint_choose_physical_orientation_landscape
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED ->
R.string.constraint_choose_physical_orientation_portrait_inverted
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED ->
R.string.constraint_choose_physical_orientation_landscape_inverted
ConstraintId.FLASHLIGHT_ON -> R.string.constraint_flashlight_on
ConstraintId.FLASHLIGHT_OFF -> R.string.constraint_flashlight_off
ConstraintId.WIFI_ON -> R.string.constraint_wifi_on
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class DetectConstraintsUseCaseImpl @AssistedInject constructor(
ConstraintDependency.SCREEN_STATE -> displayAdapter.isScreenOn.map { dependency }
ConstraintDependency.DISPLAY_ORIENTATION ->
displayAdapter.orientation.map { dependency }
ConstraintDependency.PHYSICAL_ORIENTATION ->
displayAdapter.physicalOrientation.map { dependency }
ConstraintDependency.FLASHLIGHT_STATE -> merge(
cameraAdapter.isFlashlightOnFlow(CameraLens.FRONT),
cameraAdapter.isFlashlightOnFlow(CameraLens.BACK),
Expand Down
4 changes: 4 additions & 0 deletions base/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@
<string name="constraint_choose_orientation_270">Landscape (270°)</string>
<string name="constraint_choose_orientation_portrait">Portrait (any)</string>
<string name="constraint_choose_orientation_landscape">Landscape (any)</string>
<string name="constraint_choose_physical_orientation_portrait">Physical: Portrait</string>
<string name="constraint_choose_physical_orientation_landscape">Physical: Landscape</string>
<string name="constraint_choose_physical_orientation_portrait_inverted">Physical: Portrait (upside down)</string>
<string name="constraint_choose_physical_orientation_landscape_inverted">Physical: Landscape (inverted)</string>
<string name="constraint_choose_app_playing_media">App playing media</string>
<string name="constraint_choose_app_not_playing_media">App not playing media</string>
<string name="constraint_choose_media_playing">Media is playing</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import io.github.sds100.keymapper.base.constraints.Constraint
import io.github.sds100.keymapper.base.constraints.ConstraintData
import io.github.sds100.keymapper.base.constraints.ConstraintSnapshot
import io.github.sds100.keymapper.common.utils.Orientation
import io.github.sds100.keymapper.common.utils.PhysicalOrientation
import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo
import io.github.sds100.keymapper.system.camera.CameraLens
import io.github.sds100.keymapper.system.foldable.HingeState
Expand All @@ -17,6 +18,7 @@ class TestConstraintSnapshot(
val appInForeground: String? = null,
val connectedBluetoothDevices: Set<BluetoothDeviceInfo> = emptySet(),
val orientation: Orientation = Orientation.ORIENTATION_0,
val physicalOrientation: PhysicalOrientation = PhysicalOrientation.PORTRAIT,
val isScreenOn: Boolean = false,
val appsPlayingMedia: List<String> = emptyList(),
val isWifiEnabled: Boolean = false,
Expand Down Expand Up @@ -62,6 +64,9 @@ class TestConstraintSnapshot(
orientation == Orientation.ORIENTATION_0 ||
orientation == Orientation.ORIENTATION_180

is ConstraintData.PhysicalOrientationConstraint ->
physicalOrientation == data.physicalOrientation

is ConstraintData.ScreenOff -> !isScreenOn
is ConstraintData.ScreenOn -> isScreenOn
is ConstraintData.FlashlightOff -> when (data.lens) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.sds100.keymapper.common.utils

/**
* Represents the physical orientation of the device based on the device's
* orientation sensor (accelerometer), independent of the screen rotation setting.
*/
enum class PhysicalOrientation {
PORTRAIT,
LANDSCAPE,
PORTRAIT_INVERTED,
LANDSCAPE_INVERTED,
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ data class ConstraintEntity(
const val ORIENTATION_PORTRAIT = "constraint_orientation_portrait"
const val ORIENTATION_LANDSCAPE = "constraint_orientation_landscape"

const val PHYSICAL_ORIENTATION_PORTRAIT = "constraint_physical_orientation_portrait"
const val PHYSICAL_ORIENTATION_LANDSCAPE = "constraint_physical_orientation_landscape"
const val PHYSICAL_ORIENTATION_PORTRAIT_INVERTED = "constraint_physical_orientation_portrait_inverted"
const val PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED = "constraint_physical_orientation_landscape_inverted"

const val FLASHLIGHT_ON = "flashlight_on"
const val FLASHLIGHT_OFF = "flashlight_off"

Expand Down
Loading