1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "sensor_connector.h"
17 
18 #include <chrono>
19 #include <securec.h>
20 
21 #include "display_manager_service_inner.h"
22 
23 namespace OHOS {
24 namespace Rosen {
25 namespace {
26 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "SensorConnector"};
27 
28 #ifdef SENSOR_ENABLE
29     constexpr int64_t ORIENTATION_SENSOR_SAMPLING_RATE = 200000000; // 200ms
30     constexpr int64_t ORIENTATION_SENSOR_REPORTING_RATE = 0;
31     constexpr long ORIENTATION_SENSOR_CALLBACK_TIME_INTERVAL = 200; // 200ms
32     constexpr int VALID_INCLINATION_ANGLE_THRESHOLD_COEFFICIENT = 3;
33 #endif
34 
35 #ifdef WM_SUBSCRIBE_MOTION_ENABLE
36     constexpr int32_t MOTION_ACTION_PORTRAIT = 0;
37     constexpr int32_t MOTION_ACTION_LEFT_LANDSCAPE = 1;
38     constexpr int32_t MOTION_ACTION_PORTRAIT_INVERTED = 2;
39     constexpr int32_t MOTION_ACTION_RIGHT_LANDSCAPE = 3;
40 #endif
41 }
42 
43 #ifdef SENSOR_ENABLE
44 bool GravitySensorSubscriber::isGravitySensorSubscribed_ = false;
45 SensorUser GravitySensorSubscriber::user_;
46 long GravitySensorSubscriber::lastCallbackTime_ = 0;
47 #endif
48 
49 #ifdef WM_SUBSCRIBE_MOTION_ENABLE
50 bool MotionSubscriber::isMotionSensorSubscribed_ = false;
51 sptr<RotationMotionEventCallback> MotionSubscriber::motionEventCallback_ = nullptr;
52 #endif
53 
SubscribeRotationSensor()54 void SensorConnector::SubscribeRotationSensor()
55 {
56     WLOGFD("dms: subscribe rotation-related sensor");
57     ScreenRotationController::Init();
58 #ifdef WM_SUBSCRIBE_MOTION_ENABLE
59     MotionSubscriber::SubscribeMotionSensor();
60     if (MotionSubscriber::isMotionSensorSubscribed_) {
61         return;
62     }
63 #endif
64 
65 #ifdef SENSOR_ENABLE
66     GravitySensorSubscriber::SubscribeGravitySensor();
67 #endif
68 }
69 
UnsubscribeRotationSensor()70 void SensorConnector::UnsubscribeRotationSensor()
71 {
72 #ifdef WM_SUBSCRIBE_MOTION_ENABLE
73     MotionSubscriber::UnsubscribeMotionSensor();
74 #endif
75 
76 #ifdef SENSOR_ENABLE
77     GravitySensorSubscriber::UnsubscribeGravitySensor();
78 #endif
79 }
80 
81 // Gravity Sensor
82 #ifdef SENSOR_ENABLE
SubscribeGravitySensor()83 void GravitySensorSubscriber::SubscribeGravitySensor()
84 {
85     WLOGFI("dms: Subscribe gravity Sensor");
86     if (isGravitySensorSubscribed_) {
87         WLOGFE("dms: gravity sensor's already subscribed");
88         return;
89     }
90     if (strcpy_s(user_.name, sizeof(user_.name), "ScreenRotationController") != EOK) {
91         WLOGFE("dms strcpy_s error");
92         return;
93     }
94     user_.userData = nullptr;
95     user_.callback = &HandleGravitySensorEventCallback;
96     if (SubscribeSensor(SENSOR_TYPE_ID_GRAVITY, &user_) != 0) {
97         WLOGFE("dms: Subscribe gravity sensor failed");
98         return;
99     }
100     SetBatch(SENSOR_TYPE_ID_GRAVITY, &user_, ORIENTATION_SENSOR_SAMPLING_RATE, ORIENTATION_SENSOR_REPORTING_RATE);
101     SetMode(SENSOR_TYPE_ID_GRAVITY, &user_, SENSOR_ON_CHANGE);
102     if (ActivateSensor(SENSOR_TYPE_ID_GRAVITY, &user_) != 0) {
103         WLOGFE("dms: Activate gravity sensor failed");
104         return;
105     }
106     isGravitySensorSubscribed_ = true;
107 }
108 
UnsubscribeGravitySensor()109 void GravitySensorSubscriber::UnsubscribeGravitySensor()
110 {
111     WLOGFI("dms: Unsubscribe gravity Sensor");
112     if (!isGravitySensorSubscribed_) {
113         WLOGFE("dms: Orientation Sensor is not subscribed");
114         return;
115     }
116     if (DeactivateSensor(SENSOR_TYPE_ID_GRAVITY, &user_) != 0) {
117         WLOGFE("dms: Deactivate gravity sensor failed");
118         return;
119     }
120     if (UnsubscribeSensor(SENSOR_TYPE_ID_GRAVITY, &user_) != 0) {
121         WLOGFE("dms: Unsubscribe gravity sensor failed");
122         return;
123     }
124     isGravitySensorSubscribed_ = false;
125 }
126 
HandleGravitySensorEventCallback(SensorEvent * event)127 void GravitySensorSubscriber::HandleGravitySensorEventCallback(SensorEvent *event)
128 {
129     if (!CheckCallbackTimeInterval() || event == nullptr) {
130         return;
131     }
132     if (event->sensorTypeId != SENSOR_TYPE_ID_GRAVITY) {
133         WLOGE("dms: Orientation Sensor Callback is not SENSOR_TYPE_ID_GRAVITY");
134         return;
135     }
136     GravityData* gravityData = reinterpret_cast<GravityData*>(event->data);
137     int sensorDegree = CalcRotationDegree(gravityData);
138     DeviceRotation sensorRotationConverted = ScreenRotationController::ConvertSensorToDeviceRotation(
139         CalcSensorRotation(sensorDegree));
140     ScreenRotationController::HandleSensorEventInput(sensorRotationConverted);
141 }
142 
CalcSensorRotation(int sensorDegree)143 SensorRotation GravitySensorSubscriber::CalcSensorRotation(int sensorDegree)
144 {
145     // Use ROTATION_0 when degree range is [0, 30]∪[330, 359]
146     if (sensorDegree >= 0 && (sensorDegree <= 30 || sensorDegree >= 330)) {
147         return SensorRotation::ROTATION_0;
148     } else if (sensorDegree >= 60 && sensorDegree <= 120) { // Use ROTATION_90 when degree range is [60, 120]
149         return SensorRotation::ROTATION_90;
150     } else if (sensorDegree >= 150 && sensorDegree <= 210) { // Use ROTATION_180 when degree range is [150, 210]
151         return SensorRotation::ROTATION_180;
152     } else if (sensorDegree >= 240 && sensorDegree <= 300) { // Use ROTATION_270 when degree range is [240, 300]
153         return SensorRotation::ROTATION_270;
154     } else {
155         return SensorRotation::INVALID;
156     }
157 }
158 
CalcRotationDegree(GravityData * gravityData)159 int GravitySensorSubscriber::CalcRotationDegree(GravityData* gravityData)
160 {
161     if (gravityData == nullptr) {
162         return -1;
163     }
164     float x = gravityData->x;
165     float y = gravityData->y;
166     float z = gravityData->z;
167     int degree = -1;
168     if ((x * x + y * y) * VALID_INCLINATION_ANGLE_THRESHOLD_COEFFICIENT < z * z) {
169         return degree;
170     }
171     // arccotx = pi / 2 - arctanx, 90 is used to calculate acot(in degree); degree = rad / pi * 180
172     degree = 90 - static_cast<int>(round(atan2(y, -x) / M_PI * 180));
173     // Normalize the degree to the range of 0~360
174     return degree >= 0 ? degree % 360 : degree % 360 + 360;
175 }
176 
CheckCallbackTimeInterval()177 bool GravitySensorSubscriber::CheckCallbackTimeInterval()
178 {
179     std::chrono::milliseconds ms = std::chrono::time_point_cast<std::chrono::milliseconds>(
180         std::chrono::steady_clock::now()).time_since_epoch();
181     long currentTimeInMillitm = ms.count();
182     if (currentTimeInMillitm - lastCallbackTime_ < ORIENTATION_SENSOR_CALLBACK_TIME_INTERVAL) {
183         return false;
184     }
185     lastCallbackTime_ = currentTimeInMillitm;
186     return true;
187 }
188 #endif
189 
190 // Motion
191 #ifdef WM_SUBSCRIBE_MOTION_ENABLE
SubscribeMotionSensor()192 void MotionSubscriber::SubscribeMotionSensor()
193 {
194     WLOGFD("dms: Subscribe motion Sensor");
195     if (isMotionSensorSubscribed_) {
196         WLOGFE("dms: motion sensor's already subscribed");
197         return;
198     }
199     sptr<RotationMotionEventCallback> callback = new (std::nothrow) RotationMotionEventCallback();
200     if (callback == nullptr) {
201         return;
202     }
203     int32_t ret = OHOS::Msdp::SubscribeCallback(OHOS::Msdp::MOTION_TYPE_ROTATION, callback);
204     if (ret != 0) {
205         return;
206     }
207     motionEventCallback_ = callback;
208     isMotionSensorSubscribed_ = true;
209 }
210 
UnsubscribeMotionSensor()211 void MotionSubscriber::UnsubscribeMotionSensor()
212 {
213     if (!isMotionSensorSubscribed_) {
214         WLOGFI("dms: Unsubscribe motion sensor");
215         return;
216     }
217     int32_t ret = OHOS::Msdp::UnsubscribeCallback(OHOS::Msdp::MOTION_TYPE_ROTATION, motionEventCallback_);
218     if (ret != 0) {
219         return;
220     }
221     isMotionSensorSubscribed_ = false;
222 }
223 
OnMotionChanged(const MotionEvent & motionData)224 void RotationMotionEventCallback::OnMotionChanged(const MotionEvent& motionData)
225 {
226     DeviceRotation motionRotation = DeviceRotation::INVALID;
227     switch (motionData.status) {
228         case MOTION_ACTION_PORTRAIT: {
229             motionRotation = DeviceRotation::ROTATION_PORTRAIT;
230             break;
231         }
232         case MOTION_ACTION_LEFT_LANDSCAPE: {
233             motionRotation = ScreenRotationController::IsDefaultDisplayRotationPortrait() ?
234                 DeviceRotation::ROTATION_LANDSCAPE_INVERTED : DeviceRotation::ROTATION_LANDSCAPE;
235             break;
236         }
237         case MOTION_ACTION_PORTRAIT_INVERTED: {
238             motionRotation = DeviceRotation::ROTATION_PORTRAIT_INVERTED;
239             break;
240         }
241         case MOTION_ACTION_RIGHT_LANDSCAPE: {
242             motionRotation = ScreenRotationController::IsDefaultDisplayRotationPortrait() ?
243                 DeviceRotation::ROTATION_LANDSCAPE : DeviceRotation::ROTATION_LANDSCAPE_INVERTED;
244             break;
245         }
246         default: {
247             break;
248         }
249     }
250     ScreenRotationController::HandleSensorEventInput(motionRotation);
251 }
252 #endif
253 } // Rosen
254 } // OHOS