7/12/2011

Covert string to char

這幾個禮拜 , 為了要在Android 2.3上implement HID profile 真的快把我給搞死...

不過還好 , 總算把bluetooth keyboard & mouse給弄出來了 !

過幾天再把一些心得和方法分享給在上面.

因為要自己寫JNI , 遇到上層的JAVA要傳一個字串下來 , 想當然爾JNI一定會宣告Jstring來接JAVA的字串.

但可不能直接把這個字串丟到C/C++的function , 一丟Android就直接process died....

這需要做一些轉換.

但說實在的 , JAVA 非常的不熟...所以直接從bluetooth的JNI抓出來看再改一改放到我的code裡面...

還滿簡單的.


/* Transfer jstring to C for */
const char *c_mac = env->GetStringUTFChars(address, 0);

size_t mac_sz = env->GetStringUTFLength(address) + 1;

char *c_mac_copy = (char *)malloc(mac_sz);

strncpy(c_mac_copy, c_mac, mac_sz);

hidd_command(c_mac_copy,mode);

env->ReleaseStringUTFChars(address, c_mac);



說穿了就是用GetSrtingUTFChars來轉 , 再用GetStringUTFLength來算長度 , 最後再用strncpy來把字串copy過去而己



但要注意的是,上面相對來說是指C++的JNI,如果是C的JNI,就要改成這樣了 :

const char *c_mac = (*env)->GetStringUTFChars(env,address, 0);

size_t mac_sz = (*env)->GetStringUTFLength(env,address) + 1;

char *c_mac_copy = (char *)malloc(mac_sz); // callback data

strncpy(c_mac_copy, c_mac, mac_sz);

hidd_command(c_mac_copy,mode);

(*env)->ReleaseStringUTFChars(env,address, c_mac);



原因在於jni.h的定義,路徑在 dalvik/libnativehelper/include/nativehelper/jni.h :

struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;

#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif


要特別注意了.....這個差點搞死我了= =

6/13/2011

How to capture home key event

在Android 2.3 , 想要取得home key event來做特殊事件 , 應用層是收不到該事件的.

因為Android在framwork layer做掉 , 所以並沒往APP layer上送.

frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java


// First we always handle the home key here, so applications
// can never break it, although if keyguard is on, we do let
// it handle it, because that gives us the correct 5 second
// timeout.
if (keyCode == KeyEvent.KEYCODE_HOME) {
Log.i(TAG,"----2keyCode == KeyEvent.KEYCODE_HOME");
// If a system window has focus, then it doesn't make sense
// right now to interact with applications.
WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
if (attrs != null) {
final int type = attrs.type;
if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
|| type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
// the "app" is keyguard, so give it the key
return false;
}
.............
.............
}


註釋寫的很清楚 , 而其中的重點在於type , 可以看出它有兩個type來判斷對該事件的處理 :

WindowManager.LayoutParams.TYPE_KEYGUARD
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG

所以在APP層 , 想要接收home key event的話 , 改變activity的類型即可 :


/* capture home key event*/
@Override
public void onAttachedToWindow()
{
this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
super.onAttachedToWindow();
}


其中的WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG可以改成WindowManager.LayoutParams.TYPE_KEYGUARD

但我測試過 , 用TYPE_KEYGUARD似乎會影響一些View的處理....

==========================

我發現..TYPE_KEYGUARD會使view變成懸浮視窗= =

非常怪異 !! 但實在想不出原因...最後只好自己硬幹 , 如果有人試出問題..別罵我QQ

上面提到定義了這些Typ......所以呢,我就自己定義一組Type !!

首先呢,可以在PhoneWindowManager.Java新增自己的Type :


if(type == WindowManager.LayoutParams.TYPE_DASHBOARD) {
Log.d("DASHBOARD","**** Send the home key event to app ****");
return false;
}


我自己定義了一個叫"TYPE_DASHBOARD"的東東,之後再到framwork/base/core/java/android/view/WindowManager.java去新增 :


@ViewDebug.ExportedProperty(mapping = {
.....
.....
@ViewDebug.IntToString(from = TYPE_DASHBOARD, to = "TYPE_DASHBOARD")
})

---------

public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;

/* Send Home key event to app layer */
public static final int TYPE_DASHBOARD = FIRST_SYSTEM_WINDOW+50;


當然了..那個後面數字隨便..50只是我的辛運數字 !!

改其它數字會不會出事就聽天命了...

還沒完 !! 再來到framwork/base/include/ui/InputDispatcher.h新增 :

// Window types from WindowManager.LayoutParams
enum {
.....
.....
TYPE_DASHBOARD = FIRST_SYSTEM_WINDOW+50,
}


到這裡,framwork的地方就改完了,接著只要在自己的APK加上這段 :

/* capture home key event*/
public static final int TYPE_DASHBOARD=2050;
@Override
public void onAttachedToWindow()
{
this.getWindow().setType(TYPE_DASHBOARD);
super.onAttachedToWindow();
}


嘿嘿,這樣接下來只要呼叫dispatchKeyEvent就可以收到Home key事件了 !! 而且不會有任何後遺症了喔 !!

5/05/2011

Install Java 5 on Ubuntu 10.4

某種因素,目前Ubunt 10.4的repository己經把Java 5移除

如果要想安裝Java 5的話,就必須手動加入source,如下操作 :

1.編輯apt-get

sudo vim /etc/apt/sources.list


2.加入source

## For sun-java5-jdk
deb http://ir.archive.ubuntu.com/ubuntu jaunty-updates main multiverse


3.更新repository & 安裝Java 5

sudo apt-get update
sudo apt-get install sun-java5-jdk


結束 !! :)

3/10/2011

淺談 ioctl 命令

最近因為某人開始實際碰driver, 每天照三餐靠北我.....

他拿出我二年前在某家公司寫的一份文件, 質疑了一些東西

本來呢, 我想重新整理一遍, 順便導正之前錯誤的觀念重寫一份貼上來

但....似乎想改的地方變動不大只好當作沒看見0.0

其實也只是教如何寫出在Linux虛擬出一個Driver, 仔細研究LDD3這本書就可以應付了.

剛巧他問了ioctl和magic number的問題, 我也在這稍微對這個ioctl分享自己的想法.

=======================

一般除了使用ioctl來搭建與kernel space橋樑之外, 常見的還有信號量(singel)和socket

談ioctl之前, 有一份kernel文件請一定要看, 通常它的路徑都會在 :

Kernel/Documentation/ioctl/ioctl-number.txt

其實kernel文件有很多寶,像是Kbuild.txt,devices.txt等等,滿多相關知識從那汲取的,值得一讀.

關係及使用到ioctl的頭文件, 它的路徑是在 :

Kernel/include/asm-generic/ioctl.h

其中有一個很重要的定義, 這個定義確保了每個命令都是唯一的"算法" :

#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))


怎麼說是算法呢 ? 因為IOC這個定義, 它把dir, type, nr, size 劃分成4個段

每段都有它自己的意義存在, 但從看上面到, 確保每個命令是系統唯一, 主要是靠type和nr

怎說呢 ? 且看下面.

在頭文件一開始的地方, 定義各個參數的資料段, 可以參考下圖 :



接著看頭文件它描述_IO等行為 :

#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))


其中dir代表如下 :

# define _IOC_NONE 0U
# define _IOC_WRITE 1U
# define _IOC_READ 2U

不管是dir或size, 每個使用者都有可能傳相同的方向和大小的"值".

關於type和nr的解釋, 參考LDD3的說明 :

type
The magic number. Just choose one number (after consulting ioctl-number.txt)
and use it throughout the driver. This field is eight bits wide (_IOC_TYPEBITS).

type, LDD3稱它為魔數, 也說明此魔數可以從loctl-number.txt挑選, 佔用1byte

number
The ordinal (sequential) number. It's eight bits (_IOC_NRBITS) wide.

即序號, 也可以是命令的編號, 一般我們定義從0開始, 總共可以定義255個cmd.

簡單來說, type 加 第一個nr 對應 "唯一"一個CMD

舉個例子來說, 假設我定義了一個DICKY_CMD :

#define DICKY_CMD_MAGIC_NUMBER 0xdf
#define DICKY_CMD _lOW(DICKY_CMD_MAGIC,1,unsigned int)

整個展開就會變成這樣 :

01(dir seg) , 1101 1111(Magic seg) , 0000 0000(Nr seg), ... (size就不寫了 ...)

這些就是ioctl的命令碼, 正確的說, 此命令碼, 代表是DICKY_CMD的身份, 系統才會做相對應的事.

========================

那個圖似乎有錯 ?? 與頭文件定義的順序不同....size和tyep相反了....

另, file_operations的ioctl要準備消失囉 !!

不過不會那麼快.....一樣還是會保留....就跟舊的register_char_device一樣, 都會存在

但可以的話, 還是用新的方式比較好 ! (不過我還沒看...哭了)

Kill ioctl.file_opreations

3/07/2011

Chrome to Phone

去年10月份, Google推出一款結合Android與Chrome的插件, 名叫"Chrome to Phone"

僅適合Android2.2以上系統使用.

它的使用方式就是..

在Host端(桌電or筆電)的Chrome安裝一個插件, Client端(手機)同時也安裝軟體

這樣使用者在Chrome瀏覽任何東西, 都可以直接透過軟體push到Client端

(當然也是需要Google帳戶才能用....可怕吧!!)

像是Google Map, Youtobe, 複製文字電話到手機觀看或儲存等等功能...

有興趣的人可以用key word去google一下.

但個人其實覺得, 這實用性並不大...

因為會想在手機上看Youtobe或Google Map, 一定都是出門或旅遊或通車無聊等等才會用到

有可能先打開電腦查一下...然後在push到手機上嗎= =

這樣感覺有點瞎掉.....當然也有人說可以事先先查, 然後存在手機上...

這不也是多此一舉嗎 ...

不管怎說, 這個技術也是滿不錯的, 未來我猜Google一定會把Chrome這個browser更好結合在其它device上

雖然它佔用資源多, 但現今的儲存技術及DRAM的低價格等等, 它的快速及方便的實用性擴充插件足以彌補或掩蓋這個缺點

點我看Chrome to Phone使用方法