當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]應(yīng)用程序怎么樣設(shè)置可以讓自己隨著設(shè)備的傾斜度變化而旋轉(zhuǎn)方向呢?在AndroidManifest.xml文件中的android:screenOrientation就可以了。這里追蹤一下它的內(nèi)部機(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;
}
... ...
}
}

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶(hù)希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱(chēng),數(shù)字世界的話(huà)語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱(chēng)"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉