Pages

2011年11月15日 星期二

Intent Sample

        在同一個 package 中,利用 Intent 啟動另一個 Activity,並透過 Bundle 物件帶參數給他 (下面的例子是送一個字串給接收端的 TextView) ##ReadMore##

<<發送端>>
Intent intent = new Intent();
intent.setClass(this, IntentReceiving.class);

Bundle bundle = new Bundle();
bundle.putString("Receive", "Intent Receiving");  // (Key - Value)
intent.putExtras(bundle);      

startActivity(intent);

<<接收端>>
CharSequence cs;
Bundle bundle = this.getIntent().getExtras();
cs = bundle.getString("Receive");
textview.setText(cs);

        也可以不透過 Bundle,直接 intent.setString() 或 intent.setInt()。另外,在宣告 IntentFilter 時,除了在 AndroidManifest.xml 中定義;也可直接在程式碼中描述。

參考資料

System Resource

        在 framework/base/core/res 有許多已經定義好的資源可以使用,但自己寫得應用程式,通常還是在自己的 res/。##ReadMore##

        假設現在我要讓 Settings->Display->Brightness 的 Preference Dialog 出現 Auto Brightness 的 checkbox 和 text。只要在 framework/base/core/res/res/values/config.xml 做修改:
<bool name="config_automatic_brightness_available">false</bool>

        這樣一來,這個 checkbox 和 text 就跑出來了。至於說,為甚麼這樣就會出現,是因為在 BrightnessPreference.java 在建構函式讀取這個變數值,來決定這個 UI 要不要秀出來。
mAutomaticAvailable = context.getResources().getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);

Thread & Handler

   如果在某個 Activity/Service/Class 中使用執行緒,然後,需透過該執行緒來變更/通知某個事件,就可以使用 Handler。##ReadMore##
private static final int LIGHTSENSOR_LUX = 0x101;   // 自訂常數

Thread t = new Thread() {
    public void run() {
        while (true) {
            int getLuxValue = 0;

            Message msg = new Message();
            msg.what = LIGHTSENSOR_LUX;
            msg.arg1 = getLuxValue;
            handler.sendMessage(msg); 

            try {   
               Thread.sleep(500);    
            } catch (InterruptedException e) {   
               Thread.currentThread().interrupt();   
            }
        }
    }
};
t.start();

private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {   
        case LIGHTSENSOR_LUX:
            Log.e("Test", "Lux Value = "+msg.arg1);
            break; 
    }   
    super.handleMessage(msg);
}

   Message 提供三個公開變數可以傳資料:arg1、arg2 是傳整數,obj 是傳 object type 資料;還有 setData(Bundle) 可以使用,但還沒用過。

參考網址

  • 利用 Handler 來更新 Android UI .. (Link)
  • Andorid Developer Messge .. (Link)
  • Andorid Developer Handler .. (Link)
  • Why isn't the thread stopping .. (Link)
  • 背景執行服務(Service) .. (Link)

2011年11月10日 星期四

[Froyo] Airplane Mode

        Airplane Mode 開啟就會斷掉所有通訊 (BT、WiFi、3G)。在 Android 上,這個功能要能夠正常運作,必須有 3G module。過程如下:

2011年10月11日 星期二

沙漠傳奇

好酸阿XDD!出處 ##ReadMore##

一位高級經理人在沙漠中一間廢棄的豪宅裡撿到一只神燈。

高級經理人擦了擦這只神燈,果不其然神燈精靈跑了出來。

「尊敬的顧客您好……」

「疑?不是主人嗎?」

「因為時代變遷,我們的招呼語也改版囉。」

「那,我要三個願望。」高級經理人說。

「呃,雖然很難為情,但是因為通貨膨脹,我只能給您一個願望……」

「好吧。我要一個 app。」

「啊?」

「就 app 啊,現在很流行的,手機上的,app。」

「您想要什麼樣的 app?」

「我不管,就是給我一個 app,能夠讓我看影片、按讚、買東西、賣東西、交朋友、分享檔案,還有還有,要有雲端運算,總之要賺很多錢。」

「這好像是好幾個不同的願望……」

「沒有吧,我就只是要一個 app。」

「那,尊敬的顧客,您是要多媒體 app 呢、互動遊戲 app 呢、小工具 app 呢、理財型 app 呢、資訊型 app 呢、地圖定位 app 呢,還是哪一個類型的 app?」

「奇怪了,我只是想要一個 app ,你哪來那麼多鬼扯問題。」

「App 都有分類的啊,我也得依著您的需求,才能變出您想要的 app。」

「什麼需求?我就是要『一個』app,我要賺很多很多錢,有很多很多使用者,還要在每一隻手機上都有。」

「呃,這樣有一點困難,再說,就我的理解,不同的手機的 app 並不能算同一個……」

「你覺得我要懂這麼多嗎?」

「只是想更了解您的需求……」

「需求?需求!都已經只給我一個願望了,還問我有什麼需求?我、要、一、個、a-p-p,你要我拼給你聽嗎?」

「不用,不用。那這樣好不好,我給您一個優待,在我完成這個願望之前,我先變給您一位需求分析師、一位視覺設計、一位網站設計師、一位後台工程師、 一位 iPhone — 或是您要 Android 也行 — 軟體工程師、一位行銷人員、一位客服人員,您要做的事情很簡單,就是跟他們一起商討您要做的是什麼 app,要有哪些功能、要有什麼使用者介面、要怎麼上架、要怎麼升級改版,所有人的食宿都由我負擔,您只需要花時間想清楚就好了,啊對了,除此之外,我還 可以給您一位多國語言文案、一位 icon designer、一位……」

「滾!給我滾!你給我聽好了,我是高級經理人,我沒有那麼多時間聽你鬼扯這麼多,這世界上便宜又聰明的人呼之即來,我才不要跟你講的什麼鬼設計什麼 工程師的浪費我的唇舌!你們什麼神燈精靈的都是騙子!我的願望這麼簡單,哪有什麼做不到的道理!你們以後也別出來混了,問東問西鬼扯蛋,哪來這麼多問題 啊!!!」

「這個願望我做得到。謝謝您的使用,今天很高興為您服務,再……」

高級經理人作勢揮拳,精靈還沒講完,就倏地一聲消失了。


連結

2011年7月25日 星期一

偵測有線耳機的插拔

這個功能也是 UEvent 的應用,繼承 UEventObserver,並且實作 onUEvent callback function,參考這份文件,有挺完整的介紹。不過,有幾點需要注意:##ReadMore##
  • 實作的類別改名為 WiredAccessoryObserver,這代表著,它會偵測不同的有線配件,如:耳機、HDMI。
  • 在 boot complete 之後,先到 /sys 底下去讀取耳機起始狀態,然後,開始監督 DEVPATH 這個子字串。

  原本是叫做 HeadsetObserver,看了 Android 3.1 mr2,發現已經被整合在一起。不過架構是不變的,如果偵測到插拔的動作,就會發 intent 通知 Audio Service。

  之前有發現,系統進入 suspend 之後,再去做插拔的動作,然後 resume,系統並不知道有做這個動作,原因是,kernel module 並沒有實作 resume 的函式,只要補上去就可以啦!

2011年5月20日 星期五

Battery Power Update

這是 UEvent 的應用之一,底層會定期送 battery information 給 Android,而上層負責處理的是 Battery Service。

路徑
   framework/base/services/java/com/android/server/BatteryService.java
說明
  • BatteryService 會註冊一個 UEventObserver,用來觀察是否有符合 SUBSYSTEM=power_supply 子字串的 uevent 發上來,假如有,就會觸發 onUEvent。
    mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply");
  • 當 onUEvent 觸發,會做兩件事,第一,呼叫 update,這個函式會叫用 JNI native_update,去 /sys 底下讀取 battery information,並利用 setIntField、setBooleanField 等函式,設定給 battery service。

  • 在 update 結束後,執行 processValues,處理從底下得到的數值,接著,發 ACTION_BATTERY_CHANGED Intent 給 SystemUI[註] ,更新電量資訊、圖示,如果電量過低,還會發 alert dialog。
  UEvent 是定期發出來,即使電量不變也會收到。另外,在 SystemUI[註] 會用到 framework/base/core/res/res/values/string.xml 和 configs.xml 定義的數值。例如:alert message、battery criteria 等等。

[註] Froyo 是由 StatusBarPolicy 處理 ACTION_BATTERY_CHANGED
參考資料


2011年5月18日 星期三

UEvent Simple Introduction

Android 有蠻多服務透過收 UEvent 的方式,取得從底層送上來的訊息,例如:Rotation、Battery、StatusBar 等等,可以在 framework/base/service 看到這些足跡。那麼,它的 code flow 是怎麼跑的,底下咱們來瞧一瞧。

Java Framework
路徑:
framework/base/core/java/android/os/UEventObserver.java
說明:
abstract class UEventObserver
  • UEventObserver 為系統監控是否有 uevent 從 kernel 發出來,它是一個抽象類別,程式設計師可以去繼承它,並且實作
    abstract void onUEvent(UEvent event);
  • 呼叫 startObserving,就會把需要觀察的裝置路徑,儲存在列表中(路徑長得像:"DEVPATH=/devices/...." or "SUBSYSTEM=..."),以便之後和 uevent 字串比對用。
  • 因為 UEventObserver 的運作是透過執行緒不斷地去讀取,所以第二步的 startObserving 就會去檢查執行緒起動了沒。另外,這一條執行緒是系統中僅有的一條執行緒,會透過以下變數判斷執行緒是不是已經生成。
    static boolean sThreadStarted
  • 若執行緒讀到的 uevent 字串,經比對後符合列表中的裝置路徑,就會觸發 onUEvent 這個函式。
class UEvent
  • UEvent 這個類別提供一個 HashMap 資料結構,會把透過 socket 收到的 uevent 字串做拆解,把「=」前當成 key、「=」後當成 value,以便 onUEvent 函式需要的時候使用。uevent 的長相如下:(怪怪的字元應該是結束字元)
    change@/devices/platform/tegra_i2c.1/i2c-1/1-0058/power_supply/battery�� ACTION=change�� DEVPATH=/devices/platform/tegra_i2c.1/i2c-1/1-0058/power_supply/battery�� SUBSYSTEM=power_supply�� POWER_SUPPLY_NAME=battery�� POWER_SUPPLY_TYPE=Battery�� POWER_SUPPLY_STATUS=Unknown��POWER_SUPPLY_HEALTH=Good�� POWER_SUPPLY_PRESENT=0�� POWER_SUPPLY_TECHNOLOGY=Li-ion��POWER_SUPPLY_VOLTAGE_NOW=0�� POWER_SUPPLY_CAPACITY=0�� POWER_SUPPLY_TEMP=-2731�� SEQNUM=721��

private static native void native_setup();
private static native int next_event(byte[] buffer);
  • 這兩個是叫用 JNI 介面,第一個用來做是初始化;第二個是用來讀取 uevent,都在 UEventThread.run() 中使用。


JNI
路徑:
framework/base/core/jni/android_os_UEventObserver.cpp
說明:
android_os_UEventObserver_native_setup
  • 這就是 UEventObserver.java 的 native_setup 所對應的 JNI 接口,這個函式會呼叫 HAL 中的 uevent_init。
android_os_UEventObserver_next_event
  • 這就是 UEventObserver.java 的 next_event 所對應的 JNI 接口,這個函式會呼叫 HAL 中的 uevent_next_event。


HAL(hardware)
路徑:
hardware/libhardware_legacy/uevent/uevent.c
     hardware/libhardware_legacy/include/hardware_legacy/uevent.h
說明:
uevent_init()
  • 這個函式會建立 AF_NETLINK 類型的 socket,然後 bind。

uevent_next_event(char* buffer, int buffer_length)
  • 利用 poll 的方式,對這個 socket fd 作輪詢,如果有資料,就用 recv 去接收,並放在 buffer。poll 的 timeout 等於 -1,代表「Infinitely」。


備註

  • Driver 必須要發出 uevent,語法是 kobject_uevent(&kobj, KOBJ_CHANGE),KOBJ_CHANGE 也可以是 KOBJ_ADD、KOBJ_REMOVE。

參考資料

2011年5月6日 星期五

config.gz

想了解 kernel config 的設定,可以在開機進入系統後,利用 adb tool 輸入以下指令:##ReadMore##
./adb pull /proc/config.gz

  解壓縮這個檔案,就可以得知 kernel configuration。例如:我想要把 VPN enable,Android OS 的部分已經完成,只須將底層設置打開,這時候就可以把 Nexus One 的 config.gz 拿出來比較一下。不過,想在開機後看到這個檔案,必須在編譯核心時,把 CONFIG_IKCONFIG_PROC=y 才能看到。

[Froyo] Sensor Notes

  我所實作的部分是 light sensor,因為它比較單純,至於其他類型的感測器,有各自的 know how 需要了解,所以這裡就不討論。<參考>

  Sensor HAL 的標頭檔位於 hardware/libhardware/include/hardware/sensors.h,有一個結構 sensor_module_t,它繼承自 hardware_module_t,這個結構是在 hardware.h。sensor_module_t 的變數宣告已在 hardware.h 規定成「HAL_MODULE_INFO_SYM」,這裡頭會定義一個 open 的函式指標,用來初始化 sensor_data_device_t 和 sensor_control_device_t。
const struct sensors_module_t HAL_MODULE_INFO_SYM
結構 sensor_data_device_t 定義裝置的 open、close、poll,這些東西會在 SensorManager 叫用;sensor_control_device_t 定義裝置的 activate、delay、wake,這些東西會在 SensorService 叫用。

  同一種類型的感測器可能多個,所以是一個 list,不過現在 Froyo 是直接回傳串列的第一個。如果有些函式在底層沒有實作,那 HAL 會直接 return,像 poll function 在 light sensor driver 就沒有實作。所以想要讀 light sensor 的值,只能被動地一直去讀 /sys 下的節點。

  /sys 下的檔案是一般類型的檔案,所以 read 之後,需要做 lseek(fd, 0, SEEK_SET); 移回開頭,否則會讀不到東西,第二個參數是指移動多少 byte。另外, lseek(int fildes,0,SEEK_END) 移動到結尾;lseek(int fildes,0,SEEK_CUR) 移動到目前位置 .. <參考>。

  PowerManagerService 有處理 proximate sensor 和 light sensor,針對 light sensor 的部分,它會去檢查 framework/base/core/res/res/values/config.xml 的 config_automatic_brightness_available 設定值,如果為 true,它就認為有 light sensor 存在,就會嘗試跟 SensorManager 註冊,並處理 auto brightness 的內容。不過,目前 HAL 吐上來的數值範圍 落在 [10,1000],如果給這個 service 處理會發生問題,需要做轉換。

  當系統發生出 ACTION_BOOT_COMPLETED,就去啟動 sensor service,這部分實作 sensor initialization & event callback function。

  假設把 source code 放在 hardware/libhardware 底下,需要將 hardware/libhardware/Android.mk 做以下修改,才能在 clean build 編譯到 sensor 的部分。

   include $(addsuffix /Android.mk, $(addprefix $(LOCAL_PATH)/, \
     modules/gralloc \
     modules/sensors \
   ))

  HAL library 名稱有其規則,可以是 sensors.tegra 或者 sensors.default。另外,sensor library 會呼叫 hw_get_module load() -> dlsym 載入 library。

  /* This goes first so that it can pick up a different file on the emulator. */
  "ro.hardware",
  "ro.product.board",
  "ro.board.platform",
  "ro.arch"

 
Blogger Templates