하드웨어 센서 값을 가공하는 방법
Gyro Application 분석기들어가며
내년부터 새로운 프로젝트에 참가하는데 하드웨어쪽 코드를 살펴볼 필요가 있어서 예전에 잠깐 가지고 놀았던 아두이노가 생각났다. 블루투스나 여러 통신 모듈 및 센서 모듈로 IOT 환경을 만들 수 있었는데 이번엔 좀 다른게 모바일과 웹 기반으로 위와 같은 기능을 구현할 예정이다.
생각해보면 일상속에 많은 하드웨어들이 소프트웨어화가 되면서 사람들의 주머니는 가벼워진거 같다. 가장 큰 요소가 카메라와 컴퓨터이다. 예전에는 디지털 카메라를 항상 휴대하거나 컴퓨터를 통해서 검색할 수 있었는데 요즘은 너무 잘 발달된 어플리케이션 덕분에 걸어다니면서 전기 없이 간편하게 순간을 기억할 수 있도록 소장하거나 다른 사람들에게 손쉽게 공유가 가능하다.
많은 센서들 가운데 균형 센서 이용할 계획을 가지고 있었다. 손목시계와 휴대전화에 공통으로 균형센서가 있어 이를 응용해볼까 한다. 최근 여행 다녀오면서 기내에서는 느껴지지 않지만 비행기가 조금씩 기울어질때 수평이 궁금해서 level 앱을 사용한 일을 떠올렸다. 당시에 휴대전화가 비행기 머리와 같이 평행해서 놓고 확인했을때 Y 축은 부드럽게 수평 균형을 감지하는 것을 확인할 수 있었다. 약간의 기울임이 조금씩 발생했지만 그렇게 느껴지지는 않았다.
이번에는 level 앱에서 어떻게 Gyro 센서 값을 사용하고 사람이 보기 쉽게 보여주는지 확인하고자 한다. 아래는 해당 level 앱에 있는 메니페스트를 살펴보았다.
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<manifest android:compileSdkVersion="33"
android:compileSdkVersionCodename="13"
android:installLocation="auto"
android:versionCode="46"
android:versionName="1.2.11"
package="level.sample.app"
platformBuildVersionCode="33"
platformBuildVersionName="13"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33"/>
해당 부분에서 빌드 버전 네임 등 고유 속성을 확인할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
<uses-feature android:name="android.hardware.sensor.compass" android:required="false"/>
<uses-feature android:name="android.hardware.sensor.accelerometer"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<uses-feature android:name="android.hardware.screen.landscape" android:required="false"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<supports-screens android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true"
android:xlargeScreens="true"/>
해당 부분에서 하드웨어 센서에 접근하는 권한을 확인할 수 있다.
위를 참고하면 메니페스트에서 해당 앱이 사용하는 하드웨어 기능과 빌드 속성을 간략히 확인할 수 있다.
센서 값을 calibration 하는 기능
먼저 아래 사진에서 보이는 센서 값 보정하는 부분 코드를 찾아보려고 한다.
아래와 같은 함수에서 calibration 을 터치했을 때 동작을 제어한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
@Override // android.view.View$OnTouchListener
public final boolean onTouch(View view0, MotionEvent motionEvent0) {
String s1;
float f5;
float f2;
DecimalFormat decimalFormat0;
StringBuilder stringBuilder0;
Context context0;
String s;
int v = motionEvent0.getAction();
float f = motionEvent0.getX();
float f1 = motionEvent0.getY();
if((SmartLevel.z) && ((f > ((float)this.A) - this.F - ((float)this.m.getWidth()))) && (((f1 > ((float)this.B) - this.G - this.F * 1.5f - ((float)this.m.getHeight()) - this.E * 0.5f)) && ((f1 < ((float)this.B) - this.G - this.E * 0.5f)))) {
if(v == 0) {
if(SmartLevel.A) {
q q0 = this.f;
if(q0 != null) {
q0.g(0);
}
}
if(this.a) {
boolean z = SmartLevel.s;
s = " (Y=";
if((z) && !this.w) {
SmartLevel.s(-this.i + SmartLevel.E);
context0 = this.e;
stringBuilder0 = new StringBuilder();
stringBuilder0.append(this.e.getString(0x7F1100D0)); // string:roll_zero_ok "Success! set to zero"
stringBuilder0.append(s);
decimalFormat0 = v.a;
goto label_79;
}
if(!z && (this.w)) {
SmartLevel.s(this.i + SmartLevel.E);
context0 = this.e;
stringBuilder0 = new StringBuilder();
stringBuilder0.append(this.e.getString(0x7F1100D0)); // string:roll_zero_ok "Success! set to zero"
stringBuilder0.append(s);
decimalFormat0 = v.a;
goto label_79;
}
SmartLevel.r(-this.i + SmartLevel.F);
context0 = this.e;
stringBuilder0 = new StringBuilder();
goto label_38;
}
else {
s = " (X=";
if(this.b) {
boolean z1 = SmartLevel.s;
if((z1) && !this.w) {
SmartLevel.r(-this.g + SmartLevel.F);
context0 = this.e;
stringBuilder0 = new StringBuilder();
goto label_38;
}
if(!z1 && (this.w)) {
SmartLevel.r(this.g + SmartLevel.F);
context0 = this.e;
stringBuilder0 = new StringBuilder();
label_38:
stringBuilder0.append(this.e.getString(0x7F1100D0)); // string:roll_zero_ok "Success! set to zero"
stringBuilder0.append(s);
decimalFormat0 = v.a;
f2 = SmartLevel.F;
goto label_80;
}
SmartLevel.s(this.g + SmartLevel.E);
context0 = this.e;
stringBuilder0 = new StringBuilder();
stringBuilder0.append(this.e.getString(0x7F1100D0)); // string:roll_zero_ok "Success! set to zero"
stringBuilder0.append(s);
decimalFormat0 = v.a;
goto label_79;
}
float f3 = this.i;
if(((f3 < 60.0f)) && ((f3 > -60.0f))) {
float f4 = this.g;
if(!(f4 < 60.0f) || !(f4 > -60.0f)) {
context0 = this.e;
s1 = context0.getString(0x7F1100A3); // string:nolie_msg "After putting the device on a level surface, tap Zero calibration."
v.j(context0, s1, this);
return true;
}
boolean z2 = SmartLevel.s;
if((z2) && !this.w) {
SmartLevel.s(-f3 + SmartLevel.E);
f5 = -this.g;
}
else if(!z2 && (this.w)) {
SmartLevel.s(f3 + SmartLevel.E);
f5 = this.g;
}
else {
SmartLevel.s(f4 + SmartLevel.E);
f5 = -this.i;
}
SmartLevel.r(f5 + SmartLevel.F);
this.i = SmartLevel.E;
this.g = SmartLevel.F;
this.postInvalidate();
context0 = this.e;
stringBuilder0 = new StringBuilder();
stringBuilder0.append(this.e.getString(0x7F1100D0)); // string:roll_zero_ok "Success! set to zero"
stringBuilder0.append(" (X=");
decimalFormat0 = v.a;
stringBuilder0.append("0.0");
stringBuilder0.append("˚, Y=");
label_79:
f2 = SmartLevel.E;
label_80:
stringBuilder0.append(decimalFormat0.format(((double)f2)));
stringBuilder0.append("˚)");
s1 = stringBuilder0.toString();
v.j(context0, s1, this);
return true;
}
context0 = this.e;
s1 = context0.getString(0x7F1100A3); // string:nolie_msg "After putting the device on a level surface, tap Zero calibration."
}
v.j(context0, s1, this);
}
return true;
}
if(v == 0) {
this.l = true;
return true;
}
if(v != 1 && (!this.l || v != 3)) {
return true;
}
this.l = false;
return true;
}
위에서 v.j()
함수로 리셋 결과가 넘어간다.
아래는 전달한 매개변수가 진입하는 함수다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public static void j(Context context0, String s, View view0) {
try {
if(NotificationManagerCompat.from(context0).areNotificationsEnabled()) {
Toast.makeText(context0, s, 0).show();
}
else {
Snackbar.make(view0, s.replace("\n", " "), -1).show();
}
}
catch(RuntimeException runtimeException0) {
goto label_13;
}
if(Build.VERSION.SDK_INT < 26) {
goto label_7;
}
try {
((Vibrator)context0.getSystemService("vibrator")).vibrate(b.i(16L));
return;
label_7:
((Vibrator)context0.getSystemService("vibrator")).vibrate(16L);
return;
}
catch(RuntimeException runtimeException1) {
}
try {
runtimeException1.printStackTrace();
return;
}
catch(RuntimeException runtimeException0) {
}
label_13:
runtimeException0.printStackTrace();
}
아래에서 실제로 해당 코드에서 초기화가 일어나는지 결과를 확인해본다.
1
2
3
4
5
6
7
8
9
10
[+] Logger level.sample.app.v.j(context0, s, view0) param=Reset calibration (X=0.0˚, Y=0.0˚)
[+] Logger level.sample.app.v.j(context0, s, view0) result=undefined
[+] Logger level.sample.app.v.j(context0, s, view0) param=Reset calibration (X=0.0˚, Y=0.0˚)
[+] Logger level.sample.app.v.j(context0, s, view0) result=undefined
[+] Logger level.sample.app.v.j(context0, s, view0) param=Reset calibration (X=0.0˚, Y=0.0˚)
[+] Logger level.sample.app.v.j(context0, s, view0) result=undefined
[+] Logger level.sample.app.v.j(context0, s, view0) param=Reset calibration (X=0.0˚, Y=0.0˚)
[+] Logger level.sample.app.v.j(context0, s, view0) result=undefined
[+] Logger level.sample.app.v.j(context0, s, view0) param=Reset calibration (X=0.0˚, Y=0.0˚)
[+] Logger level.sample.app.v.j(context0, s, view0) result=undefined
위와 같이 해당 부분을 통해 따라가면 센서 값을 초기화하는 것을 볼 수 있다.
X, Y 를 구해서 화면에 출력하기
다음은 센서 값을 화면에 출력하는 부분을 찾아볼 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
final class i implements SensorEventListener {
float[] a;
float b;
float c;
a[] d;
final j e;
i(j j0) {
this.e = j0;
super();
this.a = new float[3];
this.b = 0.0f;
this.c = 0.0f;
this.d = new a[]{new a(), new a()};
}
@Override // android.hardware.SensorEventListener
public final void onAccuracyChanged(Sensor sensor0, int v) {
}
@Override // android.hardware.SensorEventListener
public final void onSensorChanged(SensorEvent sensorEvent0) {
float f;
j j0 = this.e;
j0.getClass();
this.a = (float[])sensorEvent0.values.clone();
if(j0.f) {
this.c = this.a[1] - j0.g;
f = this.a[2] - j0.h;
}
else {
float[] arr_f = this.a;
float f1 = arr_f[0];
if((f1 <= -9.80665f)) {
arr_f[0] = -9.806641f;
}
else if((f1 >= 9.80665f)) {
arr_f[0] = 9.806641f;
}
float f2 = arr_f[1];
if((f2 <= -9.80665f)) {
arr_f[1] = -9.806641f;
}
else if((f2 >= 9.80665f)) {
arr_f[1] = 9.806641f;
}
this.c = 90.0f - ((float)(Math.acos(-arr_f[1] / 9.80665f) / 3.141593 * 180.0)) - j0.g;
this.b = 90.0f - ((float)(Math.acos(this.a[0] / 9.80665f) / 3.141593 * 180.0)) - j0.h;
this.c = this.d[0].a(this.c);
f = this.d[1].a(this.b);
}
this.b = f;
if(((this.c > -0.08f)) && ((this.c < 0.08f))) {
this.c = 0.0f;
}
if(((this.b > -0.08f)) && ((this.b < 0.08f))) {
this.b = 0.0f;
}
j0.e.f(this.c, this.b);
j0.e.postInvalidate();
}
}
센서 값에 대하여 위 코드를 통해 j0.e.f()
로 진입한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
protected final void f(float f, float f1) {
float f2;
if(this.l) {
return;
}
if(SmartLevel.s) {
if(this.w) {
goto label_11;
}
this.g = -f;
f2 = -f1;
}
else {
if(this.w) {
this.g = f;
this.h = f1;
return;
}
label_11:
this.g = f1;
f2 = -f;
}
this.h = f2;
}
위에 코드를 보면 this.g
에 특정 값이 대입된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
@Override // android.view.View
public final void onDraw(Canvas canvas0) {
float f59;
float f58;
float f49;
float f20;
float f19;
float f18;
float f17;
float f = 0.0f;
if(this.D) {
this.A = this.getWidth();
int v = this.getHeight();
this.B = v;
this.w = this.A > v;
this.C = Math.max(1.0f, this.e.getResources().getDisplayMetrics().density - 0.5f);
int v1 = v.c(this.e, this.w);
if((SmartLevel.r > 1.0f)) {
int v2 = Math.max(this.A, this.B);
if(this.w) {
v1 = 0;
}
this.E = ((float)(v2 + v1)) / SmartLevel.r;
}
if(this.z == 0) {
this.z = v.e(this.e, SmartLevel.H, this.w);
}
float f1 = SmartLevel.r;
if(((f1 > 150.0f)) && ((f1 <= 170.0f))) {
this.c = 1.35f;
}
else if(((f1 > 170.0f)) || (SmartLevel.s) && (((SmartLevel.r > 150.0f)) || ((SmartLevel.r < 0.0f)))) {
this.c = 1.7f;
}
float f2 = this.E * 3.0f * this.c;
this.F = f2;
float f3 = (float)this.z;
this.G = f3;
int v3 = SmartLevel.v;
if(v3 == 0xFF000000) {
this.u = -1;
this.v = -12303292;
}
else if(v3 == 0xFF6B6B6B) {
this.v = 0xFF9E9E9E;
}
if(this.w) {
float f4 = (((float)this.B) - f3 - ((float)this.t) - f2 * 3.0f) / 2.0f;
this.p = f4;
this.j = ((float)this.A) / 2.0f;
this.k = f2 * 2.0f + ((float)this.t) + f4;
}
else {
float f5 = (((float)(this.A - this.t)) - f2 * 3.0f) / 2.0f;
this.p = f5;
this.j = f2 * 2.0f + ((float)this.t) + f5;
this.k = (((float)this.B) - f3) / 2.0f + f2 * 1.7f;
float f6 = ((float)this.t) * 3.7f;
if((f5 > f6)) {
this.p = f6;
}
}
this.r.reset();
int v4 = this.w ? 1 : 2;
float f7 = this.j - this.p;
float f8 = this.F * ((float)v4);
this.s.set(f7 - 1.0f, f8, f7 + ((float)this.t) - 1.0f, ((float)this.t) + f8);
this.r.addArc(this.s, 90.0f, 180.0f);
this.r.lineTo(this.j + this.p - ((float)(this.t / 2)) + 1.0f, this.F * ((float)v4));
float f9 = this.j + this.p;
float f10 = this.F * ((float)v4);
this.s.set(f9 - ((float)this.t) + 1.0f, f10, f9 + 1.0f, ((float)this.t) + f10);
this.r.addArc(this.s, 270.0f, 180.0f);
this.r.lineTo(this.j - this.p + ((float)(this.t / 2)) - 1.0f, this.F * ((float)v4) + ((float)this.t));
this.q.reset();
int v5 = this.w ? 2 : 1;
float f11 = this.F * ((float)v5);
float f12 = this.k - this.p;
this.s.set(f11 - 1.0f, f12, f11 + ((float)this.t) + 1.0f, ((float)this.t) + f12);
this.q.addArc(this.s, 180.0f, 180.0f);
this.q.lineTo(this.F * ((float)v5) + ((float)this.t) + 1.0f, this.k + this.p - ((float)(this.t / 2)));
float f13 = this.F * ((float)v5);
float f14 = this.k + this.p;
this.s.set(f13 - 1.0f, f14 - ((float)this.t), f13 + ((float)this.t) + 1.0f, f14);
this.q.addArc(this.s, 0.0f, 180.0f);
this.q.lineTo(this.F * ((float)v5) - 1.0f, this.k - this.p + ((float)(this.t / 2)));
this.d.setStyle(Paint.Style.FILL);
this.D = false;
}
if(Math.abs(-this.g - 90.0f) < 17.0f || Math.abs(-this.g - 90.0f) > 50.0f) {
this.a = Math.abs(-this.g - 90.0f) < 17.0f;
}
float f15 = this.h;
if((f15 < 40.0f || f15 > 73.0f) && (f15 < 107.0f || f15 > 140.0f)) {
this.b = ((f15 > 73.0f)) && ((f15 < 107.0f));
}
canvas0.drawColor(SmartLevel.v);
this.d.setColor(SmartLevel.u);
this.d.setColor(this.v);
canvas0.drawPath(this.q, this.d);
canvas0.drawPath(this.r, this.d);
canvas0.drawCircle(this.j, this.k, this.p, this.d);
this.d.setColor(this.u);
this.d.setStyle(Paint.Style.STROKE);
this.d.setStrokeWidth(this.C);
canvas0.drawPath(this.q, this.d);
canvas0.drawPath(this.r, this.d);
canvas0.drawCircle(this.j, this.k, this.p, this.d);
this.d.setStrokeWidth(Math.max(1.0f, this.C - 0.5f));
float f16 = this.p;
int v6 = this.t;
if((f16 > ((float)v6) * 2.5f)) {
canvas0.drawCircle(this.j, this.k, f16 * 2.0f / 3.0f + ((float)(v6 / 6)), this.d);
canvas0.drawCircle(this.j, this.k, this.p / 3.0f + ((float)(this.t / 3)), this.d);
f17 = this.j;
f18 = this.k;
f19 = (float)this.t;
f20 = 1.9f;
}
else {
canvas0.drawCircle(this.j, this.k, f16 / 2.0f + ((float)(v6 / 4)), this.d);
f17 = this.j;
f18 = this.k;
f19 = (float)this.t;
f20 = 1.95f;
}
canvas0.drawCircle(f17, f18, f19 / f20, this.d);
this.d.setStyle(Paint.Style.FILL);
this.d.setStrokeWidth(Math.max(1.0f, this.C - 1.0f));
canvas0.drawLine(this.j, this.F * ((float)(this.w ? 1 : 2)) + ((float)this.t), this.j, this.k + this.p, this.d);
canvas0.drawLine(((float)this.t) + this.F * ((float)(this.w ? 2 : 1)), this.k, this.j + this.p, this.k, this.d);
this.d.setStrokeWidth(0.0f);
int v7 = this.w ? 1 : 2;
float f21 = this.j - ((float)(this.t / 2)) - this.C * 2.0f;
float f22 = this.F * ((float)v7);
canvas0.drawLine(f21, f22, f21, f22 + ((float)this.t), this.d);
float f23 = this.j - ((float)(this.t / 2)) - this.C * 5.0f;
float f24 = this.F * ((float)v7);
canvas0.drawLine(f23, f24, f23, f24 + ((float)this.t), this.d);
float f25 = this.C * 2.0f + (((float)(this.t / 2)) + this.j);
float f26 = this.F * ((float)v7);
canvas0.drawLine(f25, f26, f25, f26 + ((float)this.t), this.d);
float f27 = this.C * 5.0f + (((float)(this.t / 2)) + this.j);
float f28 = this.F * ((float)v7);
canvas0.drawLine(f27, f28, f27, f28 + ((float)this.t), this.d);
int v8 = this.w ? 2 : 1;
float f29 = this.F * ((float)v8);
float f30 = this.k - ((float)(this.t / 2)) - this.C * 2.0f;
canvas0.drawLine(f29, f30, ((float)this.t) + f29, f30, this.d);
float f31 = this.F * ((float)v8);
float f32 = this.k - ((float)(this.t / 2)) - this.C * 5.0f;
canvas0.drawLine(f31, f32, ((float)this.t) + f31, f32, this.d);
float f33 = this.F * ((float)v8);
float f34 = this.C * 2.0f + (((float)(this.t / 2)) + this.k);
canvas0.drawLine(f33, f34, ((float)this.t) + f33, f34, this.d);
float f35 = this.F * ((float)v8);
float f36 = this.C * 5.0f + (((float)(this.t / 2)) + this.k);
canvas0.drawLine(f35, f36, ((float)this.t) + f35, f36, this.d);
this.d.setColor(SmartLevel.u);
this.d.setTextSize(this.E * 4.0f * this.c);
if(this.w) {
float f37 = this.k;
canvas0.drawText("X", this.E * this.c + (this.j + this.p), this.d.measureText("X") / 2.0f + f37, this.d);
canvas0.drawText("Y", this.j - this.d.measureText("Y") / 2.0f, this.F * 2.0f / 3.0f + (this.k + this.p), this.d);
}
else {
float f38 = this.k;
canvas0.drawText("X", this.E * this.c * (this.p == ((float)this.t) * 3.8f ? 1.0f : -1.5f) + (this.j + this.p), this.d.measureText("X") / 2.0f + f38, this.d);
float f39 = this.j - this.d.measureText("Y") / 2.0f;
float f40 = this.k + this.p;
float f41 = this.d.measureText("M") + f40;
canvas0.drawText("Y", f39, this.E * this.c + f41, this.d);
}
float f42 = this.g;
if((f42 < -90.0f)) {
this.g = -180.0f - f42;
}
else if((f42 > 90.0f)) {
this.g = 180.0f - f42;
}
this.d.setTextSize(((float)SmartLevel.t) * this.E * 3.0f / 5.0f * this.c);
float f43 = this.d.measureText("M");
float f44 = this.h;
this.i = f44;
if(SmartLevel.C) {
if(((f44 >= -270.0f)) && ((f44 <= -90.0f))) {
this.i = SmartLevel.F * 2.0f + -(f44 + 180.0f);
}
if(((f44 <= 270.0f)) && ((f44 >= 90.0f))) {
this.i = SmartLevel.F * 2.0f + (180.0f - f44);
}
}
if(this.a) {
canvas0.save();
canvas0.rotate(-90.0f, this.F + ((float)this.t) + f43 / 2.0f, this.k - f43 / 2.0f);
String s = "Y = " + LevelView.a(this.i);
float f45 = this.E;
float f46 = this.c;
float f47 = 1.5f * f45 * f46 + (this.F + ((float)this.t));
float f48 = this.k;
if(!this.w) {
f43 = f45 * f46;
}
canvas0.drawText(s, f47, f48 + f43, this.d);
canvas0.restore();
f49 = this.F;
f = (float)(((double)(this.k - ((float)(this.t / 2)))) - Math.sin(Math.toRadians(this.i)) * ((double)this.p));
}
else if(this.b) {
canvas0.drawText("X = " + LevelView.a(this.g), 1.5f * this.E * this.c + this.j, this.E * 0.5f * this.c + (this.F * ((float)(this.w ? 1 : 2)) + ((float)this.t) + f43), this.d);
f49 = (float)(Math.sin(Math.toRadians(this.g)) * ((double)this.p) + ((double)(this.j - ((float)(this.t / 2)))));
}
else {
if(this.w) {
canvas0.drawText("X = " + LevelView.a(this.g), this.E * 3.5f * this.c + (this.j + this.p), this.k - this.p + f43, this.d);
canvas0.drawText("Y = " + LevelView.a(this.i), 3.5f * this.E * this.c + (this.j + this.p), f43 * 2.0f + (this.k - this.p) + this.E, this.d);
}
else {
canvas0.drawText("X = " + LevelView.a(this.g), this.j - this.p, (this.F * 2.0f + ((float)this.t) + this.k - this.p) / 2.0f - this.E * 0.5f + 5.0f, this.d);
canvas0.drawText("Y = " + LevelView.a(this.i), this.j - this.p, this.E * 0.5f + (this.F * 2.0f + ((float)this.t) + this.k - this.p) / 2.0f + f43 + 5.0f, this.d);
}
f49 = (float)(Math.sin(Math.toRadians(this.g)) * ((double)this.p) + ((double)(this.j - ((float)(this.t / 2)))));
float f50 = (float)(((double)(this.k - ((float)(this.t / 2)))) - Math.sin(Math.toRadians(this.i)) * ((double)this.p));
switch(SmartLevel.w) {
case 1:
case 3: {
float f51 = this.i;
if(f51 >= 1.0f || f51 <= -1.0f || (this.g >= 1.0f || this.g <= -1.0f)) {
String s1 = LevelView.b(((float)Math.sqrt(f51 * f51 + this.g * this.g)), false);
int v9 = (int)Math.toDegrees(Math.atan(this.i / this.g));
int v10 = this.g >= 0.0f ? 90 - v9 : 270 - v9;
float f52 = (float)(Math.sin(Math.toRadians(this.g)) * ((double)this.p));
float f53 = (float)(Math.sin(Math.toRadians(this.i)) * ((double)this.p));
float f54 = ((float)this.t) / 2.0f + ((float)Math.sqrt(f53 * f53 + f52 * f52));
this.d.setTextSize(((float)SmartLevel.t) * this.E * 3.0f / 6.5f * this.c);
canvas0.save();
canvas0.rotate(((float)v10), this.j, this.k);
canvas0.drawBitmap(this.o, this.j - ((float)(this.o.getWidth() / 3)), this.k - f54 - ((float)this.o.getHeight()), this.d);
canvas0.drawText(s1 + "", this.j - this.d.measureText(s1) / 2.0f, this.k - f54 - ((float)this.o.getHeight()) / 0.9f, this.d);
canvas0.restore();
}
}
}
f = f50;
}
if(!this.a && !this.b) {
canvas0.drawBitmap(this.h(0), f49, f, this.d);
}
if(!this.a) {
canvas0.drawBitmap(this.h(2), f49, this.F * ((float)(this.w ? 1 : 2)), this.d);
}
if(!this.b) {
canvas0.drawBitmap(this.h(1), this.F * ((float)(this.w ? 2 : 1)), f, this.d);
}
if(SmartLevel.z) {
this.d.setTextSize(this.E * 1.6f * this.c);
this.d.setColor(0xFF888888);
canvas0.drawBitmap(this.m, ((float)this.A) - this.F / 2.0f - ((float)this.m.getWidth()), ((float)this.B) - this.G - this.F - ((float)this.m.getHeight()) - this.E * 0.5f, this.d);
String s2 = this.e.getString(0x7F1100CF); // string:roll_zero "Zero calibration"
float f55 = this.d.measureText(this.e.getString(0x7F1100CF)); // string:roll_zero "Zero calibration"
float f56 = (float)this.m.getWidth();
float f57 = this.F / 2.0f;
if((f55 > f56 + f57)) {
f58 = (float)this.A;
f59 = this.d.measureText(this.e.getString(0x7F1100CF)); // string:roll_zero "Zero calibration"
}
else {
f58 = ((float)this.A) - f57;
float f60 = (float)this.m.getWidth();
f59 = (this.d.measureText(this.e.getString(0x7F1100CF)) + f60) / 2.0f; // string:roll_zero "Zero calibration"
}
canvas0.drawText(s2, f58 - f59, this.E * 1.0f + (((float)this.B) - this.G - this.F), this.d);
}
if((this.l) && System.currentTimeMillis() / 500L % 2L == 0L) {
this.d.setTextSize(this.E * 5.0f * this.c);
this.d.setColor(0xFFFF0000);
canvas0.drawText(this.e.getString(0x7F110063), (((float)this.A) - this.d.measureText(this.e.getString(0x7F110063))) / 2.0f, ((float)this.B) / 2.1f, this.d); // string:holding "Holding …"
}
}
위에서 보면 canvas0.drawText("X = " + LevelView.a(this.g),...)
매개변수에 센서 값을 출력하기 위해 this.g
를 전달하는 것을 볼 수 있다.
1
2
3
private static String a(float f) {
return SmartLevel.w == 3 ? LevelView.b(f, false) : LevelView.b(f, true);
}
위 함수로 들어간다.
아래 함수를 통해서 문자열을 정리 후 필터링한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
private static String b(float f, boolean z) {
String s2;
StringBuilder stringBuilder2;
int v = SmartLevel.w;
String s = "";
if(v == 0) {
StringBuilder stringBuilder0 = new StringBuilder();
stringBuilder0.append(v.a.format(((double)f)));
if(z) {
s = "˚";
}
stringBuilder0.append(s);
return stringBuilder0.toString();
}
switch(v) {
case 1: {
double f4 = Math.tan(Math.toRadians(f)) * 100.0;
if(f4 >= -1000.0 && f4 <= 1000.0) {
if(f4 > -10.0 && f4 < 10.0) {
if(((f4 > -0.4)) && ((f4 < 0.4))) {
f4 = 0.0;
}
StringBuilder stringBuilder3 = new StringBuilder();
stringBuilder3.append(v.a.format(f4));
if(z) {
s = " %";
}
stringBuilder3.append(s);
return stringBuilder3.toString();
}
StringBuilder stringBuilder4 = new StringBuilder();
stringBuilder4.append(((int)f4));
if(z) {
s = " %";
}
stringBuilder4.append(s);
return stringBuilder4.toString();
}
return "∞";
}
case 2: {
break;
}
default: {
float f1 = (float)(Math.tan(Math.toRadians(f)) * 12.0);
if(((f < -89.0f && f < -91.0f)) || ((f > 89.0f)) && ((f < 91.0f))) {
return "∞";
}
StringBuilder stringBuilder1 = new StringBuilder();
float f2 = Math.abs(f1);
String s1 = ((int)f2) <= 0 ? "0" : Integer.toString(((int)f2));
float f3 = f2 - ((float)(((int)f2)));
if(((f3 > 0.0625f)) && ((f3 <= 0.1875f))) {
stringBuilder2 = a.k(s1);
s2 = "⅛";
stringBuilder2.append(s2);
s1 = stringBuilder2.toString();
}
else {
if(((f3 > 0.1875f)) && ((f3 <= 0.3125f))) {
stringBuilder2 = a.k(s1);
s2 = "¼";
stringBuilder2.append(s2);
s1 = stringBuilder2.toString();
goto label_50;
}
if(((f3 > 0.3125f)) && ((f3 <= 0.4375f))) {
stringBuilder2 = a.k(s1);
s2 = "⅜";
stringBuilder2.append(s2);
s1 = stringBuilder2.toString();
goto label_50;
}
if(((f3 > 0.4375f)) && ((f3 <= 0.5625f))) {
stringBuilder2 = a.k(s1);
s2 = "½";
stringBuilder2.append(s2);
s1 = stringBuilder2.toString();
goto label_50;
}
if(((f3 > 0.5625f)) && ((f3 <= 0.6875f))) {
stringBuilder2 = a.k(s1);
s2 = "⅝";
stringBuilder2.append(s2);
s1 = stringBuilder2.toString();
goto label_50;
}
if(((f3 > 0.6875f)) && ((f3 <= 0.8125f))) {
stringBuilder2 = a.k(s1);
s2 = "¾";
stringBuilder2.append(s2);
s1 = stringBuilder2.toString();
goto label_50;
}
if(((f3 > 0.8125f)) && ((f3 <= 0.9375f))) {
stringBuilder2 = a.k(s1);
s2 = "⅞";
stringBuilder2.append(s2);
s1 = stringBuilder2.toString();
goto label_50;
}
if((f3 >= 0.9375f)) {
s1 = Integer.toString(((int)f2) + 1);
}
}
label_50:
stringBuilder1.append(s1);
if(z) {
s = "/12\"";
}
stringBuilder1.append(s);
return stringBuilder1.toString();
}
}
StringBuilder stringBuilder5 = new StringBuilder();
stringBuilder5.append(v.b.format(Math.toRadians(f)));
if(z) {
s = " rad";
}
stringBuilder5.append(s);
return stringBuilder5.toString();
}
실제로 값이 그렇게 나오는지 확인해본다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[+] Logger for level.sample.app.LevelView.a(f) param=-38.5569953918457
[+] Logger for level.sample.app.LevelView.a(f) result=-38.6˚
[+] Logger for level.sample.app.LevelView.a(f) param=16.77606773376465
[+] Logger for level.sample.app.LevelView.a(f) result=16.8˚
[+] Logger for level.sample.app.LevelView.a(f) param=-38.5569953918457
[+] Logger for level.sample.app.LevelView.a(f) result=-38.6˚
[+] Logger for level.sample.app.LevelView.a(f) param=16.77606773376465
[+] Logger for level.sample.app.LevelView.a(f) result=16.8˚
[+] Logger for level.sample.app.LevelView.a(f) param=-38.5569953918457
[+] Logger for level.sample.app.LevelView.a(f) result=-38.6˚
[+] Logger for level.sample.app.LevelView.a(f) param=16.77606773376465
[+] Logger for level.sample.app.LevelView.a(f) result=16.8˚
[+] Logger for level.sample.app.LevelView.a(f) param=-38.5569953918457
[+] Logger for level.sample.app.LevelView.a(f) result=-38.6˚
[+] Logger for level.sample.app.LevelView.a(f) param=16.77606773376465
[+] Logger for level.sample.app.LevelView.a(f) result=16.8˚
위와 같이 현재 AVD Gyro 센서 값을 출력하는 것을 볼 수 있다
아래와 같이 Virtual 환경에서 Gyro 센서 값을 조절하면 해당 함수를 통해 값을 출력하는 것을 확인할 수 있다.
정리하며
해당 앱은 하드웨어를 통해 얻은 라이브한 센서 값을 얻는다. 그 후 보정하는 단계를 거치게 되는데 이때 인간이 이해하기 쉽게 시각화하느라 코드 전반에 계산식이 내포된다. 이로 인한 과정이 있어서 분석이 조금 어려웠다.
If you find any errors, please let me know by comment or email. Thank you.