ちょっとイケてない。
kivy がなんなのかとか plyer がなんなのかについては、おいおいでまとめたりするかもしんない。今回は唐突に plyer は「あなたは知ってる」ていで書いとく。
タイトルの通りで、plyer.compass がちょっとマズい。
「コンパス」という機能名で欲しいのは文字通りコンパスであろう。つまり東西南北を知りたいわけだ。けど plyer.compass 単体では「何も出来ない」。
要は azimuth, roll, pitch を得たいわけなんだけれども、android API を使ってこれを得る方法は例えばこことかこことかこことか、まぁ色々みつかる。一応公式の説明はこれ。(stackexchange でのやりとりも参考になりそう。ちゃんと読めてないけど。)
これらサイトをみるに、方法は2つ:
- (非推奨)Sensor.TYPE_ORIENTATION を使う
- Sensor.TYPE_MAGNETIC_FIELD と Sensor.TYPE_ACCELEROMETER を組み合わせて計算する
そうなんだけれども、plyer.compass の実装はこのどちらでもない:
1 '''
2 Android Compass
3 ---------------------
4 '''
5
6 from plyer.facades import Compass
7 from jnius import PythonJavaClass, java_method, autoclass, cast
8 from plyer.platforms.android import activity
9
10 Context = autoclass('android.content.Context')
11 Sensor = autoclass('android.hardware.Sensor')
12 SensorManager = autoclass('android.hardware.SensorManager')
13
14
15 class MagneticFieldSensorListener(PythonJavaClass):
16 __javainterfaces__ = ['android/hardware/SensorEventListener']
17
18 def __init__(self):
19 super(MagneticFieldSensorListener, self).__init__()
20 self.SensorManager = cast('android.hardware.SensorManager',
21 activity.getSystemService(Context.SENSOR_SERVICE))
22 self.sensor = self.SensorManager.getDefaultSensor(
23 Sensor.TYPE_MAGNETIC_FIELD)
24
25 self.values = [None, None, None]
26
27 def enable(self):
28 self.SensorManager.registerListener(self, self.sensor,
29 SensorManager.SENSOR_DELAY_NORMAL)
30
31 def disable(self):
32 self.SensorManager.unregisterListener(self, self.sensor)
33
34 @java_method('(Landroid/hardware/SensorEvent;)V')
35 def onSensorChanged(self, event):
36 self.values = event.values[:3]
37
38 @java_method('(Landroid/hardware/Sensor;I)V')
39 def onAccuracyChanged(self, sensor, accuracy):
40 # Maybe, do something in future?
41 pass
42
43
44 class AndroidCompass(Compass):
45 def __init__(self):
46 super(AndroidCompass, self).__init__()
47 self.bState = False
48
49 def _enable(self):
50 if (not self.bState):
51 self.listener = MagneticFieldSensorListener()
52 self.listener.enable()
53 self.bState = True
54
55 def _disable(self):
56 if (self.bState):
57 self.bState = False
58 self.listener.disable()
59 del self.listener
60
61 def _get_orientation(self):
62 if (self.bState):
63 return tuple(self.listener.values)
64 else:
65 return (None, None, None)
66
67 def __del__(self):
68 if(self.bState):
69 self._disable()
70 super(self.__class__, self).__del__()
71
72
73 def instance():
74 return AndroidCompass()
これ、「3軸の磁力をマイクロテスラで取得」してるだけ。無論これだけが欲しいなんてことはありえない。というか「コンパス」という名前から想像出来る機能ではないわな。よくわかんないんだけど、まさにこの指摘をした人がいるんだけど、なんの議論もコメントもなくそのまんま(何もせずに)クローズされちゃってる。なんか作者に誤解かなにかがあるんじゃないのかなぁ…?
この plyer.compass クラスの何がいけてないかって。結局「全書き換え」しか術がないことね。欲しいものが欲しければ。
「Sensor.TYPE_MAGNETIC_FIELD と Sensor.TYPE_ACCELEROMETER を組み合わせて計算する」の方はともかくとして、まずは TYPE_ORIENTATION を使う方法でやるなら、結局丸々書き換えて:
1 '''
2 Android Compass
3 ---------------------
4 '''
5
6 from plyer.facades import Compass
7 from jnius import PythonJavaClass, java_method, autoclass, cast
8 from plyer.platforms.android import activity
9
10 Context = autoclass('android.content.Context')
11 Sensor = autoclass('android.hardware.Sensor')
12 SensorManager = autoclass('android.hardware.SensorManager')
13
14
15 class MagneticFieldSensorListener(PythonJavaClass):
16 __javainterfaces__ = ['android/hardware/SensorEventListener']
17
18 def __init__(self):
19 super(MagneticFieldSensorListener, self).__init__()
20 self.SensorManager = cast('android.hardware.SensorManager',
21 activity.getSystemService(Context.SENSOR_SERVICE))
22 #self.sensor = self.SensorManager.getDefaultSensor(
23 # Sensor.TYPE_MAGNETIC_FIELD)
24 self.sensor = self.SensorManager.getDefaultSensor(
25 Sensor.TYPE_ORIENTATION)
26
27 self.values = [None, None, None]
28
29 def enable(self):
30 self.SensorManager.registerListener(self, self.sensor,
31 SensorManager.SENSOR_DELAY_NORMAL)
32
33 def disable(self):
34 self.SensorManager.unregisterListener(self, self.sensor)
35
36 @java_method('(Landroid/hardware/SensorEvent;)V')
37 def onSensorChanged(self, event):
38 #self.values = event.values[:3]
39 self.values = event.values
40
41 @java_method('(Landroid/hardware/Sensor;I)V')
42 def onAccuracyChanged(self, sensor, accuracy):
43 # Maybe, do something in future?
44 pass
45
46
47 class AndroidCompass(Compass):
48 def __init__(self):
49 super(AndroidCompass, self).__init__()
50 self.bState = False
51
52 def _enable(self):
53 if (not self.bState):
54 self.listener = MagneticFieldSensorListener()
55 self.listener.enable()
56 self.bState = True
57
58 def _disable(self):
59 if (self.bState):
60 self.bState = False
61 self.listener.disable()
62 del self.listener
63
64 def _get_orientation(self):
65 if (self.bState):
66 return tuple(self.listener.values)
67 else:
68 return (None, None, None)
69
70 def __del__(self):
71 if(self.bState):
72 self._disable()
73 super(self.__class__, self).__del__()
とするしかない、と。
まぁ… plyer.compass の出来はともかくとして、kivy, jnius, plyer 全体としては素晴らしいもんなわけでね。多少間違ってても自力でどうにか出来るのは jnius, plyer のおかげなわけで。