Android 傳感器的數(shù)據(jù)流和框架
應(yīng)用程序怎么樣設(shè)置可以讓自己隨著設(shè)備的傾斜度變化而旋轉(zhuǎn)方向呢?在AndroidManifest.xml文件中的android:screenOrientation就可以了。這里追蹤一下它的內(nèi)部機(jī)制。
先看一個(gè)最關(guān)鍵的部件:/frameworks/base/core/java/android/view/WindowOrientationListener.java
這個(gè)接口注冊(cè)一個(gè)accelerator,并負(fù)責(zé)把a(bǔ)ccelerator的數(shù)據(jù)轉(zhuǎn)化為orientation。這個(gè)API對(duì)應(yīng)用程序不公開(kāi),我看Android2.3的源碼時(shí)發(fā)現(xiàn)只有PhoneWindowManager使用到它了。
/frameworks/base/policy//PhoneWindowManager。java
PhonwWindowManager注冊(cè)了一個(gè)WindowOrientationListener,就可以異步獲取當(dāng)前設(shè)備的orientation了。再結(jié)合應(yīng)用程序在AndroidManifest。xml中設(shè)置的值來(lái)管理著應(yīng)用程序界面的旋轉(zhuǎn)方向。以下是PhoneWindowManager。java中相關(guān)的兩個(gè)代碼片段。
java代碼:
public void onOrientationChanged(int rotation) {
// Send updates based on orientation value
if (localLOGV) Log。v(TAG, "onOrientationChanged, rotation changed to " +rotation);
try {
mWindowManager。setRotation(rotation, false,
mFancyRotationAnimation);
} catch (RemoteException e) {
// Ignore
}
}
…
switch (orientation) {//這個(gè)值就是當(dāng)前設(shè)備屏幕的旋轉(zhuǎn)方向,再結(jié)合應(yīng)用程序設(shè)置的android:configChanges屬性值就可以確定應(yīng)用程序界面的旋轉(zhuǎn)方向了。應(yīng)用程序設(shè)置值的優(yōu)先級(jí)大于傳感器確定的優(yōu)先級(jí)。
case ActivityInfo。SCREEN_ORIENTATION_PORTRAIT:
//always return portrait if orientation set to portrait
return mPortraitRotation;
case ActivityInfo。SCREEN_ORIENTATION_LANDSCAPE:
//always return landscape if orientation set to landscape
return mLandscapeRotation;
case ActivityInfo。SCREEN_ORIENTATION_REVERSE_PORTRAIT:
//always return portrait if orientation set to portrait
return mUpsideDownRotation;
case ActivityInfo。SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
//always return seascape if orientation set to reverse landscape
return mSeascapeRotation;
case ActivityInfo。SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
//return either landscape rotation based on the sensor
mOrientationListener。setAllow180Rotation(
isLandscapeOrSeascape(Surface。ROTATION_180));
return getCurrentLandscapeRotation(lastRotation);
case ActivityInfo。SCREEN_ORIENTATION_SENSOR_PORTRAIT:
mOrientationListener。setAllow180Rotation(
??!isLandscapeOrSeascape(Surface。ROTATION_180));
return getCurrentPortraitRotation(lastRotation);
}
? ? 讓?xiě)?yīng)用程序隨屏幕方向自動(dòng)旋轉(zhuǎn)的實(shí)現(xiàn)原理就這么交待完了。我解決這一步時(shí)也沒(méi)有費(fèi)多少力氣,在板子上打開(kāi)SensorTest,對(duì)比一下XYZ三個(gè)軸和MileStone上面的數(shù)據(jù),修改一下正負(fù)值就可以了。但要解決Teeter運(yùn)行時(shí)Z軸反轉(zhuǎn)的問(wèn)題,還得深層次挖一挖。
PhoneWindowManager。java中有這么一句:
mWindowManager。setRotation(rotation, false, mFancyRotationAnimation);
當(dāng)PhonewindowManager通過(guò)WindowOrientationListener這個(gè)監(jiān)聽(tīng)器得知屏幕方向改變時(shí),會(huì)通知給WindowManagerService(/frameworks/base/service//WindowManagerService。java)
WindowManagerService中有這么一個(gè)監(jiān)聽(tīng)器集合:mRotationWatchers,誰(shuí)想監(jiān)聽(tīng)屏幕方向改變,就會(huì)在這里注冊(cè)一個(gè)監(jiān)聽(tīng)器
java代碼:
public void onRotationChanged(int rotation) {
synchronized(sListeners) {
sRotation??= rotation;
}
}
static int getRotation() {
synchronized(sListeners) {
return sRotation;
}
}
? ?? ???SensorManager要這個(gè)值有什么作用呢?看看在哪里使用了SensorManager。getRotation()吧。只有一個(gè)方法:mapSensorDataToWindow
當(dāng)一個(gè)Activity注冊(cè)了一個(gè)Sensor事件監(jiān)聽(tīng)器后,總是會(huì)通過(guò)接口來(lái)異步獲取sensor事件的。在這里,新老版本出現(xiàn)了分化。老版本中,Android1。5以前,Sensor事件被分發(fā)給監(jiān)聽(tīng)者(onSensorChanged)之前,總會(huì)先用這個(gè)方法處理一下。新版本的監(jiān)聽(tīng)接口是SensorEventListener,分發(fā)前是沒(méi)有處理方法的??匆幌逻@個(gè)方法,原來(lái)是轉(zhuǎn)換坐標(biāo)系用的。應(yīng)用程序的界面方向隨屏幕發(fā)生變化以后,通過(guò)異步分發(fā)接口傳遞給它的傳感器數(shù)據(jù)也要從傳感器的坐標(biāo)系轉(zhuǎn)換到應(yīng)用程序的坐標(biāo)系。假設(shè)屏幕默認(rèn)方向是豎屏,這個(gè)時(shí)候分發(fā)給它的SensorEvent里面的值與frameworks層從HAL的sensor。c中讀到的數(shù)據(jù)是一樣的。當(dāng)設(shè)備右側(cè)抬起,屏幕切換到橫屏是,應(yīng)用程序的界面也旋轉(zhuǎn)了90度,這個(gè)時(shí)候,SensorEvent在分發(fā)給應(yīng)用程序之前就需要先把自己的坐標(biāo)系順時(shí)針旋轉(zhuǎn)90度。
新版本接口中,傳感器數(shù)據(jù)直接通過(guò)SensorEventListener分發(fā)給應(yīng)用程序。而老版本接口中,分發(fā)之前先要結(jié)合當(dāng)前設(shè)備的旋轉(zhuǎn)方向?qū)鞲衅鲾?shù)據(jù)做一個(gè)坐標(biāo)系轉(zhuǎn)換。到這里,一切都清楚了。WindowOrientationListener借助SensorManager的accelerator數(shù)據(jù)制造了屏幕旋轉(zhuǎn)方向,而屏幕旋轉(zhuǎn)方向又被SensorManager用來(lái)兼容老版本的SensorListener接口??梢哉f(shuō),如果不考慮兼容老版本的接口的話(huà),SensorManager是完全不用向WindowManagerService。java中注冊(cè)監(jiān)聽(tīng)器監(jiān)聽(tīng)當(dāng)前設(shè)備屏幕旋轉(zhuǎn)方向的,直接分發(fā)下去就好了。SensorManager的代碼恐怕要減少一半多。framework層是時(shí)候把SensorListener相關(guān)的一系列API扔到一邊了。
還有一個(gè)地方,就是HAL層的sensor。c到SensorManager之間的部分。這個(gè)部分把sensor。c中讀到的傳感器數(shù)據(jù)整合成一個(gè)服務(wù)(SensorService)供SensorManager使用。很好地隔離了API層和HAL層。但從數(shù)據(jù)處理的角度來(lái)講,只是扮演了一個(gè)數(shù)據(jù)傳遞者的角色,沒(méi)有對(duì)數(shù)據(jù)進(jìn)行任何的改變。
上面的寫(xiě)完了,接下來(lái)是HAL層了。各個(gè)廠商的寫(xiě)法都不一樣,有的為了把所有傳感器集成進(jìn)來(lái),還形成了自己的一個(gè)框架。讓我們穿過(guò)HAL框架,直接進(jìn)入sensor。c。這里有我最關(guān)心的最終如何與sensor的driver交互,向上層傳遞了哪些信息。再?gòu)?fù)雜的frameworks,也不過(guò)是把sensor。c提供的接口封裝一下而己。sensor的數(shù)據(jù)從來(lái)沒(méi)有被改變過(guò)。這里只是簡(jiǎn)述一下sensor。c的大致功能,那里我寫(xiě)了一個(gè)可以通過(guò)ADB或者串口運(yùn)行的C++程序?qū)iT(mén)演示控制driver和讀取數(shù)據(jù)的細(xì)節(jié)。
SensorManager要這個(gè)值有什么作用呢?看看在哪里使用了SensorManager.getRotation()吧。只有一個(gè)方法:mapSensorDataToWindow
? ?? ? 當(dāng)一個(gè)Activity注冊(cè)了一個(gè)Sensor事件監(jiān)聽(tīng)器后,總是會(huì)通過(guò)接口來(lái)異步獲取sensor事件的。在這里,新老版本出現(xiàn)了分化。老版本中,Android1.5以前,Sensor事件被分發(fā)給監(jiān)聽(tīng)者(onSensorChanged)之前,總會(huì)先用這個(gè)方法處理一下。新版本的監(jiān)聽(tīng)接口是SensorEventListener,分發(fā)前是沒(méi)有處理方法的。看一下這個(gè)方法,原來(lái)是轉(zhuǎn)換坐標(biāo)系用的。應(yīng)用程序的界面方向隨屏幕發(fā)生變化以后,通過(guò)異步分發(fā)接口傳遞給它的傳感器數(shù)據(jù)也要從傳感器的坐標(biāo)系轉(zhuǎn)換到應(yīng)用程序的坐標(biāo)系。假設(shè)屏幕默認(rèn)方向是豎屏,這個(gè)時(shí)候分發(fā)給它的SensorEvent里面的值與frameworks層從HAL的sensor.c中讀到的數(shù)據(jù)是一樣的。當(dāng)設(shè)備右側(cè)抬起,屏幕切換到橫屏是,應(yīng)用程序的界面也旋轉(zhuǎn)了90度,這個(gè)時(shí)候,SensorEvent在分發(fā)給應(yīng)用程序之前就需要先把自己的坐標(biāo)系順時(shí)針旋轉(zhuǎn)90度。
新版本接口中,傳感器數(shù)據(jù)直接通過(guò)SensorEventListener分發(fā)給應(yīng)用程序。而老版本接口中,分發(fā)之前先要結(jié)合當(dāng)前設(shè)備的旋轉(zhuǎn)方向?qū)鞲衅鲾?shù)據(jù)做一個(gè)坐標(biāo)系轉(zhuǎn)換。到這里,一切都清楚了。WindowOrientationListener借助SensorManager的accelerator數(shù)據(jù)制造了屏幕旋轉(zhuǎn)方向,而屏幕旋轉(zhuǎn)方向又被SensorManager用來(lái)兼容老版本的SensorListener接口??梢哉f(shuō),如果不考慮兼容老版本的接口的話(huà),SensorManager是完全不用向
? ?? ?WindowManagerService.java中注冊(cè)監(jiān)聽(tīng)器監(jiān)聽(tīng)當(dāng)前設(shè)備屏幕旋轉(zhuǎn)方向的,直接分發(fā)下去就好了。SensorManager的代碼恐怕要減少一半多。framework層是時(shí)候把SensorListener相關(guān)的一系列API扔到一邊了。
還有一個(gè)地方,就是HAL層的sensor.c到SensorManager之間的部分。這個(gè)部分把sensor.c中讀到的傳感器數(shù)據(jù)整合成一個(gè)服務(wù)(SensorService)供SensorManager使用。很好地隔離了API層和HAL層。但從數(shù)據(jù)處理的角度來(lái)講,只是扮演了一個(gè)數(shù)據(jù)傳遞者的角色,沒(méi)有對(duì)數(shù)據(jù)進(jìn)行任何的改變。
? ?? ?上面的寫(xiě)完了,接下來(lái)是HAL層了。各個(gè)廠商的寫(xiě)法都不一樣,有的為了把所有傳感器集成進(jìn)來(lái),還形成了自己的一個(gè)框架。讓我們穿過(guò)HAL框架,直接進(jìn)入sensor.c。這里有我最關(guān)心的最終如何與sensor的driver交互,向上層傳遞了哪些信息。再?gòu)?fù)雜的frameworks,也不過(guò)是把sensor.c提供的接口封裝一下而己。sensor的數(shù)據(jù)從來(lái)沒(méi)有被改變過(guò)。這里只是簡(jiǎn)述一下sensor.c的大致功能,那里我寫(xiě)了一個(gè)可以通過(guò)ADB或者串口運(yùn)行的C++程序?qū)iT(mén)演示控制driver和讀取數(shù)據(jù)的細(xì)節(jié)。
? ?? ? 1、給上層提供一個(gè)獲取sensor list的接口。這個(gè)是寫(xiě)死在sensor.c里面的。往一個(gè)設(shè)備上面移植frameworks時(shí),這一部分是要根據(jù)設(shè)備上的sensor來(lái)修改這個(gè)文件的。
? ?? ? 2、給上層提供控制接口:active/deactive某一個(gè)sensor。set某個(gè)sensor的delay值(即,獲取sensor數(shù)據(jù)的頻率,比如設(shè)置為200,000的話(huà),就是驅(qū)動(dòng)每隔200毫秒向上面發(fā)一次數(shù)據(jù))。讀取某個(gè)sensor的數(shù)據(jù)。
現(xiàn)在我們知道了,調(diào)試傳感器時(shí),只在兩個(gè)地方下手就可以了:
? ?? ? 1、/frameworks/base/core/java/android/view/WindowOrientation.java,校正accelerator數(shù)據(jù)與屏幕旋轉(zhuǎn)方向的對(duì)應(yīng)關(guān)系。
? ?? ? 2、/hardware/libhardware/modules/sensor/sensor.c,對(duì)驅(qū)動(dòng)遞上來(lái)的數(shù)據(jù)進(jìn)行初步校正。這一步可以參考一下已經(jīng)的校正好的機(jī)器(我用的是自己的MileStone),然后再運(yùn)行一下SensorTest(網(wǎng)上有的下),只要同一個(gè)擺放姿勢(shì)下,我們讀上來(lái)的數(shù)據(jù)和它的一樣就可以了。因?yàn)榍懊嬲f(shuō)過(guò),在新版本(1.5及以上)接口中,數(shù)據(jù)流經(jīng)過(guò)sensor.c->SensorService->SensorManager,最后通過(guò)onSensorChanged分發(fā)給應(yīng)用程序的整個(gè)過(guò)程中,是從來(lái)沒(méi)有被改變過(guò)的。至于老版本中SensorManager部分做的校正,讓他吃屎去吧。
? ? 我再說(shuō)最后一次:sensor數(shù)據(jù)自從被sensor.c從driver讀上來(lái),一直到傳遞給應(yīng)用程序的onSensorChanged接口,整個(gè)過(guò)程中,數(shù)據(jù)都沒(méi)有被改變過(guò)。這很重要,因?yàn)檫@意味著frameworks層是不需要sensor校正的。我們只需要在WindowOrientationListener里面找到那兩個(gè)數(shù)組(THRESHOLDS和ROTATE_TO),然后調(diào)調(diào)屏幕旋轉(zhuǎn)方向就可以了。
? ?? ? 兼容傳感器老接口時(shí)出現(xiàn)的問(wèn)題。? ?
? ?? ? 屏幕旋轉(zhuǎn)后,傳感器數(shù)據(jù)也要變的坐標(biāo)系,這和以前的理解不一樣,得糾正一下。
? ?? ? 調(diào)試好sensor后,屏幕可以正常旋轉(zhuǎn)了,但HTC手機(jī)自帶的Teeter運(yùn)行起來(lái)有問(wèn)題。跟蹤了一下,發(fā)現(xiàn)Teeter還在使用舊的傳感器監(jiān)聽(tīng)接口onSensorChanged(int sensor, float[] value)。因此,需要修改/frameworks/base/core/java/android/hardware/SensorManager.java中的mapSensorDataToWindow方法,這個(gè)方法負(fù)責(zé)把HAL讀到的原始數(shù)據(jù)轉(zhuǎn)化成舊接口的數(shù)據(jù)(利用onSensorChanged(int
sensor, float[] value)接收到的數(shù)據(jù))。
? ?? ? 目前只做了0度和90度兩個(gè)方向,所以也修改了一下WindowOrientationListener,讓所有API只能在這兩個(gè)方向上旋轉(zhuǎn):
? ?? ?1、mAllow180Rotation變量永遠(yuǎn)設(shè)置為false。
? ?? ?2、修改ROTATE_TO數(shù)組,把270度全部修改為90度。
? ?? ? 另外,sensor.c中poll data的接口會(huì)有一個(gè)int型返回值,表示讀到的sensors_event_t的個(gè)數(shù),這個(gè)值一定要等于實(shí)際個(gè)數(shù)。我自己的程序里面,實(shí)際讀到了一個(gè)(accelerator),但返回時(shí)不管讀到幾個(gè),都返回當(dāng)前傳感器的個(gè)數(shù)。這樣的話(huà),在應(yīng)用程序中用老接口onSensorChanged(int sensor, float[] value)來(lái)監(jiān)聽(tīng)時(shí),除了一個(gè)正常數(shù)據(jù)之外,還會(huì)讀到(sensor.c中的poll data函數(shù)返回值-1)個(gè)全部為0的冗余數(shù)據(jù)。?
通過(guò)AndroidManifest.xml設(shè)置屏幕方向的話(huà),安裝后就不能改變,而程序內(nèi)部設(shè)置屏幕方向就不會(huì)有這個(gè)限制。主要靠這兩個(gè)API:getRequestedOrientation()和setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)這兩個(gè)API通過(guò)ActivityManagerService.java的轉(zhuǎn)換后,實(shí)際上都是調(diào)用的WindowManagerService的同名方法。每個(gè)Activity在WindowManagerService端都有一個(gè)AppWindowToken做代表,而屏幕的方向信息就存儲(chǔ)在這里。
? ?? ? PhoneWindowManager會(huì)自動(dòng)根據(jù)屏幕物理特性決定屏幕方向,看這段代碼:
java代碼:
if (mPortraitRotation < 0) {? ? // Initialize the rotation angles for each orientation once.? ? Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))? ?? ?? ?? ?.getDefaultDisplay();? ? if (d.getWidth() > d.getHeight()) {? ?? ???mPortraitRotation = Surface.ROTATION_90;? ?? ???mLandscapeRotation = Surface.ROTATION_0;? ?? ???mUpsideDownRotation = Surface.ROTATION_270;? ?? ???mSeascapeRotation = Surface.ROTATION_180;? ? } else {? ?? ???mPortraitRotation = Surface.ROTATION_0;? ?? ???mLandscapeRotation = Surface.ROTATION_90;? ?? ???mUpsideDownRotation = Surface.ROTATION_180;? ?? ???mSeascapeRotation = Surface.ROTATION_270;? ? }}
? ?? ? 這里的d.getWidth() 和 d.getHeight()得到的是物理屏幕的寬高。一般來(lái)說(shuō),平板和手機(jī)的是不一樣的。平板是寬比高大(0度時(shí)位于landscape模式,右轉(zhuǎn)90度進(jìn)入porit模式),手機(jī)是高比寬大(0度是位于porit模式,右轉(zhuǎn)90度進(jìn)入landscape模式)。如果應(yīng)用程序只關(guān)心當(dāng)前是橫屏還是豎屏,而不直接使用傳感器的話(huà),沒(méi)什么問(wèn)題。如果像依靠重力感應(yīng)的游戲那樣直接使用傳感器,就需要自己根據(jù)物理屏幕的坐標(biāo)系對(duì)傳感器數(shù)據(jù)做轉(zhuǎn)化,否則就會(huì)出現(xiàn)坐標(biāo)系混亂的問(wèn)題。
? ?? ? 我這里碰到的是Range Thunder和Teeter兩個(gè)小游戲。它們都沒(méi)有通過(guò)上面的d.getWidth()和d.getHeight()來(lái)檢測(cè)設(shè)備的物理屏幕從確定哪個(gè)是landscape和porit模式,而是直接假設(shè)設(shè)備是和手機(jī)一樣的模式。由于游戲運(yùn)行在landscape模式下,它們都把傳感器數(shù)據(jù)右轉(zhuǎn)90度。這樣做法在手機(jī)上是沒(méi)有問(wèn)題,但在平板電腦上是不應(yīng)該轉(zhuǎn)化的,這是因?yàn)槲锢砥聊粚挶雀叽蟮那闆r下,默認(rèn)就是landscape模式。
? ?? ? 看到下面一樓讀者提到的問(wèn)題后,補(bǔ)充一下我針對(duì)他說(shuō)的那個(gè)問(wèn)題的解決方案。? ?? ? 拿新接口來(lái)說(shuō),我們可以在onSensorChangedLocked接口中,SensorEvent傳遞出去之前,對(duì)坐標(biāo)系調(diào)整一下。但是,按照這種方法把使用新接口游戲調(diào)整正確后,發(fā)現(xiàn)使用老接口的游戲又亂了,屏幕的旋轉(zhuǎn)方向也亂了。
? ?? ? 我們已經(jīng)知道,WindowOrientationListener使用SensorManager來(lái)確定屏幕的旋轉(zhuǎn)方向,SensorManager再根據(jù)旋轉(zhuǎn)方向?qū)Φ讓幼x上來(lái)的傳感器做坐標(biāo)系轉(zhuǎn)換,然后傳遞給onSensorChanged(SensorEvent event)。而老接口onSensorChanged(int sensor,float[] value)是用onSensorChanged(SensorEvent event)的數(shù)據(jù)再做坐標(biāo)系轉(zhuǎn)換。所以,你還需要在老接口中根據(jù)新接口中的坐標(biāo)系轉(zhuǎn)換也做相應(yīng)地轉(zhuǎn)換。這樣,使用老接口的游戲也可以了。但屏幕旋轉(zhuǎn)不對(duì)怎么辦?這個(gè)問(wèn)題陷入了一個(gè)怪圈。好吧,就到這,下面記錄一下我的解決方案:? ?? ? 我們先為SensorEvent增加一個(gè)屬性來(lái)記錄傳感器的原始數(shù)據(jù):
java代碼:/**? ???* 這個(gè)注釋一定要加上,要不你編譯時(shí)還要先update-api一下。? ???* {@hide}? ???*/float[] originalValue=new float[3];
? ?? ? 有三個(gè)地方用到它,在onSensorChangedLocked中為新接口做坐標(biāo)系轉(zhuǎn)換,LegacyListener.onSensorChanged接口中為老接口做坐系轉(zhuǎn)換,在WiindowOrientationListener中根據(jù)傳感器數(shù)據(jù)計(jì)算屏幕旋轉(zhuǎn)方向。
? ?? ? 在這三個(gè)地方進(jìn)行計(jì)算時(shí)都使用originalValue里面存放的原始數(shù)據(jù)進(jìn)行計(jì)算,計(jì)算結(jié)果放到SensorEvent.value中。這樣一來(lái),哪個(gè)接口不對(duì)調(diào)整哪個(gè)接口,因?yàn)槎际鞘褂玫脑紨?shù)據(jù),所以互不影響,再不會(huì)出現(xiàn)按下葫蘆起來(lái)瓢的事情了。
? ?? ? 不過(guò)呢,要是寫(xiě)游戲的人比較認(rèn)真,不是只簡(jiǎn)單地考慮Landscape/Porit模式,而是使用Display.getRotation()來(lái)獲取屏幕的旋轉(zhuǎn)實(shí)際角度來(lái)做gsensor數(shù)據(jù)坐標(biāo)系的轉(zhuǎn)換,那他的程序在我們的板子上就悲劇了:
? ?? ? 獲取當(dāng)前屏幕旋轉(zhuǎn)角度:
java代碼:
復(fù)制代碼
? ?? ? 很不幸,Gallery3D就是這樣來(lái)做圖片翻轉(zhuǎn)特效的。下面代碼段位于/packages/apps/Gallery3D/src/com/cooliris/media/GridInputProcessor.java文件中,根據(jù)屏幕旋轉(zhuǎn)角度計(jì)算出圖片的傾斜度。只好讓它使用原始數(shù)據(jù)了,下面分別是修改前和修改后的代碼。
? ?? ? 修改前:
java代碼:
? ?? ???修改后的代碼:
java代碼:
public void onSensorChanged(RenderView view, SensorEvent event, int state) {
if (mZoomGesture)
return;
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
float[] values = event.original;
float valueToUse;
switch (mDisplay.getRotation()) {
case Surface.ROTATION_0:
valueToUse = values[0];
break;
case Surface.ROTATION_90:
valueToUse = -values[1];
break;
case Surface.ROTATION_180:
valueToUse = -values[0];
break;
case Surface.ROTATION_270:
valueToUse = values[1];
break;
default:
valueToUse = 0.0f;
}
... ...
}
}