Android Application Building Flow
embedded linux ,android
2010年11月9日 星期二
2010年11月3日 星期三
Intent 與 intent-filter
AndroidManifest.xml 向 framework 登記此AP,包含哪些activity,service等,所以android接獲intent時,就有資訊可以解析哪個應用程式最符合這個intent。
Intent 可以啟動activity,service,broadcast receiver,intent 可以指定action跟data,action是指要做什麼樣的事,例如打電話或編輯文章,data則是指此action boundle在一起的資料內容,以URI格式表示。
Intent分成兩種,implicit intent與explicit intent,明確的intent表示指定要啟動的activity,而implicit intent,則是透過設定intent-filter讓系統有能力解析最適合的activity或service等,intent要由哪個應用程式接收,有三種比對的filter,分別是<action>,<category>,<data>。,而implicit intent自動加入CATEGORY_DEFAULT,如果intent-filter中沒有android.intent.category
.DEFAULT,則match就會失敗,所以要讓activity或service接收implicit intent就必須要加入android.intent.category.DEFAULT。
intent-filter 可以被包在 activity,service,receiver中
網路上收集的intent範例(轉自http://ysl-paradise.blogspot.com/2008/12/intent.html)
顯示網頁
Intent 可以啟動activity,service,broadcast receiver,intent 可以指定action跟data,action是指要做什麼樣的事,例如打電話或編輯文章,data則是指此action boundle在一起的資料內容,以URI格式表示。
Intent分成兩種,implicit intent與explicit intent,明確的intent表示指定要啟動的activity,而implicit intent,則是透過設定intent-filter讓系統有能力解析最適合的activity或service等,intent要由哪個應用程式接收,有三種比對的filter,分別是<action>,<category>,<data>。,而implicit intent自動加入CATEGORY_DEFAULT,如果intent-filter中沒有android.intent.category
.DEFAULT,則match就會失敗,所以要讓activity或service接收implicit intent就必須要加入android.intent.category.DEFAULT。
intent-filter 可以被包在 activity,service,receiver中
<intent-filter android:icon="drawable resource"
android:label="string resource"
android:priority="integer">
<action android:name="string" />
//可以有很多action,只要其中一項符合即可,如果intent filter
//沒有指定action,這此AP永不被執行,若intent沒有指定action
//,則任何app的action filter皆符合此intent
<category android:name="string" />
//若intent有設定Category,必須intent的每項category都通過filter設定
//的Category,若intent沒有設定Category,則都符合此intent
<data android:name="string" />
//1.當filter內沒有設定任何data tag,而intent內也沒有設定URI與data type,
//那這test就通過
//2.當filter有設定URI,沒有設定data type,而intent object也是只有URI沒有
//data type,這時候通過,這通常只會發生在mailto: 與tel: 時
//3.當filter內只有設定data type 沒有設定URI,而intent object有設定相同
//的data type無URI則通過
//4.當filter內設定的data type與URI都與intent Object內設定的對應即通過
//若filter內只有設定data type而URI不設定,只有在intent Object內的
//data type有對應,而URI為content: 或file:才會通過
</intent-filter>
intent機制的好處是,要擴充功能只要發出intent,android就會去找最適合的應用程式,不需要在自己的應用程式裡加code。網路上收集的intent範例(轉自http://ysl-paradise.blogspot.com/2008/12/intent.html)
顯示網頁
Uri uri = Uri.parse("http://google.com");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
顯示地圖
Uri uri = Uri.parse("geo:38.899533,-77.036476");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//其他 geo URI 範例
//geo:latitude,longitude
//geo:latitude,longitude?z=zoom
//geo:0,0?q=my+street+address
//geo:0,0?q=business+near+city
//google.streetview:cbll=lat,lng&cbp=1,yaw,,pitch,zoom&mz=mapZoom
路徑規劃
Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//where startLat, startLng, endLat, endLng are a long with 6 decimals like: 50.123456
撥打電話
//叫出撥號程式
Uri uri = Uri.parse("tel:0800000123");
Intent it = new Intent(Intent.ACTION_DIAL, uri);
startActivity(it);
//直接打電話出去
Uri uri = Uri.parse("tel:0800000123");
Intent it = new Intent(Intent.ACTION_CALL, uri);
startActivity(it);
//用這個,要在 AndroidManifest.xml 中,加上
//
傳送 SMS/MMS
//叫起簡訊程式
Intent it = new Intent(Intent.ACTION_VIEW);
it.putExtra("sms_body", "The SMS text");
it.setType("vnd.android-dir/mms-sms");
startActivity(it);
//傳送簡訊
Uri uri = Uri.parse("smsto:0800000123");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
it.putExtra("sms_body", "The SMS text");
startActivity(it);
//傳送 MMS
Uri uri = Uri.parse("content://media/external/images/media/23");
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra("sms_body", "some text");
it.putExtra(Intent.EXTRA_STREAM, uri);
it.setType("image/png");
startActivity(it);
//如果是 HTC Sense 手機,你要用
Intent sendIntent = new Intent("android.intent.action.SEND_MSG");
sendIntent.putExtra("address", toText);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, "subject");
sendIntent.putExtra("sms_body", textMessage);
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(url));
sendIntent.setType("image/jpeg");
startActivity(sendIntent);
//底下這段更好,可在所有手機上用
//refer to http://stackoverflow.com/questions/2165516/sending-mms-into-different-android-devices
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mmsto:");
intent.putExtra("address", );
intent.putExtra("subject", );
startActivity(intent);
傳送 Email
Uri uri = Uri.parse("mailto:xxx@abc.com");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(it);
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");
it.putExtra(Intent.EXTRA_TEXT, "The email body text");
it.setType("text/plain");
startActivity(Intent.createChooser(it, "Choose Email Client"));
Intent it=new Intent(Intent.ACTION_SEND);
String[] tos={"me@abc.com"};
String[] ccs={"you@abc.com"};
it.putExtra(Intent.EXTRA_EMAIL, tos);
it.putExtra(Intent.EXTRA_CC, ccs);
it.putExtra(Intent.EXTRA_TEXT, "The email body text");
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.setType("message/rfc822");
startActivity(Intent.createChooser(it, "Choose Email Client"));
//傳送影音附件檔
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///sdcard/mysong.mp3"));
it.setType("audio/mp3");
startActivity(Intent.createChooser(it, "Choose Email Client"));
//傳送圖片附件檔
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///sdcard/mypic.jpg"));
it.setType("image/jpeg");
startActivity(Intent.createChooser(it, "Choose Email Client"));
顯示聯絡人清單
Intent it = new Intent(Intent.ACTION_VIEW, People.CONTENT_URI); startActivity(it);顯示某個朋友的詳細資料
Uri uriPerson = ContentUris.withAppendedId(People.CONTENT_URI, 5); //5 是朋友的 ID Intent it = new Intent(Intent.ACTION_VIEW, uriPerson); startActivity(it);播放多媒體
Intent it = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/song.mp3");
it.setDataAndType(uri, "audio/mp3");
startActivity(it);
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
從圖庫中回傳選到的圖片
Intent it = new Intent(Intent.ACTION_GET_CONTENT);
it.addCategory(Intent.CATEGORY_OPENABLE);
it.setType("image/*");
startActivityForResult(it, 0);
//回傳的圖片可透過 it.getData() 取得圖片之 Uri
啟動照相機,並將相片存在指定的檔案中
Intent it = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //假設你要將相片存在 /sdcard/xxx.jpg 中 File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/xxx.jpg"); it.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f)); startActivity(it, 0);Market 相關
//尋找某個應用程式
Uri uri = Uri.parse("market://search?q=pname:pkg_name");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//where pkg_name is the full package path for an application
//顯示某應用程式詳細畫面
Uri uri = Uri.parse("market://details?id=pkg_name_or_app_id");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//where app_id is the application ID, find the ID
//by clicking on your application on Market home
//page, and notice the ID from the address bar
Uninstall 應用程式
Uri uri = Uri.fromParts("package", strPackageName, null);
Intent it = new Intent(Intent.ACTION_DELETE, uri);
startActivity(it);
安裝 APK 檔
Uri uri = Uri.parse("url_of_apk_file");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
it.setData(uri);
it.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
it.setClassName("com.android.packageinstaller",
"com.android.packageinstaller.PackageInstallerActivity");
startActivity(it);
//make sure the url_of_apk_file is readable for all users
推薦書單<入手>
已購入
1. 嵌入式系統韌體揭密
2. 嵌入式系統—使用 C 和 GNU 開發工具 第二版
3. 嵌入式系統入門
4. 作業系統導論 第二版
5. Embedded Linux 開發實務徹底研究
6. 現代嵌入式系統專案實務
7. 建構嵌入式 Linux 系統 第二版
8. 编码:隐匿在计算机软硬件背后的语言
9. 系统程序员成长计划
10. 嵌入式Linux内存使用与性能优化
1. 嵌入式系統韌體揭密
2. 嵌入式系統—使用 C 和 GNU 開發工具 第二版
3. 嵌入式系統入門
4. 作業系統導論 第二版
5. Embedded Linux 開發實務徹底研究
6. 現代嵌入式系統專案實務
7. 建構嵌入式 Linux 系統 第二版
8. 编码:隐匿在计算机软硬件背后的语言
9. 系统程序员成长计划
10. 嵌入式Linux内存使用与性能优化
2010年11月2日 星期二
Dma6410XP開發環境架設
Install Fedora 8
1. 複製SDK與書本光碟內容到NB
2. 利用VMware安裝Fedora8
3. 看DMA-6410XP_CE6.0&Android2.1_100818.pdf
4. 安裝vmware tool ( 語系轉成英文 )
http://life.iiietc.ncu.edu.tw/xms/content/show.php?id=16092
擴充vmware空間 vmware-vdiskmamager.exe -x 100Gb "D:/xxx.vmdk"
Cross Compiler for uboot and kernel
5. mkdir /usr/local/arm
6. tar -jxvf 4.3.1-eabi-armv6-20080707.tar.bz2 -C /usr/local/arm
install 2.1 SDK
1. 複製SDK與書本光碟內容到NB
2. 利用VMware安裝Fedora8
3. 看DMA-6410XP_CE6.0&Android2.1_100818.pdf
4. 安裝vmware tool ( 語系轉成英文 )
http://life.iiietc.ncu.edu.tw/xms/content/show.php?id=16092
擴充vmware空間 vmware-vdiskmamager.exe -x 100Gb "D:/xxx.vmdk"
Cross Compiler for uboot and kernel
5. mkdir /usr/local/arm
6. tar -jxvf 4.3.1-eabi-armv6-20080707.tar.bz2 -C /usr/local/arm
7. vim ~/.bashrc
8. export PATH=/usr/local/arm/4.3.1-eabi-armv6/usr/bin:$PATH
9. . ~/.bashrc
build kernel
10. cp dma6410xp-linux-2.6.29_101010.tar.bz2 ~
11. cd ~
12. tar -jxvf dma6410xp-linux-2.6.29_101010.tar.bz2
13. cd dma6410xp-linux-2.6.29
14. make clean
15. make smdk6410_android_128M_defconfig
16. make zImage
build uboot
22-1. yum install gperf
22-2 CD install libsdl-dev
build Android
23. mkdir ~/sdk
24. cd sdk
25. cp jdk-6u14-linux-i586.bin .
26. chmod u+x jdk-6u14-linux-i586.bin
27. ./jdk-6u14-linux-i586.bin
22. vim ~/.bashrc
22. export JAVA_HOME=/root/Android6410/sdk/jdk1.6.0_14
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/bin:$JAVA_HOME:/jre/bin:$PATH:$HOME/bin
23. cp dma6410XP_android2.1_source_100920.tar.bz2 ~
24. tar -jxf dma6410XP_android2.1_source_100920.tar.bz2
25. cd android_source
26. source ./build_android_env
27. ./build_android.sh
燒image
10. cp dma6410xp-linux-2.6.29_101010.tar.bz2 ~
11. cd ~
12. tar -jxvf dma6410xp-linux-2.6.29_101010.tar.bz2
13. cd dma6410xp-linux-2.6.29
14. make clean
15. make smdk6410_android_128M_defconfig
16. make zImage
build uboot
17. cp dma6410-u-boot-1.1.6_100913.tar.bz2 ~
18. cd ~
19. tar -jxvf dma6410-u-boot-1.1.6_100913.tar.bz2
20. cd dma6410-u-boot-1.1.6
21. make smdk6410_config
22. make
22-2 CD install libsdl-dev
build Android
23. mkdir ~/sdk
24. cd sdk
25. cp jdk-6u14-linux-i586.bin .
26. chmod u+x jdk-6u14-linux-i586.bin
27. ./jdk-6u14-linux-i586.bin
22. vim ~/.bashrc
22. export JAVA_HOME=/root/Android6410/sdk/jdk1.6.0_14
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/bin:$JAVA_HOME:/jre/bin:$PATH:$HOME/bin
23. cp dma6410XP_android2.1_source_100920.tar.bz2 ~
24. tar -jxf dma6410XP_android2.1_source_100920.tar.bz2
25. cd android_source
26. source ./build_android_env
27. ./build_android.sh
燒image
install 2.1 SDK
Android SDK Tools使用
這邊文章介紹幾個SDK tools
1. emulator
2. mksdcard
3. adb
4. DDMS
1. emulator
2. mksdcard
3. adb
4. DDMS
[root@localhost ~]# cd /home/online/android-sdk-linux_x86-1.6_r1/tools/
[root@localhost tools]#
[root@localhost tools]# ls
adb dmtracedump hprof-conv source.properties
android draw9patch lib sqlite3
apkbuilder emulator mksdcard traceview
ddms hierarchyviewer NOTICE.txt zipalign
[root@localhost tools]# ./android list target
Available Android targets:
id: 1
Name: Android 1.5
Type: Platform
API level: 3
Revision: 1
Skins: QVGA-P, HVGA (default), HVGA-L, HVGA-P, QVGA-L
id: 2
Name: Android 1.6
Type: Platform
API level: 4
Revision: 1
Skins: HVGA (default), QVGA, WVGA800, WVGA854
id: 3
Name: Google APIs
Type: Add-On
Vendor: Google Inc.
Revision: 3
Description: Android + Google APIs
Based on Android 1.5 (API level 3)
Libraries:
* com.google.android.maps (maps.jar)
API for Google Maps
Skins: QVGA-P, HVGA-L, HVGA (default), QVGA-L, HVGA-P
id: 4
Name: Google APIs
Type: Add-On
Vendor: Google Inc.
Revision: 1
Description: Android + Google APIs
Based on Android 1.6 (API level 4)
Libraries:
* com.google.android.maps (maps.jar)
API for Google Maps
Skins: WVGA854, HVGA (default), WVGA800, QVGA
[root@localhost tools]# ./android create avd --target 2 --name myavd
Android 1.6 is a basic Android platform.
Do you wish to create a custom hardware profile [no]
Created AVD 'myavd' based on Android 1.6, with the following hardware config:
hw.lcd.density=160
[root@localhost tools]# mksdcard 512M mycard
[root@localhost tools]# ./emulator -avd myavd -skin HVGA -sdcard mycard &
[1] 4446
[root@localhost tools]# emulator: warning: opening audio output failed
[root@localhost tools]# ./android list avd
Available Android Virtual Devices:
Name: sdk_1_6
Path: /root/.android/avd/sdk_1_6.avd
Target: Android 1.6 (API level 4)
Skin: HVGA
Sdcard: 32M
---------
Name: avd16
Path: /root/.android/avd/avd16.avd
Target: Android 1.6 (API level 4)
Skin: HVGA
---------
Name: myavd
Path: /root/.android/avd/myavd.avd
Target: Android 1.6 (API level 4)
Skin: HVGA
[root@localhost tools]# adb devices
List of devices attached
emulator-5554 device
[root@localhost tools]# adb get-state
device
[root@localhost tools]# adb get-serialno
emulator-5554
[root@localhost tools]# #adb -s emulator-5554 install xxx.apk
[root@localhost tools]# #adb -s emulator-5554 uninstall com.example.xxx.xxx.apk
[root@localhost tools]# #adb shell
[root@localhost tools]# #adb pull <remote> <local>
[root@localhost tools]# #adb push <local> <remote>
[root@localhost tools]# #adb logcat
[root@localhost tools]# #adb bugreport
[root@localhost tools]#
DDMS2010年10月31日 星期日
以Android HAL 方式擴充 Framework
這邊詳細說明 Jollen Mokoid 專案如何擴充新硬體。
首先給出整個架構,可以看到由上而下分成,
應用程式層 LedTest.apk
框架層 mokioid.jar
--實作 Manager ( 透過 aidl 溝通 )
--實作 Service
JNI 層 libmokoid_runtime.so
HAL 層 led.goldfish.so
dma6410xp 新產品分支設定
AndroidProduct.mk
首先給出整個架構,可以看到由上而下分成,
應用程式層 LedTest.apk
框架層 mokioid.jar
--實作 Manager ( 透過 aidl 溝通 )
--實作 Service
JNI 層 libmokoid_runtime.so
HAL 層 led.goldfish.so
[root@localhost mokoid]# tree
.
|-- Android.mk
|-- apps //應用程式層 LedTest.apk
| |-- Android.mk
| `-- LedTest
| |-- Android.mk
| |-- AndroidManifest.xml
| `-- src
| `-- com
| `-- mokoid
| `-- LedTest
| |-- LedSystemServer.java
| `-- LedTest.java
|-- dma6410xp //新產品分支設定
| |-- AndroidBoard.mk //一般keypad設定在這檔案
| |-- AndroidProducts.mk //andoird building system
//會自動去找這各檔案
| |-- BoardConfig.mk //一些board feature例如driver
| |-- dma6410xp.mk
|-- frameworks //框架層 mokioid.jar
| |-- Android.mk
| `-- base
| |-- Android.mk
| |-- core
| | `-- java //Manager層
| | `-- mokoid
| | `-- hardware
| | |-- ILedService.aidl
| | `-- LedManager.java
| `-- service
| |-- Android.mk
| |-- com.mokoid.server.xml
| |-- java //Service層
| | `-- com
| | `-- mokoid
| | `-- server
| | `-- LedService.java
| `-- jni //JNI層 libmokoid_runtime.so
| |-- Android.mk
| `-- com_mokoid_server_LedService.cpp
`-- hardware //硬體抽象層 led.goldfish.so
|-- Android.mk
`-- modules
|-- Android.mk
|-- include
| `-- mokoid
| `-- led.h
`-- led
|-- Android.mk
`-- led.c
26 directories, 35 files
[root@localhost mokoid]#
dma6410xp 新產品分支設定
AndroidProduct.mk
PRODUCT_MAKEFILES := \ $(LOCAL_DIR)/dma6410xp.mkDma6410xp.mk
// 繼承generic.mk的設定 包含標準的應用程式等
$(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk)
// 將新增的應用程式加入image中
PRODUCT_PACKAGES += \
LedTest
// 將此檔案複製到正確的路徑
PRODUCT_COPY_FILES := \
vendor/mokoid/frameworks/base/service/com.mokoid.server.xml:
system/etc/permissions/com.mokoid.server.xml
// 設定name 可用 make PRODUCT-dma6410xp-eng 來編譯image
PRODUCT_NAME := dma6410xp
PRODUCT_DEVICE := dma6410xp
AndroidBoard.mk
LOCAL_PATH := $(call my-dir) ifeq ($(TARGET_PREBUILT_KERNEL),) TARGET_PREBUILT_KERNEL := $(LOCAL_PATH)/kernel endif
BoardConfig.mk
hardware 硬體抽象層
android.mk
TARGET_CPU_ABI := armeabi BOARD_USES_GENERIC_AUDIO := true USE_CAMERA_STUB := true TARGET_NO_KERNEL := true
hardware 硬體抽象層
android.mk
//目前路徑 LOCAL_PATH := $(call my-dir) //清除local變數 include $(CLEAR_VARS) // c header file路徑 LOCAL_C_INCLUDES += \ vendor/mokoid/hardware/modules/include/ LOCAL_PRELINK_MODULE := false // 編譯完的so放在system/lib/hw下 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := led.c // 模組名稱 LOCAL_MODULE := led.goldfish // 編譯成.so include $(BUILD_SHARED_LIBRARY)
led.h
#include <hardware/hardware.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
/***************************************************************************/
// 繼承 struct hw_module_t
struct led_module_t {
struct hw_module_t common;
};
// 繼承 struct hw_module_t
struct led_control_device_t {
struct hw_device_t common;
/* open device node 返回的 fd */
int fd;
/* callback function 指向 led_on led_off 實作 */
int (*set_on)(struct led_control_device_t *dev, int32_t led);
int (*set_off)(struct led_control_device_t *dev, int32_t led);
};
/***************************************************************************/
struct led_control_context_t {
struct led_control_device_t device;
};
#define LED_HARDWARE_MODULE_ID "led"
led.c
android.mk
#define LOG_TAG "MokoidLedStub"
#include <hardware/hardware.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <mokoid/led.h>
/**
* Definition of kernel-space driver.
*/
#define LED_DEVICE "/dev/led"
#define LED_C608 1
#define LED_C609 2
static int led_device_close(struct hw_device_t* device)
{
struct led_control_device_t* ctx =
(struct led_control_device_t*)device;
if (ctx) {
close(ctx->fd);
free(ctx);
}
return 0;
}
static int led_on(struct led_control_device_t *dev, int32_t led)
{
int fd;
LOGI("LED Stub: set %d on.", led);
fd = dev->fd;
switch (led) {
case LED_C608:
ioctl(fd, 1, &led);
break;
case LED_C609:
ioctl(fd, 1, &led);
break;
default:
return -1;
}
return 0;
}
static int led_off(struct led_control_device_t *dev, int32_t led)
{
int fd;
LOGI("LED Stub: set %d off.", led);
fd = dev->fd;
switch (led) {
case LED_C608:
ioctl(fd, 2, &led);
break;
case LED_C609:
ioctl(fd, 2, &led);
break;
default:
return -1;
}
return 0;
}
static int led_device_open(const struct hw_module_t* module,
const char* name,
struct hw_device_t** device)
{
struct led_control_device_t *dev;
dev = (struct led_control_device_t *)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
//初始化 led_control_device_t
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = module;
dev->common.close = led_device_close;
//設定實作函數指標
dev->set_on = led_on;
dev->set_off = led_off;
*device = &dev->common;
//open led device node
dev->fd = open(LED_DEVICE, O_RDONLY);
if (dev->fd < 0)
dev->fd = 2; /* Error Handler */
led_off(dev, LED_C608);
led_off(dev, LED_C609);
success:
return 0;
}
static struct hw_module_methods_t led_module_methods = {
open: led_device_open
};
// 一定要 HAL_MODULE_INFO_SYM 這名稱
const struct led_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: LED_HARDWARE_MODULE_ID,
name: "Sample LED Stub",
author: "The Mokoid Open Source Project",
methods: &led_module_methods,
}
/* supporting APIs go here. */
};
jni 讓C與Java可以溝通 android.mk
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) //# [optional, user, eng] //# eng = required //# optinal = no install on target LOCAL_MODULE_TAGS := eng //# This is the target being built. LOCAL_MODULE:= libmokoid_runtime //# Target install path. LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) //# All of the source files that we will compile. LOCAL_SRC_FILES:= \ com_mokoid_server_LedService.cpp //# All of the shared libraries we link against. LOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ libnativehelper \ libcutils \ libutils \ libhardware //# No static libraries. LOCAL_STATIC_LIBRARIES := //# Also need the JNI headers. LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ vendor/mokoid/hardware/modules/include/ //# No specia compiler flags. LOCAL_CFLAGS += //# Don't prelink this library. For more efficient code, you may want //# to add this library to the prelink map and set this to true. LOCAL_PRELINK_MODULE := false include $(BUILD_SHARED_LIBRARY)
com_mokoid_server_LedServoce.cpp
Android.mk
#define LOG_TAG "MokoidPlatform"
#include "utils/Log.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <jni.h>
#include <mokoid/led.h>
// -----------------------------------------------------------------
struct led_control_device_t *sLedDevice = NULL;
static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led) {
LOGI("LedService JNI: mokoid_setOn() is invoked.");
if (sLedDevice == NULL) {
LOGI("LedService JNI: sLedDevice was not fetched correctly.");
return -1;
} else {
return sLedDevice->set_on(sLedDevice, led);
}
}
static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led) {
LOGI("LedService JNI: mokoid_setOff() is invoked.");
if (sLedDevice == NULL) {
LOGI("LedService JNI: sLedDevice was not fetched correctly.");
return -1;
} else {
return sLedDevice->set_off(sLedDevice, led);
}
}
/** helper APIs */
static inline int led_control_open(const struct hw_module_t* module,
struct led_control_device_t** device) {
//取得 sLedDevice instance 指標
return module->methods->open(module,
LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}
static jboolean
mokoid_init(JNIEnv *env, jclass clazz)
{
led_module_t* module;
//利用 hw_get_module API 取得 hw_module_t
if ( hw_get_module(LED_HARDWARE_MODULE_ID,
(const hw_module_t**)&module) == 0 )
{
LOGI("LedService JNI: LED Stub found.");
if (led_control_open(&module->common, &sLedDevice) == 0) {
LOGI("LedService JNI: Got Stub operations.");
return 0;
}
}
LOGE("LedService JNI: Get Stub operations failed.");
return -1;
}
// --------------------------------------------------------------
static const JNINativeMethod gMethods[] =
{
//java call c function
{"_init", "()Z", (void*)mokoid_init},
{ "_set_on", "(I)Z", (void*)mokoid_setOn },
{ "_set_off", "(I)Z", (void*)mokoid_setOff },
};
static int registerMethods(JNIEnv* env) {
static const char* const kClassName =
"com/mokoid/server/LedService";
jclass clazz;
/* look up the class */
clazz = env->FindClass(kClassName);
if (clazz == NULL) {
LOGE("Can't find class %s\n", kClassName);
return -1;
}
/* register all the methods */
if (env->RegisterNatives(clazz, gMethods,
sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
{
LOGE("Failed registering methods for %s\n", kClassName);
return -1;
}
/* fill out the rest of the ID cache */
return 0;
}
// ----------------------------------------------------------------
/*
* 當這個so被VM載入 則呼叫此function
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed\n");
goto bail;
}
assert(env != NULL);
if (registerMethods(env) != 0) {
LOGE("ERROR: PlatformLibrary native registration failed\n");
goto bail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
bail:
return result;
}
framework 框架層Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(call all-subdir-java-files)
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := mokoid
LOCAL_SRC_FILES += \
core/java/mokoid/hardware/ILedService.aidl
include $(BUILD_JAVA_LIBRARY)
# The JNI component
include $(CLEAR_VARS)
include $(call all-makefiles-under,$(LOCAL_PATH))
com.mokoid.server.xml
LedService.java
package com.mokoid.server;
import android.util.Config;
import android.util.Log;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import mokoid.hardware.ILedService;
public final class LedService extends ILedService.Stub {
static {
System.load("/system/lib/libmokoid_runtime.so");
}
public LedService() {
Log.i("LedService", "Go to get LED Stub...");
_init();
}
/*
* Mokoid LED native methods.
*/
public boolean setOn(int led) {
Log.i("MokoidPlatform", "LED On");
return _set_on(led);
}
public boolean setOff(int led) {
Log.i("MokoidPlatform", "LED Off");
return _set_off(led);
}
private static native boolean _init();
private static native boolean _set_on(int led);
private static native boolean _set_off(int led);
}
ILedService.aidl
package mokoid.hardware;
interface ILedService
{
boolean setOn(int led);
boolean setOff(int led);
}
LedManager.java
package mokoid.hardware;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.util.Log;
import mokoid.hardware.ILedService;
/**
* Class that lets you access the Mokoid LedService.
*/
public class LedManager
{
private static final String TAG = "LedManager";
private ILedService mLedService;
public LedManager() {
mLedService = ILedService.Stub.asInterface(
ServiceManager.getService("led"));
if (mLedService != null) {
Log.i(TAG, "The LedManager object is ready.");
}
}
public boolean LedOn(int n) {
boolean result = false;
try {
result = mLedService.setOn(n);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in LedManager.LedOn:", e);
}
return result;
}
public boolean LedOff(int n) {
boolean result = false;
try {
result = mLedService.setOff(n);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in LedManager.LedOff:", e);
}
return result;
}
}
apps 應用程式層
Android.mk
Android.mk
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := user # This is the target being built. LOCAL_PACKAGE_NAME := LedTest # Only compile source java files in this apk. LOCAL_SRC_FILES := $(call all-java-files-under, src) # Link against the current Android SDK. LOCAL_SDK_VERSION := current # Also link against our own custom library. LOCAL_JAVA_LIBRARIES := mokoid framework # We need to assign platform key to use ServiceManager.addService. LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE)AndroidManifest.xml
LedSystemServer.java
package com.mokoid.LedTest;
import com.mokoid.server.LedService;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
public class LedSystemServer extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onStart(Intent intent, int startId) {
Log.i("LedSystemServer", "Start LedService...");
/* Please also see SystemServer.java for your interests. */
LedService ls = new LedService();
try {
ServiceManager.addService("led", ls);
} catch (RuntimeException e) {
Log.e("LedSystemServer", "Start LedService failed.");
}
}
}
LedTest.java
package com.mokoid.LedTest;
import mokoid.hardware.LedManager;
import com.mokoid.server.LedService;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Button;
import android.content.Intent;
import android.view.View;
public class LedTest extends Activity implements View.OnClickListener {
private LedManager mLedManager = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Start LedService in a seperated process.
startService(new Intent("com.mokoid.systemserver"));
// Just for testing. !! PLEASE DON't DO THIS !!
//LedService ls = new LedService();
Button btn = new Button(this);
btn.setText("Click to turn LED 1 On");
btn.setOnClickListener(this);
setContentView(btn);
}
public void onClick(View v) {
// Get LedManager.
if (mLedManager == null) {
Log.i("LedTest", "Creat a new LedManager object.");
mLedManager = new LedManager();
}
if (mLedManager != null) {
Log.i("LedTest", "Got LedManager object.");
}
/** Call methods in LedService via proxy object
* which is provided by LedManager.
*/
mLedManager.LedOn(1);
TextView tv = new TextView(this);
tv.setText("LED 1 is On.");
setContentView(tv);
}
}
訂閱:
文章 (Atom)
