react-native-orientation-director 1.2.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -18
- package/android/build.gradle +13 -1
- package/android/gradle.properties +12 -0
- package/android/src/main/java/com/orientationdirector/OrientationDirectorPackage.kt +5 -4
- package/android/src/main/java/com/orientationdirector/implementation/EventManager.kt +0 -1
- package/android/src/main/java/com/orientationdirector/implementation/LifecycleListener.kt +1 -1
- package/android/src/main/java/com/orientationdirector/implementation/Orientation.kt +2 -0
- package/android/src/main/java/com/orientationdirector/implementation/{OrientationDirectorImpl.kt → OrientationDirectorModuleImpl.kt} +47 -33
- package/android/src/main/java/com/orientationdirector/implementation/OrientationSensorsEventListener.kt +79 -0
- package/android/src/main/java/com/orientationdirector/implementation/Utils.kt +28 -15
- package/android/src/newarch/OrientationDirectorModule.kt +59 -0
- package/android/src/oldarch/OrientationDirectorModule.kt +66 -0
- package/android/src/test/java/com/orientationdirector/implementation/OrientationDirectorModuleImplTest.kt +188 -0
- package/android/src/test/java/com/orientationdirector/implementation/UtilsTest.kt +314 -0
- package/ios/OrientationDirector.mm +12 -37
- package/lib/commonjs/EventEmitter.js +50 -0
- package/lib/commonjs/EventEmitter.js.map +1 -0
- package/lib/commonjs/NativeOrientationDirector.js.map +1 -1
- package/lib/commonjs/RNOrientationDirector.js +21 -12
- package/lib/commonjs/RNOrientationDirector.js.map +1 -1
- package/lib/commonjs/hooks/useDeviceOrientation.hook.js +1 -1
- package/lib/commonjs/hooks/useDeviceOrientation.hook.js.map +1 -1
- package/lib/commonjs/hooks/useInterfaceOrientation.hook.js +1 -1
- package/lib/commonjs/hooks/useInterfaceOrientation.hook.js.map +1 -1
- package/lib/commonjs/hooks/useIsInterfaceOrientationLocked.hook.js +1 -1
- package/lib/commonjs/hooks/useIsInterfaceOrientationLocked.hook.js.map +1 -1
- package/lib/commonjs/index.js +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/module.js +2 -2
- package/lib/commonjs/module.js.map +1 -1
- package/lib/commonjs/types/{InterfaceOrientationToLocalizedStringProvider.type.js → HumanReadableAutoRotationsResource.type.js} +1 -1
- package/lib/commonjs/types/HumanReadableAutoRotationsResource.type.js.map +1 -0
- package/lib/commonjs/types/HumanReadableOrientationsResource.type.js +6 -0
- package/lib/commonjs/types/HumanReadableOrientationsResource.type.js.map +1 -0
- package/lib/module/EventEmitter.js +41 -0
- package/lib/module/EventEmitter.js.map +1 -0
- package/lib/module/NativeOrientationDirector.js.map +1 -1
- package/lib/module/RNOrientationDirector.js +20 -9
- package/lib/module/RNOrientationDirector.js.map +1 -1
- package/lib/module/module.js +1 -1
- package/lib/module/module.js.map +1 -1
- package/lib/module/types/HumanReadableAutoRotationsResource.type.js +2 -0
- package/lib/module/types/HumanReadableAutoRotationsResource.type.js.map +1 -0
- package/lib/module/types/HumanReadableOrientationsResource.type.js +2 -0
- package/lib/module/types/HumanReadableOrientationsResource.type.js.map +1 -0
- package/lib/typescript/src/EventEmitter.d.ts +11 -0
- package/lib/typescript/src/EventEmitter.d.ts.map +1 -0
- package/lib/typescript/src/NativeOrientationDirector.d.ts +3 -1
- package/lib/typescript/src/NativeOrientationDirector.d.ts.map +1 -1
- package/lib/typescript/src/RNOrientationDirector.d.ts +8 -4
- package/lib/typescript/src/RNOrientationDirector.d.ts.map +1 -1
- package/lib/typescript/src/module.d.ts +1 -1
- package/lib/typescript/src/module.d.ts.map +1 -1
- package/lib/typescript/src/types/HumanReadableAutoRotationsResource.type.d.ts +3 -0
- package/lib/typescript/src/types/HumanReadableAutoRotationsResource.type.d.ts.map +1 -0
- package/lib/typescript/src/types/HumanReadableOrientationsResource.type.d.ts +3 -0
- package/lib/typescript/src/types/HumanReadableOrientationsResource.type.d.ts.map +1 -0
- package/lib/typescript/src/types/Orientation.enum.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/EventEmitter.ts +70 -0
- package/src/NativeOrientationDirector.ts +12 -1
- package/src/RNOrientationDirector.ts +34 -21
- package/src/module.ts +1 -1
- package/src/types/HumanReadableAutoRotationsResource.type.ts +3 -0
- package/src/types/HumanReadableOrientationsResource.type.ts +3 -0
- package/src/types/Orientation.enum.ts +0 -2
- package/android/src/main/java/com/orientationdirector/OrientationDirectorModule.kt +0 -65
- package/android/src/main/java/com/orientationdirector/implementation/SensorListener.kt +0 -26
- package/android/src/newarch/OrientationDirectorSpec.kt +0 -7
- package/android/src/oldarch/OrientationDirectorSpec.kt +0 -18
- package/lib/commonjs/types/InterfaceOrientationToLocalizedStringProvider.type.js.map +0 -1
- package/lib/module/types/InterfaceOrientationToLocalizedStringProvider.type.js +0 -2
- package/lib/module/types/InterfaceOrientationToLocalizedStringProvider.type.js.map +0 -1
- package/lib/typescript/src/types/InterfaceOrientationToLocalizedStringProvider.type.d.ts +0 -3
- package/lib/typescript/src/types/InterfaceOrientationToLocalizedStringProvider.type.d.ts.map +0 -1
- package/src/types/InterfaceOrientationToLocalizedStringProvider.type.ts +0 -6
package/README.md
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
# react-native-orientation-director
|
|
6
6
|
|
|
7
|
-
A
|
|
7
|
+
A React Native library that allows you to listen to orientation changes, lock interface orientation
|
|
8
|
+
to a selected one and get current orientation.
|
|
8
9
|
Written in Kotlin, Swift and Typescript. It supports both the Old and New React Native architecture.
|
|
9
10
|
|
|
10
11
|
This library takes inspiration from and builds upon the following amazing alternatives:
|
|
@@ -27,17 +28,29 @@ This library takes inspiration from and builds upon the following amazing altern
|
|
|
27
28
|
|
|
28
29
|
## Installation
|
|
29
30
|
|
|
31
|
+
### React Native Bare
|
|
32
|
+
|
|
30
33
|
You can install the package via npm or yarn:
|
|
31
34
|
|
|
32
35
|
```sh
|
|
33
36
|
npm install react-native-orientation-director
|
|
34
37
|
```
|
|
38
|
+
|
|
35
39
|
```sh
|
|
36
40
|
yarn add react-native-orientation-director
|
|
37
41
|
```
|
|
38
42
|
|
|
39
43
|
Don't forget to run pod-install.
|
|
40
44
|
|
|
45
|
+
### Expo
|
|
46
|
+
|
|
47
|
+
This library can be installed only for [Development Builds](https://docs.expo.dev/develop/development-builds/introduction/)
|
|
48
|
+
using the following command:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
npx expo install react-native-orientation-director
|
|
52
|
+
```
|
|
53
|
+
|
|
41
54
|
## Setup
|
|
42
55
|
|
|
43
56
|
To properly handle interface orientation changes in iOS, you need to update your AppDelegate.mm file.
|
|
@@ -60,36 +73,47 @@ There is no need to do anything in Android, it works out of the box.
|
|
|
60
73
|
|
|
61
74
|
This library exports a class called: [RNOrientationDirector](https://github.com/gladiuscode/react-native-orientation-director/blob/main/src/RNOrientationDirector.ts) that exposes the following methods:
|
|
62
75
|
|
|
63
|
-
| Method
|
|
64
|
-
|
|
65
|
-
| getInterfaceOrientation
|
|
66
|
-
| getDeviceOrientation
|
|
67
|
-
| lockTo
|
|
68
|
-
| unlock
|
|
69
|
-
| isLocked
|
|
70
|
-
| isAutoRotationEnabled
|
|
71
|
-
| listenForDeviceOrientationChanges
|
|
72
|
-
| listenForInterfaceOrientationChanges
|
|
73
|
-
| listenForLockChanges
|
|
74
|
-
| convertOrientationToHumanReadableString
|
|
75
|
-
|
|
|
76
|
-
|
|
|
76
|
+
| Method | Description |
|
|
77
|
+
| ---------------------------------------- | --------------------------------------------------------------------------------- |
|
|
78
|
+
| getInterfaceOrientation | Returns the last interface orientation |
|
|
79
|
+
| getDeviceOrientation | Returns the last device orientation |
|
|
80
|
+
| lockTo | Locks the interface to a specific orientation |
|
|
81
|
+
| unlock | Unlock the interface |
|
|
82
|
+
| isLocked | Returns the current interface orientation status (locked / unlocked) |
|
|
83
|
+
| isAutoRotationEnabled | (Android Only) Returns if auto rotation is enabled |
|
|
84
|
+
| listenForDeviceOrientationChanges | Triggers a provided callback each time the device orientation changes |
|
|
85
|
+
| listenForInterfaceOrientationChanges | Triggers a provided callback each time the interface orientation changes |
|
|
86
|
+
| listenForLockChanges | Triggers a provided callback each time the interface orientation status changes |
|
|
87
|
+
| convertOrientationToHumanReadableString | Returns a human readable string based on the given orientation |
|
|
88
|
+
| convertAutoRotationToHumanReadableString | Returns a human readable string based on the given auto rotation |
|
|
89
|
+
| setHumanReadableOrientations | Sets the mapping needed to convert orientation values to human readable strings |
|
|
90
|
+
| setHumanReadableAutoRotations | Sets the mapping needed to convert auto rotation values to human readable strings |
|
|
91
|
+
| resetSupportedInterfaceOrientations | Resets the supported interface orientations to settings |
|
|
77
92
|
|
|
78
93
|
In addition, the library exposes the following hooks:
|
|
79
94
|
|
|
80
95
|
| Hook | Description |
|
|
81
|
-
|
|
96
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
82
97
|
| [useInterfaceOrientation](https://github.com/gladiuscode/react-native-orientation-director/blob/main/src/hooks/useInterfaceOrientation.hook.ts) | Returns the current interface orientation and listens to changes |
|
|
83
98
|
| [useDeviceOrientation](https://github.com/gladiuscode/react-native-orientation-director/blob/main/src/hooks/useDeviceOrientation.hook.ts) | Returns the current device orientation and listens to changes |
|
|
84
99
|
| [useIsInterfaceOrientationLocked](https://github.com/gladiuscode/react-native-orientation-director/blob/main/src/hooks/useIsInterfaceOrientationLocked.hook.ts) | Returns the current interface orientation status and listens to changes |
|
|
85
100
|
|
|
86
101
|
Head over to the [example project](example) to see how to use the library.
|
|
87
102
|
|
|
103
|
+
### Android
|
|
104
|
+
|
|
105
|
+
Since on Android we need to deal with sensors and their usage, it is worth noting that the device orientation computation works
|
|
106
|
+
differently than on iOS, mainly in the following ways:
|
|
107
|
+
|
|
108
|
+
1. Upon start up, all required sensors are enabled just for the initial device orientation computation, then they are disabled;
|
|
109
|
+
2. Each time a new device orientation listener is added, all required sensors are enabled if disabled;
|
|
110
|
+
3. After the last device orientation listener is removed, all required sensors are disabled;
|
|
111
|
+
|
|
112
|
+
This behavior allows us to follow Google's best practices related to the Sensors Framework. More [here](https://developer.android.com/develop/sensors-and-location/sensors/sensors_overview#sensors-practices).
|
|
113
|
+
|
|
88
114
|
## Roadmap
|
|
89
115
|
|
|
90
|
-
- [ ] Add support for Expo
|
|
91
116
|
- [ ] Add JS side tests
|
|
92
|
-
- [ ] Add Android side tests
|
|
93
117
|
- [ ] Add iOS side tests
|
|
94
118
|
|
|
95
119
|
## Contributing
|
package/android/build.gradle
CHANGED
|
@@ -33,6 +33,10 @@ def getExtOrIntegerDefault(name) {
|
|
|
33
33
|
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["OrientationDirector_" + name]).toInteger()
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
def getDefault(name) {
|
|
37
|
+
return project.properties["OrientationDirector_" + name]
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
def supportsNamespace() {
|
|
37
41
|
def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
|
|
38
42
|
def major = parsed[0].toInteger()
|
|
@@ -59,7 +63,6 @@ android {
|
|
|
59
63
|
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
60
64
|
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
61
65
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
62
|
-
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
buildFeatures {
|
|
@@ -102,6 +105,10 @@ repositories {
|
|
|
102
105
|
}
|
|
103
106
|
|
|
104
107
|
def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
108
|
+
def junit_version = getDefault("junitVersion")
|
|
109
|
+
def android_x_core_version = getDefault("androidXCoreVersion")
|
|
110
|
+
def robolectric_version = getDefault("robolectricVersion")
|
|
111
|
+
def mockito_core_version = getDefault("mockitoCoreVersion")
|
|
105
112
|
|
|
106
113
|
dependencies {
|
|
107
114
|
// For < 0.71, this will be from the local maven repo
|
|
@@ -109,6 +116,11 @@ dependencies {
|
|
|
109
116
|
//noinspection GradleDynamicVersion
|
|
110
117
|
implementation "com.facebook.react:react-native:+"
|
|
111
118
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
119
|
+
|
|
120
|
+
testImplementation "junit:junit:$junit_version"
|
|
121
|
+
testImplementation "androidx.test:core:$android_x_core_version"
|
|
122
|
+
testImplementation "org.robolectric:robolectric:$robolectric_version"
|
|
123
|
+
testImplementation "org.mockito:mockito-core:$mockito_core_version"
|
|
112
124
|
}
|
|
113
125
|
|
|
114
126
|
if (isNewArchitectureEnabled()) {
|
|
@@ -3,3 +3,15 @@ OrientationDirector_minSdkVersion=21
|
|
|
3
3
|
OrientationDirector_targetSdkVersion=31
|
|
4
4
|
OrientationDirector_compileSdkVersion=31
|
|
5
5
|
OrientationDirector_ndkversion=21.4.7075529
|
|
6
|
+
|
|
7
|
+
#########################
|
|
8
|
+
# TESTING
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
OrientationDirector_junitVersion=4.13.2
|
|
12
|
+
OrientationDirector_androidXCoreVersion=1.5.+
|
|
13
|
+
OrientationDirector_robolectricVersion=4.13
|
|
14
|
+
OrientationDirector_mockitoCoreVersion=5.14.2
|
|
15
|
+
|
|
16
|
+
#
|
|
17
|
+
#########################
|
|
@@ -5,11 +5,12 @@ import com.facebook.react.bridge.ReactApplicationContext
|
|
|
5
5
|
import com.facebook.react.bridge.NativeModule
|
|
6
6
|
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
7
7
|
import com.facebook.react.module.model.ReactModuleInfo
|
|
8
|
+
import com.orientationdirector.implementation.OrientationDirectorModuleImpl
|
|
8
9
|
import java.util.HashMap
|
|
9
10
|
|
|
10
11
|
class OrientationDirectorPackage : TurboReactPackage() {
|
|
11
12
|
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
12
|
-
return if (name ==
|
|
13
|
+
return if (name == OrientationDirectorModuleImpl.NAME) {
|
|
13
14
|
OrientationDirectorModule(reactContext)
|
|
14
15
|
} else {
|
|
15
16
|
null
|
|
@@ -20,9 +21,9 @@ class OrientationDirectorPackage : TurboReactPackage() {
|
|
|
20
21
|
return ReactModuleInfoProvider {
|
|
21
22
|
val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
|
|
22
23
|
val isTurboModule: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
|
23
|
-
moduleInfos[
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
moduleInfos[OrientationDirectorModuleImpl.NAME] = ReactModuleInfo(
|
|
25
|
+
OrientationDirectorModuleImpl.NAME,
|
|
26
|
+
OrientationDirectorModuleImpl.NAME,
|
|
26
27
|
false, // canOverrideExistingModule
|
|
27
28
|
false, // needsEagerInit
|
|
28
29
|
true, // hasConstants
|
|
@@ -2,7 +2,7 @@ package com.orientationdirector.implementation
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
4
4
|
|
|
5
|
-
class LifecycleListener
|
|
5
|
+
class LifecycleListener : LifecycleEventListener {
|
|
6
6
|
|
|
7
7
|
private var onHostResumeCallback: (() -> Unit)? = null
|
|
8
8
|
private var onHostPauseCallback: (() -> Unit)? = null
|
|
@@ -3,13 +3,12 @@ package com.orientationdirector.implementation
|
|
|
3
3
|
import android.content.pm.ActivityInfo
|
|
4
4
|
import android.os.Handler
|
|
5
5
|
import android.os.Looper
|
|
6
|
-
import android.view.OrientationEventListener.ORIENTATION_UNKNOWN
|
|
7
6
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
8
7
|
|
|
9
|
-
class
|
|
8
|
+
class OrientationDirectorModuleImpl internal constructor(private val context: ReactApplicationContext) {
|
|
10
9
|
private var mUtils = Utils(context)
|
|
11
10
|
private var mEventManager = EventManager(context)
|
|
12
|
-
private var
|
|
11
|
+
private var mOrientationSensorsEventListener = OrientationSensorsEventListener(context)
|
|
13
12
|
private var mAutoRotationObserver = AutoRotationObserver(
|
|
14
13
|
context, Handler(
|
|
15
14
|
Looper.getMainLooper()
|
|
@@ -22,43 +21,39 @@ class OrientationDirectorImpl internal constructor(private val context: ReactApp
|
|
|
22
21
|
private var lastDeviceOrientation = Orientation.UNKNOWN
|
|
23
22
|
private var initialized = false
|
|
24
23
|
private var isLocked: Boolean = false
|
|
24
|
+
private var areOrientationSensorsEnabled = false;
|
|
25
|
+
private var didComputeInitialDeviceOrientation = false;
|
|
25
26
|
|
|
26
27
|
init {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (mSensorListener.canDetectOrientation()) {
|
|
32
|
-
mSensorListener.enable()
|
|
33
|
-
} else {
|
|
34
|
-
mSensorListener.disable()
|
|
28
|
+
mOrientationSensorsEventListener.setOnOrientationAnglesChangedCallback { orientation ->
|
|
29
|
+
onOrientationAnglesChanged(orientation)
|
|
35
30
|
}
|
|
36
31
|
|
|
37
32
|
mAutoRotationObserver.enable()
|
|
38
33
|
|
|
39
34
|
context.addLifecycleEventListener(mLifecycleListener)
|
|
40
35
|
mLifecycleListener.setOnHostResumeCallback {
|
|
41
|
-
if (
|
|
42
|
-
|
|
36
|
+
if (!didComputeInitialDeviceOrientation || areOrientationSensorsEnabled) {
|
|
37
|
+
mOrientationSensorsEventListener.enable()
|
|
43
38
|
}
|
|
44
|
-
|
|
45
39
|
mAutoRotationObserver.enable()
|
|
46
40
|
}
|
|
47
41
|
mLifecycleListener.setOnHostPauseCallback {
|
|
48
|
-
if (initialized) {
|
|
49
|
-
|
|
42
|
+
if (initialized && areOrientationSensorsEnabled) {
|
|
43
|
+
mOrientationSensorsEventListener.disable()
|
|
50
44
|
mAutoRotationObserver.disable()
|
|
51
45
|
}
|
|
52
46
|
}
|
|
53
47
|
mLifecycleListener.setOnHostDestroyCallback {
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
if (areOrientationSensorsEnabled) {
|
|
49
|
+
mOrientationSensorsEventListener.disable()
|
|
50
|
+
mAutoRotationObserver.disable()
|
|
51
|
+
}
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
initialSupportedInterfaceOrientations =
|
|
59
55
|
context.currentActivity?.requestedOrientation ?: initialSupportedInterfaceOrientations
|
|
60
56
|
lastInterfaceOrientation = initInterfaceOrientation()
|
|
61
|
-
lastDeviceOrientation = initDeviceOrientation()
|
|
62
57
|
isLocked = initIsLocked()
|
|
63
58
|
|
|
64
59
|
initialized = true
|
|
@@ -103,16 +98,19 @@ class OrientationDirectorImpl internal constructor(private val context: ReactApp
|
|
|
103
98
|
updateLastInterfaceOrientationTo(initInterfaceOrientation())
|
|
104
99
|
}
|
|
105
100
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
fun enableOrientationSensors() {
|
|
102
|
+
areOrientationSensorsEnabled = true
|
|
103
|
+
mOrientationSensorsEventListener.enable()
|
|
109
104
|
}
|
|
110
105
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
106
|
+
fun disableOrientationSensors() {
|
|
107
|
+
areOrientationSensorsEnabled = false
|
|
108
|
+
mOrientationSensorsEventListener.disable()
|
|
109
|
+
}
|
|
114
110
|
|
|
115
|
-
|
|
111
|
+
private fun initInterfaceOrientation(): Orientation {
|
|
112
|
+
val rotation = mUtils.getInterfaceRotation()
|
|
113
|
+
return mUtils.convertToOrientationFromScreenRotation(rotation)
|
|
116
114
|
}
|
|
117
115
|
|
|
118
116
|
private fun initIsLocked(): Boolean {
|
|
@@ -126,11 +124,10 @@ class OrientationDirectorImpl internal constructor(private val context: ReactApp
|
|
|
126
124
|
).contains(activity.requestedOrientation)
|
|
127
125
|
}
|
|
128
126
|
|
|
129
|
-
private fun
|
|
130
|
-
val deviceOrientation = mUtils.convertToDeviceOrientationFrom(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return;
|
|
127
|
+
private fun onOrientationAnglesChanged(orientationAngles: FloatArray) {
|
|
128
|
+
val deviceOrientation = mUtils.convertToDeviceOrientationFrom(orientationAngles)
|
|
129
|
+
if (deviceOrientation == Orientation.UNKNOWN) {
|
|
130
|
+
return
|
|
134
131
|
}
|
|
135
132
|
|
|
136
133
|
if (lastDeviceOrientation == deviceOrientation) {
|
|
@@ -141,6 +138,11 @@ class OrientationDirectorImpl internal constructor(private val context: ReactApp
|
|
|
141
138
|
lastDeviceOrientation = deviceOrientation
|
|
142
139
|
|
|
143
140
|
adaptInterfaceTo(deviceOrientation)
|
|
141
|
+
|
|
142
|
+
if (!didComputeInitialDeviceOrientation) {
|
|
143
|
+
didComputeInitialDeviceOrientation = true
|
|
144
|
+
mOrientationSensorsEventListener.disable()
|
|
145
|
+
}
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
private fun adaptInterfaceTo(deviceOrientation: Orientation) {
|
|
@@ -152,7 +154,19 @@ class OrientationDirectorImpl internal constructor(private val context: ReactApp
|
|
|
152
154
|
return
|
|
153
155
|
}
|
|
154
156
|
|
|
155
|
-
|
|
157
|
+
var newInterfaceOrientation = mUtils.convertToInterfaceOrientationFrom(deviceOrientation);
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* When the device orientation is either face up or face down,
|
|
161
|
+
* we can't match it to an interface orientation, because
|
|
162
|
+
* it could be either portrait or any landscape.
|
|
163
|
+
* So we read it from the system itself.
|
|
164
|
+
*/
|
|
165
|
+
if (newInterfaceOrientation == Orientation.UNKNOWN) {
|
|
166
|
+
val rotation = mUtils.getInterfaceRotation()
|
|
167
|
+
newInterfaceOrientation = mUtils.convertToOrientationFromScreenRotation(rotation)
|
|
168
|
+
}
|
|
169
|
+
|
|
156
170
|
if (newInterfaceOrientation == lastInterfaceOrientation) {
|
|
157
171
|
return
|
|
158
172
|
}
|
|
@@ -171,6 +185,6 @@ class OrientationDirectorImpl internal constructor(private val context: ReactApp
|
|
|
171
185
|
}
|
|
172
186
|
|
|
173
187
|
companion object {
|
|
174
|
-
const val NAME = "
|
|
188
|
+
const val NAME = "OrientationDirector"
|
|
175
189
|
}
|
|
176
190
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package com.orientationdirector.implementation
|
|
2
|
+
|
|
3
|
+
import android.content.Context.SENSOR_SERVICE
|
|
4
|
+
import android.hardware.Sensor
|
|
5
|
+
import android.hardware.SensorEvent
|
|
6
|
+
import android.hardware.SensorEventListener
|
|
7
|
+
import android.hardware.SensorManager
|
|
8
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
9
|
+
|
|
10
|
+
class OrientationSensorsEventListener(
|
|
11
|
+
context: ReactApplicationContext,
|
|
12
|
+
) : SensorEventListener {
|
|
13
|
+
private var mSensorManager: SensorManager = context.getSystemService(SENSOR_SERVICE) as SensorManager
|
|
14
|
+
|
|
15
|
+
private var mAccelerometerSensor: Sensor? = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
|
|
16
|
+
private var mMagneticFieldSensor: Sensor? = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
|
|
17
|
+
|
|
18
|
+
private var hasRequiredSensors: Boolean = mAccelerometerSensor != null && mMagneticFieldSensor != null
|
|
19
|
+
|
|
20
|
+
private val accelerometerReading = FloatArray(3)
|
|
21
|
+
private val magnetometerReading = FloatArray(3)
|
|
22
|
+
|
|
23
|
+
private var lastComputedOrientationAngles = FloatArray(3)
|
|
24
|
+
private var onOrientationAnglesChangedCallback: ((orientationAngles: FloatArray) -> Unit)? = null
|
|
25
|
+
|
|
26
|
+
fun setOnOrientationAnglesChangedCallback(callback: (orientation: FloatArray) -> Unit) {
|
|
27
|
+
onOrientationAnglesChangedCallback = callback
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override fun onSensorChanged(event: SensorEvent?) {
|
|
31
|
+
if (event == null) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
|
|
36
|
+
System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.size)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD) {
|
|
40
|
+
System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
val rotationMatrix = FloatArray(9)
|
|
44
|
+
val didComputeMatrix = SensorManager.getRotationMatrix(
|
|
45
|
+
rotationMatrix,
|
|
46
|
+
null,
|
|
47
|
+
accelerometerReading,
|
|
48
|
+
magnetometerReading
|
|
49
|
+
)
|
|
50
|
+
if (!didComputeMatrix) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
val orientationAngles = FloatArray(3)
|
|
55
|
+
SensorManager.getOrientation(rotationMatrix, orientationAngles)
|
|
56
|
+
|
|
57
|
+
if (lastComputedOrientationAngles.contentEquals(orientationAngles)) {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onOrientationAnglesChangedCallback?.invoke(orientationAngles)
|
|
62
|
+
lastComputedOrientationAngles = orientationAngles
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
|
|
66
|
+
|
|
67
|
+
fun enable() {
|
|
68
|
+
if (!hasRequiredSensors) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
mSensorManager.registerListener(this, mAccelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL)
|
|
73
|
+
mSensorManager.registerListener(this, mMagneticFieldSensor, SensorManager.SENSOR_DELAY_NORMAL)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fun disable() {
|
|
77
|
+
mSensorManager.unregisterListener(this)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -19,19 +19,32 @@ class Utils(private val context: ReactContext) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
fun convertToDeviceOrientationFrom(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
fun convertToDeviceOrientationFrom(orientationAngles: FloatArray): Orientation {
|
|
23
|
+
val (_, pitchRadians, rollRadians) = orientationAngles;
|
|
24
|
+
|
|
25
|
+
val pitchDegrees = Math.toDegrees(pitchRadians.toDouble()).toFloat()
|
|
26
|
+
val rollDegrees = Math.toDegrees(rollRadians.toDouble()).toFloat()
|
|
27
|
+
|
|
28
|
+
// This is needed to account for inaccuracy due to subtle movements such as tilting
|
|
29
|
+
val tolerance = 20f
|
|
30
|
+
|
|
31
|
+
//////////////////////////////////////
|
|
32
|
+
// These limits are set based on SensorManager.getOrientation reference
|
|
33
|
+
// https://developer.android.com/develop/sensors-and-location/sensors/sensors_position#sensors-pos-orient
|
|
34
|
+
//
|
|
35
|
+
val portraitLimit = -90f
|
|
36
|
+
val landscapeRightLimit = 180f
|
|
37
|
+
val landscapeLeftLimit = -180f
|
|
38
|
+
//
|
|
39
|
+
//////////////////////////////////////
|
|
40
|
+
|
|
41
|
+
return when {
|
|
42
|
+
rollDegrees.equals(-0f) && (pitchDegrees.equals(0f) || pitchDegrees.equals(-0f)) -> Orientation.FACE_UP
|
|
43
|
+
rollDegrees.equals(-180f) && (pitchDegrees.equals(0f) || pitchDegrees.equals(-0f)) -> Orientation.FACE_DOWN
|
|
44
|
+
rollDegrees in tolerance..landscapeRightLimit - tolerance -> Orientation.LANDSCAPE_RIGHT
|
|
45
|
+
rollDegrees in landscapeLeftLimit + tolerance..-tolerance -> Orientation.LANDSCAPE_LEFT
|
|
46
|
+
pitchDegrees in portraitLimit..-0f -> Orientation.PORTRAIT
|
|
47
|
+
else -> Orientation.PORTRAIT_UPSIDE_DOWN
|
|
35
48
|
}
|
|
36
49
|
}
|
|
37
50
|
|
|
@@ -54,7 +67,7 @@ class Utils(private val context: ReactContext) {
|
|
|
54
67
|
}
|
|
55
68
|
|
|
56
69
|
fun convertToOrientationFromScreenRotation(screenRotation: Int): Orientation {
|
|
57
|
-
return when(screenRotation) {
|
|
70
|
+
return when (screenRotation) {
|
|
58
71
|
Surface.ROTATION_270 -> Orientation.LANDSCAPE_RIGHT
|
|
59
72
|
Surface.ROTATION_90 -> Orientation.LANDSCAPE_LEFT
|
|
60
73
|
Surface.ROTATION_180 -> Orientation.PORTRAIT_UPSIDE_DOWN
|
|
@@ -63,7 +76,7 @@ class Utils(private val context: ReactContext) {
|
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
fun convertToInterfaceOrientationFrom(deviceOrientation: Orientation): Orientation {
|
|
66
|
-
return when(deviceOrientation) {
|
|
79
|
+
return when (deviceOrientation) {
|
|
67
80
|
Orientation.PORTRAIT -> Orientation.PORTRAIT
|
|
68
81
|
Orientation.LANDSCAPE_RIGHT -> Orientation.LANDSCAPE_LEFT
|
|
69
82
|
Orientation.PORTRAIT_UPSIDE_DOWN -> Orientation.PORTRAIT_UPSIDE_DOWN
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
package com.orientationdirector
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Promise
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.orientationdirector.implementation.OrientationDirectorModuleImpl
|
|
6
|
+
|
|
7
|
+
class OrientationDirectorModule internal constructor(context: ReactApplicationContext) :
|
|
8
|
+
NativeOrientationDirectorSpec(context) {
|
|
9
|
+
|
|
10
|
+
private var implementation = OrientationDirectorModuleImpl(context)
|
|
11
|
+
|
|
12
|
+
override fun getName() = OrientationDirectorModuleImpl.NAME
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
override fun getInterfaceOrientation(promise: Promise) {
|
|
16
|
+
promise.resolve(implementation.getInterfaceOrientation().ordinal)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
override fun getDeviceOrientation(promise: Promise) {
|
|
21
|
+
promise.resolve(implementation.getDeviceOrientation().ordinal)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
override fun lockTo(orientation: Double) {
|
|
26
|
+
implementation.lockTo(orientation.toInt())
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
override fun unlock() {
|
|
31
|
+
implementation.unlock()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
override fun resetSupportedInterfaceOrientations() {
|
|
36
|
+
implementation.resetSupportedInterfaceOrientations()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override fun isLocked(): Boolean {
|
|
40
|
+
return implementation.getIsLocked()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override fun isAutoRotationEnabled(): Boolean {
|
|
44
|
+
return implementation.getIsAutoRotationEnabled()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override fun enableOrientationSensors() {
|
|
48
|
+
return implementation.enableOrientationSensors()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override fun disableOrientationSensors() {
|
|
52
|
+
return implementation.disableOrientationSensors()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
override fun addListener(eventName: String) {}
|
|
56
|
+
|
|
57
|
+
override fun removeListeners(count: Double) {}
|
|
58
|
+
|
|
59
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
package com.orientationdirector
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
4
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
5
|
+
import com.facebook.react.bridge.Promise
|
|
6
|
+
import com.facebook.react.bridge.ReactMethod
|
|
7
|
+
import com.orientationdirector.implementation.OrientationDirectorModuleImpl
|
|
8
|
+
|
|
9
|
+
class OrientationDirectorModule internal constructor(context: ReactApplicationContext) :
|
|
10
|
+
ReactContextBaseJavaModule(context) {
|
|
11
|
+
|
|
12
|
+
private var implementation = OrientationDirectorModuleImpl(context)
|
|
13
|
+
|
|
14
|
+
override fun getName() = OrientationDirectorModuleImpl.NAME
|
|
15
|
+
|
|
16
|
+
@ReactMethod()
|
|
17
|
+
fun getInterfaceOrientation(promise: Promise) {
|
|
18
|
+
promise.resolve(implementation.getInterfaceOrientation().ordinal)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@ReactMethod()
|
|
22
|
+
fun getDeviceOrientation(promise: Promise) {
|
|
23
|
+
promise.resolve(implementation.getDeviceOrientation().ordinal)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@ReactMethod()
|
|
27
|
+
fun lockTo(orientation: Double) {
|
|
28
|
+
implementation.lockTo(orientation.toInt())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@ReactMethod()
|
|
32
|
+
fun unlock() {
|
|
33
|
+
implementation.unlock()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@ReactMethod()
|
|
37
|
+
fun resetSupportedInterfaceOrientations() {
|
|
38
|
+
implementation.resetSupportedInterfaceOrientations()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
42
|
+
fun isLocked(): Boolean {
|
|
43
|
+
return implementation.getIsLocked()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
47
|
+
fun isAutoRotationEnabled(): Boolean {
|
|
48
|
+
return implementation.getIsAutoRotationEnabled()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@ReactMethod()
|
|
52
|
+
fun enableOrientationSensors() {
|
|
53
|
+
return implementation.enableOrientationSensors()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@ReactMethod()
|
|
57
|
+
fun disableOrientationSensors() {
|
|
58
|
+
return implementation.disableOrientationSensors()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@ReactMethod()
|
|
62
|
+
fun addListener(eventName: String) {}
|
|
63
|
+
|
|
64
|
+
@ReactMethod()
|
|
65
|
+
fun removeListeners(count: Double) {}
|
|
66
|
+
}
|