產(chǎn)品分類

      當前位置: 首頁 > 工業(yè)電子產(chǎn)品 > 集成電路(ICs) > IC傳感器

      類型分類:
      科普知識
      數(shù)據(jù)分類:
      IC傳感器

      android 傳感器 源碼:Android傳感器源碼分析(AOSP)

      發(fā)布日期:2022-05-11 點擊率:37


      android 傳感器 源碼:Android傳感器源碼分析(AOSP)  第1張

      android 傳感器 源碼:Android傳感器源碼分析(AOSP)

      簡介
      上一節(jié)制作了一個傳感器的應(yīng)用,應(yīng)用程序獲取傳感器數(shù)據(jù)代碼流程大致如下

      源碼分析
      如上所示,在應(yīng)用層調(diào)用幾個常用接口就能夠獲取到傳感器數(shù)據(jù)了,主要接口包括

      下面對這四個接口為主線來學習源代碼,理解傳感器的框架

      getSystemService
      該接口是一個用來獲取系統(tǒng)服務(wù)的接口,SensorManager是一個抽象類,為應(yīng)用層提供傳感器接口,SystemSensorManager繼承SensorManager實現(xiàn)了這些接口功能,我們來看一下SystemSensorManager的創(chuàng)建.

      SystemSensorManager在SystemServiceRegistry的靜態(tài)初始化塊當中,因此在系統(tǒng)初始階段加載SystemServiceRegistry時,SystemSensorManager就會被創(chuàng)建,來看一下它的構(gòu)造函數(shù)

      調(diào)用nativeCreate創(chuàng)建Native層的SensorManager,在創(chuàng)建過程中會循環(huán)等待SensorService被創(chuàng)建,與其建立binder關(guān)系,接著調(diào)用SensorSerivce的getSensorList,來獲取硬件傳感器列表信息.

      上面SensorManager會等待SensorService注冊,將它保存在成員變量mSensorServer中.小結(jié)一下這一段流程UML圖

      SensorManager功能都來自于SensorService,它在Android的Sensor框架中占據(jù)核心位置,接下來看一下分析一下SensorService的相關(guān)代碼.
      當內(nèi)核啟動后執(zhí)行init 程序,該程序解析 init.rc文件(zygote包含在init.${ro.zygote}.rc中),rc文件中指定的應(yīng)用程序在app_main.cpp中,調(diào)用AndroidRuntime的start方法,接著通過JNI調(diào)用Zyoteinit.java中的main函數(shù),從這里開始追蹤.

      上面代碼可知ZygoteInit的main函數(shù)執(zhí)中調(diào)用startSystemServer函數(shù),調(diào)用forkSystemServer創(chuàng)建系統(tǒng)服務(wù),跳轉(zhuǎn)到SystemServer的main函數(shù)

      在 SystemServer 的main函數(shù)中,會創(chuàng)建SystemService對象,并調(diào)用run方法,在run方法中調(diào)用startBootstrapServices(),接著調(diào)用Native方法startSensorService(),

      在android_server_SystemServer_startSensorService中創(chuàng)建線程start_sensor_service來實例化SensorService,然后將SensorService添加到ServiceManager當中(SensorManager從ServiceManager里獲取SensorService).當SensorService被創(chuàng)建時,onFirstRef被調(diào)用,這個初始化函數(shù)完成了一些重要的初始化過程,我們來看一下

      在 SensorService 的 onFirstRef 接口中,獲取SensorDevice(單例類)的引用,這里看一下SensorDevice的構(gòu)造函數(shù)

      SensorDevice調(diào)用 hw_get_module接口加載HAL的Sensor庫庫,接著調(diào)用HAL層提供的open接口,執(zhí)行HAL層的初始化,同時返回硬件訪問接口,接著調(diào)用 Sensor HAL提供的 get_sensors_list 接口,獲取所支持的 Sensor列表.
      接著上面SensorService::onFirstRef接口,通過SensorDevice獲取傳感器列表信息后,調(diào)用registerSensor分別將傳感器添加到mSensors中.然后創(chuàng)建 Looper , Looper用來監(jiān)聽傳感器數(shù)據(jù)的上報和分發(fā),接著調(diào)用run方法,啟動threadLoop,輪詢HAL層傳感器數(shù)據(jù)的上報.來看一下SensorService的threadLoop

      SensorService的流程圖

      getDefaultSensor/getSensorList
      SensorManager.java中的getDefaultSensor方法是依賴getSensorlist實現(xiàn)的,來看一下getSensorlist方法.

      registerListener
      SensorManager.java向應(yīng)用提供的registerListener方法,最終會調(diào)到SystemSensorManager中的registerListenerImpl方法,

      創(chuàng)建一個與looper,listener相關(guān)聯(lián)的SensorEventQueue,看一下SensorEventQueue的構(gòu)造函數(shù),

      接著看它的基類baseEventQueue和它的nativeInitbaseEventQueue方法.

      nativeInitSensorEventQueue中,有兩件事要注意,1.創(chuàng)建SensorEventQueue對象2.創(chuàng)建Receiver.先看一下SensorEventQueue的創(chuàng)建

      SensorManager通過mSensorServer(它是在SensorManager構(gòu)造函數(shù)里getService獲得)的createSensorEventConnection接口,創(chuàng)建一個SensorEventConnection對象,它是SensorService的內(nèi)部類,在SensorService::enable中被添加,用來在接收到的HAL層的數(shù)據(jù)發(fā)送出去的重要通道.接著創(chuàng)建一個與這個SensorEventConnection對象關(guān)聯(lián)的SensorEventQueue對象,并返回.Native層的SensorEventQueue是非常重要的數(shù)據(jù)通道,一方面接收Native層SensorService發(fā)送過來的數(shù)據(jù)(SensorService的數(shù)據(jù)來自HAL層),另一方面將數(shù)據(jù)分發(fā)到framewrok層SystemSensorManager的baseEventQueue子類對象中.后面會通過代碼說明這個過程如何發(fā)生.接著看Receiver類,Receiver構(gòu)造函數(shù)

      Receiver構(gòu)造函數(shù)中,主要建立與SensorService和MessageQueue之間的關(guān)聯(lián),接著看它的onFirstRef.

      Native層的MessageQueue調(diào)用Looper類的addFd方法,添加對SensorEventQueue的監(jiān)聽,看一下looper的addFd方法.

      Receiver繼承LooperCallback并實現(xiàn)了handleEvent函數(shù),addFD時會將callback傳入Looper.Looper的addFd如果被監(jiān)控的文件描述符,已經(jīng)存在用EPOLL_CTL_MOD參數(shù)調(diào)用epoll_ctl修改,否則,EPOLL_CTL_ADD來添加.(Native層的Looper是以epoll為核心實現(xiàn)的,對Looper不熟悉的可以看一下epoll的簡介).Looper在添加文件描述符后,后續(xù)通過pollOnce或pollAll接口來訪問,最終都會調(diào)用pollInner來等待這些文件描述符被寫入數(shù)據(jù),我們來看一下pollInner

      在Looper中epoll_wait來監(jiān)聽文件描述符是否有數(shù)據(jù)寫入,當有數(shù)據(jù)寫入后,調(diào)用callback的handleEvent方法來進行處理,這里是調(diào)用了Receiver的handleEvent方法,handleEvent中依賴于SensorEventQueue中的mSensorChannel(mSensorChannel是在SensorEventConnection構(gòu)造時創(chuàng)建的)來實現(xiàn)數(shù)據(jù)的讀取的,mSensorChannel是一個BitTube對象,BitTube提供全雙工的跨進程的通訊管道(這里對它做了一個說明,有興趣可以了解一下),handleEvent依賴它來獲取發(fā)送過來的數(shù)據(jù)(數(shù)據(jù)從哪發(fā)來?我們后面再說),我們看一下Receiver的handleEvent接口

      上面會根據(jù)不同類型的傳感器將數(shù)據(jù)進行處理,常用傳感器通過 gbaseEventQueueClassInfo.dispatchSensorEvent進行分發(fā),這里實際上是調(diào)用的framework層的SensorEventQueue類(繼承baseEventQueue)的dispatchSensorEvent方法.

      dispatchSensorEvent里,通過handle找到對應(yīng)的sensor,將數(shù)據(jù)通過SensorEventListener的onSensorChanged將數(shù)據(jù)給應(yīng)用程序.
      回顧一下前面的流程,Looper通過epoll_wait將數(shù)據(jù)讀出,回調(diào)Receiver的handleEvent函數(shù),handleEvent調(diào)用SensorEventQueuem的read方法讀取數(shù)據(jù),然后通過JNI回調(diào)framework層SensorEventQueue的dispatchSensorEvent方法,在dispatchSensorEvent方法中回調(diào)SensorEventListener的onSensorChanged方法,這個方法為應(yīng)用注冊的監(jiān)聽方法,將數(shù)據(jù)返回到應(yīng)用層.可是是誰將數(shù)據(jù)寫入Looper監(jiān)控的文件描述符中的?我們接著看一下這個過程.之前說過”handleEvent調(diào)用SensorEventQueue的read方法讀取數(shù)據(jù)”,讀取和寫入都依賴于BitTube對象,它在SensorEventConnection構(gòu)造函數(shù)中創(chuàng)建(mChannel),然后SensorEventQueue通過getSensorChannel()接口獲取該對象,(這里可以按照mSensorChannel的線索,反推寫入數(shù)據(jù)的地方,接下來直接描述結(jié)果),SensorService在onFirstRef最后執(zhí)行了run,threadLoop開始運行,這個函數(shù)上面分析過了,在最后時

      SensorEventConnection的sendEvents方法會將數(shù)據(jù)寫入BitTube中

      到這里傳感器數(shù)據(jù)的寫入,讀取流程分析完畢.
      這里在簡述一下數(shù)據(jù)的完整流程:SensorService的threadLoop線程,循環(huán)通過SensorDevice的poll接口,從HAL層獲取傳感器數(shù)據(jù),然后調(diào)用已建立好的傳感器連接通道SensorEventConnection的sendEvents方法,寫入到BitTube的socketpai通道中,Looper函數(shù)的epoll_wait被喚醒,然后回調(diào)Receiver的handleEvent方法,在該方法中SensorEventQueue會讀取socketpai通道里的數(shù)據(jù),調(diào)用JNI調(diào)用framework層的SensorEventQueue的dispatchSensorEvent方法,在此方法中回調(diào)SensorEventListener的onSensorChanged方法和onAccuracyChanged,這兩個方法就是應(yīng)用程序注冊的方法.
      傳感器HAL層的AOSP部分包括sensor.h,接下來看一下這個文件內(nèi)容.

      HAL層關(guān)鍵結(jié)構(gòu)和接口
      HAL層中關(guān)鍵的結(jié)構(gòu)和接口存在sensor.h文件中,包括:sensor_module_t、sensors_poll_device_1、get_sensors_list等

      sensor.h
      sensor_module_t

      sensors_poll_device_1

      sensors_poll_device_1_t兼容老1.0版本sensors_poll_device_t,并提供了新版本接口batch,flush,inject_sensor_data接口.
      - get_sensors_list

      獲取所有sensor的列表,由*list指向,傳遞給上層使用.又的平臺是靜態(tài)方式注冊list,有的平臺動態(tài)方式注冊.

      set_operation_mode

      模式設(shè)置接口,用來將sensor service注入的數(shù)據(jù)返回.因傳感器數(shù)據(jù)來自于底層硬件,這個方式多用于調(diào)試或特殊功能,多數(shù)平臺不實現(xiàn)這個接口.

      sensor_t

      這個結(jié)構(gòu)體在實現(xiàn)hal層代碼時,參數(shù)已又英文注釋,重點關(guān)注handle、type、minDelay、flags.

      sensors_event_t

      傳感器數(shù)據(jù)上報的結(jié)構(gòu)體,注意sensor和sensors_vec_t,sensor變量對應(yīng)的是handle,如果不匹配將無法被上層enable,sensors_vec_t中的status默認為0,需要設(shè)置為大于0的狀態(tài),否則上層會將數(shù)據(jù)丟棄,status可選參數(shù)如下

      HAL層以下部分各SOC廠商實現(xiàn)方式不同(有些走input,有些走IIO,有些走share memory),這里不繼續(xù)追述.

      android 傳感器 源碼:android各傳感器開發(fā),顯示返回數(shù)據(jù) 碼農(nóng)集市專業(yè)分享IT編程學習資源

      關(guān)于碼農(nóng)集市

      本站旨在為廣大IT學習愛好者提供一個非營利性互相學習交流分享平臺。本站所有資源都可以被免費獲取學習研究。本站資源來自網(wǎng)友分享,僅供學習研究,請務(wù)必在下載后24小時內(nèi)給予刪除,不得用于其他任何用途,否則后果自負。基于互聯(lián)網(wǎng)的特殊性,coder100無法對用戶傳輸?shù)淖髌贰⑿畔ⅰ?nèi)容的權(quán)屬或合法性、安全性、合規(guī)性、真實性、科學性、完整權(quán)、有效性等進行實質(zhì)審查;無論coder100經(jīng)營者是否已進行審查,用戶均應(yīng)自行承擔因其傳輸?shù)淖髌贰⑿畔ⅰ?nèi)容而可能或已經(jīng)產(chǎn)生的侵權(quán)或權(quán)屬糾紛等法律責任。本站所有資源不代表本站的觀點或立場,基于網(wǎng)友分享,根據(jù)中國法律《信息網(wǎng)絡(luò)傳播權(quán)保護條例》第二十二條之規(guī)定,若資源存在侵權(quán)或相關(guān)問題請聯(lián)系本站客服人員,#qq.com,請把#換成@,本站將給予最大的支持與配合,做到及時反饋和處理。關(guān)于更多版權(quán)及免責申明參見  版權(quán)及免責申明

      android 傳感器 源碼:[實戰(zhàn)示例] 帶您深入探討 Android 傳感器【附源碼】

      轉(zhuǎn)自:
      Android 是一個面向應(yīng)用程序開發(fā)的富平臺,它擁有許多具有吸引力的用戶界面元素和數(shù)據(jù)管理功能。Android 還提供了一組豐富的接口選項。
      在本文中,學習如何配合使用 Android 的各種傳感器選項監(jiān)控您的環(huán)境。樣例代碼展示了如何在 Android 電話中錄制音頻。想構(gòu)建自己的監(jiān)視器嗎?想用聲音來接聽電話或者打開房門嗎?請學習如何利用配備有 Android 的設(shè)備的硬件功能。
      對于 Java? 開發(fā)人員來說,Android 平臺是通過使用硬件傳感器創(chuàng)建創(chuàng)新應(yīng)用程序的理想平臺。我們將學習一些可用于 Android 應(yīng)用程序的接口連接選項,包括使用傳感器子系統(tǒng)和錄制音頻片段。
      利用配備 Android 的設(shè)備的硬件功能可以構(gòu)建哪些應(yīng)用程序呢?任何需要電子監(jiān)視和監(jiān)聽的應(yīng)用程序都可以構(gòu)建。嬰兒監(jiān)視器、安全系統(tǒng),甚至地震儀都可以。理論上講,您不能同時出現(xiàn)在兩個地方,但 Android 可以利用一些可行的方法實現(xiàn)這一點。縱觀本文始末,您必須記住,使用的 Android 設(shè)備不僅僅局限于 “手機”,還可以是部署在固定位置、具有無線網(wǎng)絡(luò)連接的設(shè)備,比如 EDGE 或 WiFi。請下載附件中本文示例的源代碼。
      Android 傳感器功能
      使用 Android 平臺有一個很新穎的地方,那就是您可以在設(shè)備內(nèi)部訪問一些“好工具”。過去,訪問設(shè)備底層硬件的能力一度讓移動開發(fā)人員感到非常棘手。盡管 Android Java 環(huán)境的角色仍然是您和設(shè)備的橋梁,但Android 開發(fā)團隊讓許多硬件功能浮出了水面。該平臺是一個開源平臺,因此您可以自由地編寫代碼實現(xiàn)您的任務(wù)。
      如果尚未安裝 Android,您可以 下載     Android SDK。您還可以 瀏覽 android.hardware 包的內(nèi)容并參考本文的示例。android.media 包 包含了一些提供有用和新穎功能的類。
      Android SDK 中包含的一些面向硬件的功能描述如下。
      表 1. Android SDK 中提供的面向硬件的特性
      特性
      描述
      android.hardware.Camera
      允許應(yīng)用程序與相機交互的類,可以截取照片、獲取預(yù)覽屏幕的圖像,修改用來治理相機操作的參數(shù)。
      android.hardware.SensorManager
      允許訪問 Android 平臺傳感器的類。并非所有配備 Android 的設(shè)備都支持 SensorManager 中的所有傳感器,雖然這種可能性讓人非常興奮。(可用傳感器的簡介見下文)
      android.hardware.SensorListener
      在傳感器值實時更改時,希望接收更新的類要實現(xiàn)的接口。應(yīng)用程序?qū)崿F(xiàn)該接口來監(jiān)視硬件中一個或多個可用傳感器。例如,本文中的 代碼 包含實現(xiàn)該接口的類,實現(xiàn)后可以監(jiān)視設(shè)備的方向和內(nèi)置的加速表。
      android.media.MediaRecorder
      用于錄制媒體樣例的類,對于錄制特定位置(比如嬰兒保育)的音頻活動非常有用。還可以分析音頻片段以便在訪問控件或安全應(yīng)用程序時進行身份鑒定。例如,它可以幫助您通過聲音打開門,以節(jié)省時間,不需要從房產(chǎn)經(jīng)紀人處獲取鑰匙。
      android.FaceDetector
      允許對人臉(以位圖形式包含)進行基本識別的類。不可能有兩張完全一樣的臉。可以使用該類作為設(shè)備鎖定方法,無需記密碼 — 這是手機的生物特征識別功能。
      android.os.*
      包含幾個有用類的包,可以與操作環(huán)境交互,包括電源管理、文件查看器、處理器和消息類。和許多可移動設(shè)備一樣,支持 Android 的電話可能會消耗大量電能。讓設(shè)備在正確的時間 “醒來” 以監(jiān)視感興趣的事件是在設(shè)計時需要首先關(guān)注的方面。
      java.util.Date
      java.util.Timer
      java.util.TimerTask
      當測量實際的事件時,數(shù)據(jù)和時間往往很重要。例如,java.util.Date 類允許您在遇到特定的事件或狀況時獲取時間戳。您可以使用 java.util.Timer 和 java.util.TimerTask 分別執(zhí)行周期性任務(wù)或時間點任務(wù)。

      android.hardware.SensorManager 包含幾個常量,這表示 Android 傳感器系統(tǒng)的不同方面,包括:傳感器類型方向、加速表、光線、磁場、臨近性、溫度等。采樣率最快、游戲、普通、用戶界面。當應(yīng)用程序請求特定的采樣率時,其實只是對傳感器子系統(tǒng)的一個提示,或者一個建議。不保證特定的采樣率可用。準確性高、低、中、不可靠。
      SensorListener 接口是傳感器應(yīng)用程序的中心。它包括兩個必需方法:
      onSensorChanged(int sensor,float values[]) 方法在傳感器值更改時調(diào)用。該方法只對受此應(yīng)用程序監(jiān)視的傳感器調(diào)用(更多內(nèi)容見下文)。該方法的參數(shù)包括:一個整數(shù),指示更改的傳感器;一個浮點值數(shù)組,表示傳感器數(shù)據(jù)本身。有些傳感器只提供一個數(shù)據(jù)值,另一些則提供三個浮點值。方向和加速表傳感器都提供三個數(shù)據(jù)值。
      當傳感器的準確性更改時,將調(diào)用 onAccuracyChanged(int sensor,int accuracy) 方法。參數(shù)包括兩個整數(shù):一個表示傳感器,另一個表示該傳感器新的準確值。

      要與傳感器交互,應(yīng)用程序必須注冊以偵聽與一個或多個傳感器相關(guān)的活動。注冊使用 SensorManager 類的 registerListener 方法完成。本文中的源代碼中演示了如何注冊和注銷 SensorListener。
      記住,并非所有支持 Android 的設(shè)備都支持 SDK 中定義的所有傳感器。如果某個傳感器無法在特定的設(shè)備上使用,您的應(yīng)用程序就會適當?shù)亟导墶?br/>傳感器示例
      樣例應(yīng)用程序僅監(jiān)控對方向和加速表傳感器的更改(見源代碼)。當收到更改時,傳感器值在 TextView 小部件的屏幕上顯示。
      圖 1 展示了該應(yīng)用程序的運行情況。
      圖 1.  監(jiān)視加速和方向

      使用 Eclipse 環(huán)境和 Android Developer Tools 插件創(chuàng)建的應(yīng)用程序。清單 1 展示了該應(yīng)用程序的代碼。
      清單 1. IBMEyes.java

      package com.msi.ibm.eyes;
      import android.app.Activity;
      import android.os.Bundle;
      import android.util.Log;
      import android.widget.TextView;
      import android.hardware.SensorManager;
      import android.hardware.SensorListener;
      public class IBMEyes extends Activity implements SensorListener {
      final String tag="IBMEyes";
      SensorManager sm=null;
      TextView xViewA=null;
      TextView yViewA=null;
      TextView zViewA=null;
      TextView xViewO=null;
      TextView yViewO=null;
      TextView zViewO=null;

      @Override
      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
        // get reference to SensorManager
      sm=(SensorManager) getSystemService(SENSOR_SERVICE);
      setContentView(R.layout.main);
      xViewA=(TextView) findViewById(R.id.xbox);
      yViewA=(TextView) findViewById(R.id.ybox);
      zViewA=(TextView) findViewById(R.id.zbox);
      xViewO=(TextView) findViewById(R.id.xboxo);
      yViewO=(TextView) findViewById(R.id.yboxo);
      zViewO=(TextView) findViewById(R.id.zboxo);
      }
      public void onSensorChanged(int sensor, float[] values) {
      synchronized (this) {
      Log.d(tag, "onSensorChanged: " + sensor + ", x: " +
      values[0] + ", y: " + values[1] + ", z: " + values[2]);
      if (sensor==SensorManager.SENSOR_ORIENTATION) {
      xViewO.setText("Orientation X: " + values[0]);
      yViewO.setText("Orientation Y: " + values[1]);
      zViewO.setText("Orientation Z: " + values[2]);
      }
      if (sensor==SensorManager.SENSOR_ACCELEROMETER) {
      xViewA.setText("Accel X: " + values[0]);
      yViewA.setText("Accel Y: " + values[1]);
      zViewA.setText("Accel Z: " + values[2]);
      }
      }
      }

      public void onAccuracyChanged(int sensor, int accuracy) {
      Log.d(tag,"onAccuracyChanged: " + sensor + ", accuracy: " + accuracy);
      }
      @Override
      protected void onResume() {
      super.onResume();
       // register this class as a listener for the orientation and accelerometer sensors
      sm.registerListener(this,
      SensorManager.SENSOR_ORIENTATION |SensorManager.SENSOR_ACCELEROMETER,
      SensorManager.SENSOR_DELAY_NORMAL);
      }

      @Override
      protected void onStop() {
      // unregister listener
      sm.unregisterListener(this);
      super.onStop();
      }
      }

      編寫應(yīng)用程序必須基于常見的活動,因為它只是利用從傳感器獲取的數(shù)據(jù)更新屏幕。在設(shè)備可能在前臺執(zhí)行其他活動的應(yīng)用程序中,將應(yīng)用程序構(gòu)建為服務(wù)可能更加合適。
      該活動的 onCreate 方法可以引用 SensorManager,其中包含所有與傳感器有關(guān)的函數(shù)。onCreate 方法還建立了對 6 個 TextView 小部件的引用,您需要使用傳感器數(shù)據(jù)值更新這些小部件。

      onResume() 方法使用對 SensorManager 的引用通過 registerListener 方法注冊傳感器更新:
      第一個參數(shù)是實現(xiàn) SensorListener 接口的類的實例。
      第二個參數(shù)是所需傳感器的位掩碼。在本例中,應(yīng)用程序從 SENSOR_ORIENTATION 和 SENSOR_ACCELEROMETER 請求數(shù)據(jù)。
      第三個參數(shù)是一個系統(tǒng)提示,指出應(yīng)用程序更新傳感器值所需的速度。

      應(yīng)用程序(活動)暫停后,需要注銷偵聽器,這樣以后就不會再收到傳感器更新。這通過 SensorManager 的 unregisterListener 方法實現(xiàn)。惟一的參數(shù)是 SensorListener 的實例。
      在 registerListener 和 unregisterListener 方法調(diào)用中,應(yīng)用程序使用關(guān)鍵字 this。注意類定義中的 implements 關(guān)鍵字,其中聲明了該類實現(xiàn) SensorListener 接口。這就是要將它傳遞到 registerListener 和 unregisterListener 的原因。

      SensorListener 必須實現(xiàn)兩個方法 onSensorChange 和 onAccuracyChanged。示例應(yīng)用程序不關(guān)心傳感器的準確度,但關(guān)注傳感器當前的 X、Y 和 Z 值。onAccuracyChanged 方法實質(zhì)上不執(zhí)行任何操作;它只在每次調(diào)用時添加一個日志項。
      似乎經(jīng)常需要調(diào)用 onSensorChanged方法,因為加速表和方向傳感器正在快速發(fā)送數(shù)據(jù)。查看第一個參數(shù)確定哪個傳感器在發(fā)送數(shù)據(jù)。確認了發(fā)送數(shù)據(jù)的傳感器之后,將使用方法第二個參數(shù)傳遞的浮點值數(shù)組中所包含的數(shù)據(jù)更新相應(yīng)的 UI元素。該示例只是顯示這些值,但在更加高級的應(yīng)用程序中,還可以分析這些值,比較原來的值,或者設(shè)置某種模式識別算法來確定用戶(或外部環(huán)境)的行為。
      現(xiàn)在您已經(jīng)了解了傳感器子系統(tǒng),接下來的部分將回顧一個在 Android 手機上錄制音頻的代碼樣例。該樣例運行在 DEV1 開發(fā)設(shè)備上。
      使用 MediaRecorder

      android.media 包包含與媒體子系統(tǒng)交互的類。使用 android.media.MediaRecorder 類進行媒體采樣,包括音頻和視頻。MediaRecorder 作為狀態(tài)機運行。您需要設(shè)置不同的參數(shù),比如源設(shè)備和格式。設(shè)置后,可執(zhí)行任何時間長度的錄制,直到用戶停止。

      清單 2 包含的代碼在 Android 設(shè)備上錄制音頻。顯示的代碼不包括應(yīng)用程序的 UI 元素(見源代碼)。
      清單 2. 錄制音頻片段

      MediaRecorder mrec ;
      File audiofile=null;
      private static final String TAG="SoundRecordingDemo";
      protected void startRecording() throws IOException
      {
        mrec.setAudioSource(MediaRecorder.AudioSource.MIC);
        mrec.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        if (mSampleFile==null)
        {
        File sampleDir=Environment.getExternalStorageDirectory();
        try
        {
       audiofile=File.createTempFile("ibm", ".3gp", sampleDir);
        }
        catch (IOException e)
        {
        Log.e(TAG,"sdcard access error");
        return;
        }
        }
        mrec.setOutputFile(audiofile.getAbsolutePath());
        mrec.prepare();
        mrec.start();
      }
      protected void stopRecording()
      {
        mrec.stop();
        mrec.release();
        processaudiofile(audiofile.getAbsolutePath());
      }
      protected void processaudiofile()
      {
        ContentValues values=new ContentValues(3);
        long current=System.currentTimeMillis();
        values.put(MediaStore.Audio.Media.TITLE, "audio" + audiofile.getName());
        values.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000));
        values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/3gpp");
        values.put(MediaStore.Audio.Media.DATA, audiofile.getAbsolutePath());
        ContentResolver contentResolver=getContentResolver();

      Uri base=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        Uri newUri=contentResolver.insert(base, values);

      sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri));
      }

      在 startRecording 方法中,實例化并初始化 MediaRecorder 的實例:
      輸入源被設(shè)置為麥克風(MIC)。
      輸出格式被設(shè)置為 3GPP(*.3gp 文件),這是移動設(shè)備專用的媒體格式。
      編碼器被設(shè)置為 AMR_NB,這是音頻格式,采樣率為 8 KHz。NB 表示窄頻。SDK 文檔 解釋了不同的數(shù)據(jù)格式和可用的編碼器。

      音頻文件存儲在存儲卡而不是內(nèi)存中。External.getExternalStorageDirectory() 返回存儲卡位置的名稱,在該目錄中將創(chuàng)建一個臨時文件名。然后,通過調(diào)用 setOutputFile 方法將文件關(guān)聯(lián)到 MediaRecorder 實例。音頻數(shù)據(jù)將存儲到該文件中。

      調(diào)用 prepare 方法完成 MediaRecorder 的初始化。準備開始錄制流程時,將調(diào)用 start 方法。在調(diào)用 stop 方法之前,將對存儲卡上的文件進行錄制。release 方法將釋放分配給 MediaRecorder 實例的資源。
      音頻采樣完成之后,需要采取以下步驟:
      向設(shè)備的媒體庫添加該音頻。
      執(zhí)行一些模式識別步驟確定聲音:
      這是嬰兒的啼哭聲嗎?
      這是所有人的聲音嗎?是否要解鎖手機?
      這是 “芝麻開門” 嗎?是否要打開通往 “秘密通道” 的大門?
      自動將音頻文件上傳到網(wǎng)絡(luò)位置以便處理。

      在該代碼樣例中,processaudiofile 方法將音頻添加到媒體庫。使用 Intent 通知設(shè)備上的媒體應(yīng)用程序有新內(nèi)容可用。

      關(guān)于該代碼片段最后要注意的是:如果您試用,它一開始不會錄制音頻。您將看到創(chuàng)建的文件,但是沒有任何音頻。
      您需要向 AndroidManifest.xml 文件添加權(quán)限:

      現(xiàn)在,您已經(jīng)學了一點關(guān)于與 Android 傳感器和錄制音頻相關(guān)的內(nèi)容。下一節(jié)將更全面的介紹與數(shù)據(jù)采集和報告系統(tǒng)有關(guān)的應(yīng)用程序架構(gòu)。
      Android 作為傳感器平臺

      Android 平臺包含各種用于監(jiān)視環(huán)境的傳感器選項。有了輸入或模擬選項數(shù)組,以及高級計算和互聯(lián)功能,Android 成為構(gòu)建實際系統(tǒng)的最佳平臺。
      圖 2 顯示了輸入、應(yīng)用程序邏輯、通知方法或輸出之間的簡單視圖。

      圖 2. 以 Android 為中心的傳感器系統(tǒng)的方塊圖

      該架構(gòu)很靈活;應(yīng)用程序邏輯可以劃分為本地 Android 設(shè)備和服務(wù)器端資源(可以實現(xiàn)更大的數(shù)據(jù)庫和計算功能)。
      例如,本地 Android 設(shè)備上錄制的音軌可以 POST 到 Web 服務(wù)器,其中將根據(jù)音頻模式數(shù)據(jù)庫比較數(shù)據(jù)。很明顯,這僅僅是冰山一角。希望您能更深入地研究,讓 Android 平臺超越移動電話的范疇。
      結(jié)束語

      在本文中,我們介紹了 Android 傳感器。樣例應(yīng)用程序度量了方向和加速,以及使用 MediaRecorder 類與錄制功能進行交互。對于構(gòu)建實際系統(tǒng),Android 是一個靈活、有吸引力的平臺。Android 領(lǐng)域發(fā)展迅速,并且不斷壯大。請務(wù)必關(guān)注該平臺。
      android 傳感器 源碼:Android傳感器源碼分析(AOSP)  第2張

      android 傳感器 源碼:分享一套源碼十多種安卓傳感器如何使用的源碼十分全面

      private long lastUpdateTime;
      // 手機上一個位置時重力感應(yīng)坐標
      private float lastX;
      private float lastY;
      private float lastZ;
      Vibrator vibrator;
      // 速度閾值,當搖晃速度達到這值后產(chǎn)生作用
      private static final int SPEED_SHRESHOLD=1000;
      // 兩次檢測的時間間隔
      private static final int UPTATE_INTERVAL_TIME=70;
      private DevicePolicyManager deviceManager;
      // private boolean isAdmin;
      private PowerManager pm;
      public void onSensorChanged(SensorEvent event) {
      // 現(xiàn)在檢測時間
      long currentUpdateTime= System.currentTimeMillis();
      // 兩次檢測的時間間隔
      long timeInterval=currentUpdateTime - lastUpdateTime;
      // 判斷是否達到了檢測時間間隔
      // if (timeInterval < UPTATE_INTERVAL_TIME)        // return;        // 現(xiàn)在的時間變成last時間        lastUpdateTime= currentUpdateTime;        // 獲得x,y,z坐標        float x=event.values[0];        float y=event.values[1];        float z=event.values[2];        // if (Math.abs(x) > 9.0 || Math.abs(y) > 9.0) {
      // Log.e("onSensorChanged", Math.abs(x)+"::"+Math.abs(y));
      // Log.e("onSensorChanged", isAdmin+"");
      // if (!isAdmin) {
      // Log.e("onSensorChanged", isAdmin+"");
      // deviceManager.lockNow();
      // // deviceManager.resetPassword("", 0);
      // }
      // }
      //
      // 獲得x,y,z的變化值
      float deltaX=x - lastX;
      float deltaY=y - lastY;
      float deltaZ=z - lastZ;
      // Log.e("onSensorChanged", deltaX+
      // "::::"+deltaY+"::::::"+deltaZ+"::::"+timeInterval);
      // 將現(xiàn)在的坐標變成last坐標
      lastX= x;
      lastY = y;
      lastZ = z;

      // double riderSpeed=Math.sqrt(deltaX * deltaX + deltaY * deltaY +
      // deltaZ * deltaZ);
      //
      // if (riderSpeed > 5) {
      // // 按照自己需求設(shè)置屏幕的亮度
      // toggleBrightness(this);
      // Log.e(TAG, brightness + ":::" +
      // isAutoBrightness(this.getContentResolver()));
      // Log.e("執(zhí)行車友的拿手機的動作", riderSpeed + "");
      // // pm.goToSleep(SystemClock.uptimeMillis());
      // new Handler().postDelayed(new Runnable() {
      //
      // @Override
      // public void run() {
      //
      // wake.release();
      //
      // }
      // }, 50);// 在釋放的時候異常了
      // }

      下一篇: PLC、DCS、FCS三大控

      上一篇: 電氣控制線路圖控制原

      推薦產(chǎn)品

      更多
      主站蜘蛛池模板: 日韩最新视频一区二区三| 亚洲av无码一区二区三区人妖| 亚洲一区二区三区乱码在线欧洲| 国产精品视频一区国模私拍| 国产AV一区二区三区无码野战| 亚洲国产精品一区二区第一页免| 国产成人欧美一区二区三区| 色窝窝无码一区二区三区色欲 | 日韩一区二区三区在线精品| 在线播放国产一区二区三区 | 久久中文字幕无码一区二区| 色偷偷久久一区二区三区| 区三区激情福利综合中文字幕在线一区| 久久精品日韩一区国产二区| 亚洲一区动漫卡通在线播放| 精品欧洲av无码一区二区14| 久久国产视频一区| 国产无套精品一区二区| 超清无码一区二区三区| 中文字幕在线观看一区| 成人区精品人妻一区二区不卡| 乱人伦一区二区三区| 国产成人精品久久一区二区三区av| 天美传媒一区二区三区| 在线不卡一区二区三区日韩| 美日韩一区二区三区| 国产一区二区在线观看视频| 一区二区三区在线播放视频| 免费观看一区二区三区| 高清一区二区三区日本久| 亚洲AV无码第一区二区三区| 色窝窝无码一区二区三区色欲| 日本内射精品一区二区视频| 69久久精品无码一区二区| 免费看无码自慰一区二区| 一区二区三区四区在线播放| 伊人久久精品无码av一区| 日韩精品一区二区三区色欲AV| 亚洲一区二区无码偷拍| 国产一区二区三区露脸| 国产一区二区三区不卡AV|