要使用Gerrit搭配Jenkins auto build並auto code review/verify使用
需要建立一個Jenkins使用的帳號
若在LDAP auth之下
可使用指令建立內部使用的帳號
ssh -p <port> <host> gerrit create-account \
[--group <GROUP>] \
[--full-name <FULLNAME>] \
[--email <EMAIL>] \
[--ssh-key -|<KEY>] \
<USERNAME>
1). 建立帳號jenkins,指定公鑰
$ cat ~/.ssh/id_rsa.pub | ssh -p 29418 [Admin Account]@[ip] gerrit create-account --ssh-key - --full-name jenkins jenkins
2). 建立帳號jenkins,指定公鑰,指定名稱為jenkins
$ cat ~/.ssh/id_rsa.pub | ssh -p 29418 [Admin Account]@[ip] gerrit create-account --ssh-key - --full-name jenkins jenkins
ref:http://gerrit.googlecode.com/svn/documentation/2.2.1/cmd-create-account.html
2012年12月24日 星期一
2012年12月19日 星期三
[git] 開發使用指令
1). 開一個開發/測試使用branch
git branch [test_branch]
2). 移到此branch
git checkout [test_branch]
3). 在開發完後,將變更commit成一筆
git add .
git commit
4). 改壞了要回覆成codebase上的
4.1). 全部回覆到codebase
git checkout HEAD .
4.2). 回覆特定資料夾
git checkout [folder_name]
5). 紀錄此筆commit id,等等要把這筆commit剪(cherry-pick)過去master branch
git log
6). 切換到master
git checkout master
7). 把剛剛那筆commit剪過來master branch
git cherry-pick [commit-id]
8). push到codebase
git push
※ref: http://blog.luzi82.com/2010/08/git-cherry-pick-rebase.html
git branch [test_branch]
2). 移到此branch
git checkout [test_branch]
3). 在開發完後,將變更commit成一筆
git add .
git commit
5). 紀錄此筆commit id,等等要把這筆commit剪(cherry-pick)過去master branch
git log
6). 切換到master
git checkout master
7). 把剛剛那筆commit剪過來master branch
git cherry-pick [commit-id]
8). push到codebase
git push
※ref: http://blog.luzi82.com/2010/08/git-cherry-pick-rebase.html
2012年12月12日 星期三
2012年12月10日 星期一
[Linux] 無需帳號密碼shell的問題解決
1). 刪掉自己電腦known-hosts文件中儲存的特定ip私鑰
$ ssh-keygen -f "/home/qn_lo/.ssh/known_hosts" -R [ip.ip.ip.ip]:29418
$ ssh-keygen -f "/home/qn_lo/.ssh/known_hosts" -R [ip.ip.ip.ip]:29418
2012年12月7日 星期五
[Linux] vim視窗分割
將vim切割成兩個視窗
1). 水平切割
:new [path/filename]
2). 垂直切割
:vnew [path/filename]
3). 切換視窗
Ctrl+w w
1). 水平切割
:new [path/filename]
2). 垂直切割
:vnew [path/filename]
3). 切換視窗
Ctrl+w w
[Linux] 開啟vim預設設定檔
1). 安裝vim
$ sudo apt-get install vim
2). 開啟vim預設設定檔,新增一隻.local檔
$ sudo vi /etc/vim/vimrc.local
3). 將以下內容貼在這隻檔案
4). 由於nobackup有時會失效,則再新增一隻檔案
$ sudo vi /etc/vim/_gvimrc
$ sudo apt-get install vim
2). 開啟vim預設設定檔,新增一隻.local檔
$ sudo vi /etc/vim/vimrc.local
3). 將以下內容貼在這隻檔案
" 語法高亮度顯示 syntax on " 搜尋不分大小寫 set ignorecase " 搜尋若打小寫,則為不分大小寫;搜尋若有大寫,則為精確搜尋 set smartcase " 顯示列號 set number " 標記搜尋到的字串 set hlsearch " 指標線 set cursorline " 設定 tab 鍵的字元數 set tabstop=4 " 自動縮排 set autoindent " 不要留備份檔 set nobackup set nowritebackup
4). 由於nobackup有時會失效,則再新增一隻檔案
$ sudo vi /etc/vim/_gvimrc
" 不要留備份檔 set nobackup
2012年12月6日 星期四
2012年12月5日 星期三
[Android] device內的folder
1. system/app
裝的app會放在這個目錄
需要可以pull出來
$ adb pull /system/app/[name.apk] .
2. system/lib
需要用到的library
裝的app會放在這個目錄
需要可以pull出來
$ adb pull /system/app/[name.apk] .
2. system/lib
需要用到的library
2012年11月30日 星期五
[Linux] 開啟共享資料夾
[方法1]
資料夾點選右鍵[屬性]>[共享]
[方法2]
若出現以下Error message
'net usershare' 傳回 255 錯誤訊號: net usershare: cannot open usershare directory /var/lib/samba/usershares. Error 拒絕不符權限的操作
You do not have permission to create a usershare. Ask your administrator to grant you permissions to create a share.
此為權限問題
使用root權限開啟圖形化介面,以方法1方式修改共享資料夾
點選 “alt + f2″
輸入“gksudo nautilus”
會跳出圖形化介面的資料夾
ref: http://linuxowns.wordpress.com/2008/10/28/share-ubuntu-folders-with-windows-samba/
資料夾點選右鍵[屬性]>[共享]
[方法2]
若出現以下Error message
'net usershare' 傳回 255 錯誤訊號: net usershare: cannot open usershare directory /var/lib/samba/usershares. Error 拒絕不符權限的操作
You do not have permission to create a usershare. Ask your administrator to grant you permissions to create a share.
此為權限問題
使用root權限開啟圖形化介面,以方法1方式修改共享資料夾
點選 “alt + f2″
輸入“gksudo nautilus”
會跳出圖形化介面的資料夾
ref: http://linuxowns.wordpress.com/2008/10/28/share-ubuntu-folders-with-windows-samba/
[Linux] 更改電腦名稱(hostname)
要更改電腦名稱
需修改以下兩隻檔案中
將原有的電腦名稱改成新電腦名稱
改完之後重開機
/etc/hosts
/etc/hostname (第一行)
$ sudo vi /etc/hosts
line2: 127.0.0.1 [hostname]
ex: 127.0.0.1 qn.ubuntu
$ sudo vi hostname
line1: qn.ubuntu
需修改以下兩隻檔案中
將原有的電腦名稱改成新電腦名稱
改完之後重開機
/etc/hosts
/etc/hostname (第一行)
$ sudo vi /etc/hosts
line2: 127.0.0.1 [hostname]
ex: 127.0.0.1 qn.ubuntu
$ sudo vi hostname
line1: qn.ubuntu
[Android] 在userdebug之下push檔案到read only
在user mode,system等權限為read only,無法push檔案
在userdebug mode及eng mode,權限是打開的
若顯示read only,須先remout後,就可以繼續push
$ adb root
$ adb remount
$ adb push [filename] /system/lib
在userdebug mode及eng mode,權限是打開的
若顯示read only,須先remout後,就可以繼續push
$ adb root
$ adb remount
$ adb push [filename] /system/lib
2012年11月13日 星期二
[Android] 在codebase中build APP
需要放到Android codebase底下build的app
放在package/app或是vendor/3rdparty底下
這樣就會build了
build出來的路徑是out/target/common/obj/APPS
若要build在image中
在device/nvidia/ventana/ventana.mk
增加PRODUCT_PACKAGES += [product name]
放在package/app或是vendor/3rdparty底下
這樣就會build了
build出來的路徑是out/target/common/obj/APPS
若要build在image中
在device/nvidia/ventana/ventana.mk
增加PRODUCT_PACKAGES += [product name]
2012年11月12日 星期一
[Android] 查看Android device key:app sign key
查看sign什麼key
$ adb shell getprop ro.build.fingerprint
若是Android default的key會顯示test key
但Android要出貨,需過CTS,其中一項會檢測key需用自己創造的key
則會顯示release key
android的app若是需要用到系統權限
則需要用同一把key sign此app
此app才能夠獲得系統權限
sign app for system permission)
$ java -Xmx2048m -jar utils/linux-x86/framework/signapk.jar -w keys/platform.x509.pem keys/platform.pk8 unsigned_app.apk signed_app.apk
$ adb shell getprop ro.build.fingerprint
若是Android default的key會顯示test key
但Android要出貨,需過CTS,其中一項會檢測key需用自己創造的key
則會顯示release key
android的app若是需要用到系統權限
則需要用同一把key sign此app
此app才能夠獲得系統權限
sign app for system permission)
$ java -Xmx2048m -jar utils/linux-x86/framework/signapk.jar -w keys/platform.x509.pem keys/platform.pk8 unsigned_app.apk signed_app.apk
2012年11月9日 星期五
[git] clone裸版本庫;下載git server
下載一份git server的形式 (裸版本庫)
非codebase
git server的形式如下
/branches
/hooks
/logs
/objects
/refs
config
description
HEAD
下載:
$ git clone --bare ssh://[git server ip]
非codebase
git server的形式如下
/branches
/hooks
/logs
/objects
/refs
config
description
HEAD
下載:
$ git clone --bare ssh://[git server ip]
2012年11月6日 星期二
[linux][git] 架設Git Server及GitWeb
架設Git Server及GitWeb
1). 安裝ssh server、git-core、apache2、gitweb
$ sudo apt-get install ssh git-core apache2 gitweb
2). 創建放git server資料的使用者帳戶
$ sudo useradd -m -s /bin/bash [account]
$ sudo passwd [account]
※ useradd參數
-m:強制有家目錄
-s:設定shell,預設是/bin/sh
3). 啟動ssh
$ sudo sudo /etc/init.d/ssh restart
4). 創建git project
$ sudo su - [account]
$ mkdir TestProject.git
$ cd TestProject.git
$ git init --bare
5). 修改Gitweb連結路徑
$ cd /var/cache/
$ sudo rmdir git
$ sudo ln -sf [放git project的目錄路徑] git
ex: sudo ln -sf /home/git git
1). 安裝ssh server、git-core、apache2、gitweb
$ sudo apt-get install ssh git-core apache2 gitweb
2). 創建放git server資料的使用者帳戶
$ sudo useradd -m -s /bin/bash [account]
$ sudo passwd [account]
※ useradd參數
-m:強制有家目錄
-s:設定shell,預設是/bin/sh
3). 啟動ssh
$ sudo sudo /etc/init.d/ssh restart
4). 創建git project
$ sudo su - [account]
$ mkdir TestProject.git
$ cd TestProject.git
$ git init --bare
5). 修改Gitweb連結路徑
$ cd /var/cache/
$ sudo rmdir git
$ sudo ln -sf [放git project的目錄路徑] git
ex: sudo ln -sf /home/git git
2012年10月31日 星期三
2012年10月29日 星期一
[python] 編碼錯誤解決(UnicodeDecodeError)
錯誤訊息:
Traceback (most recent call last):
File "./check_notice.py", line 243, in <module>
file.save('Check_Legal_Notice_Report.xls')
File "/usr/local/lib/python2.7/dist-packages/xlwt/Workbook.py", line 643, in save
doc.save(filename, self.get_biff_data())
File "/usr/local/lib/python2.7/dist-packages/xlwt/Workbook.py", line 618, in get_biff_data
shared_str_table = self.__sst_rec()
File "/usr/local/lib/python2.7/dist-packages/xlwt/Workbook.py", line 580, in __sst_rec
return self.__sst.get_biff_record()
File "/usr/local/lib/python2.7/dist-packages/xlwt/BIFFRecords.py", line 77, in get_biff_record
self._add_to_sst(s)
File "/usr/local/lib/python2.7/dist-packages/xlwt/BIFFRecords.py", line 92, in _add_to_sst
u_str = upack2(s, self.encoding)
File "/usr/local/lib/python2.7/dist-packages/xlwt/UnicodeUtils.py", line 50, in upack2
us = unicode(s, encoding)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 40: ordinal not in range(128)
--
此為編碼錯誤(UnicodeDecodeError)
Python內部使用unicode編碼
在做編碼轉換時,需先將其他解碼(decode)成unicode
再從unicode編碼(encode)成另一種編碼
Ex1:
print a.encode('utf-8')
Ex2:
sheet.write(row,col,data.encode('utf-8'))
Traceback (most recent call last):
File "./check_notice.py", line 243, in <module>
file.save('Check_Legal_Notice_Report.xls')
File "/usr/local/lib/python2.7/dist-packages/xlwt/Workbook.py", line 643, in save
doc.save(filename, self.get_biff_data())
File "/usr/local/lib/python2.7/dist-packages/xlwt/Workbook.py", line 618, in get_biff_data
shared_str_table = self.__sst_rec()
File "/usr/local/lib/python2.7/dist-packages/xlwt/Workbook.py", line 580, in __sst_rec
return self.__sst.get_biff_record()
File "/usr/local/lib/python2.7/dist-packages/xlwt/BIFFRecords.py", line 77, in get_biff_record
self._add_to_sst(s)
File "/usr/local/lib/python2.7/dist-packages/xlwt/BIFFRecords.py", line 92, in _add_to_sst
u_str = upack2(s, self.encoding)
File "/usr/local/lib/python2.7/dist-packages/xlwt/UnicodeUtils.py", line 50, in upack2
us = unicode(s, encoding)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 40: ordinal not in range(128)
--
此為編碼錯誤(UnicodeDecodeError)
Python內部使用unicode編碼
在做編碼轉換時,需先將其他解碼(decode)成unicode
再從unicode編碼(encode)成另一種編碼
Ex1:
print a.encode('utf-8')
Ex2:
sheet.write(row,col,data.encode('utf-8'))
2012年10月26日 星期五
[python] list與dictionary的結合
dictionary能儲存資料以及索引
對整理資料能夠有比較好的架構
但資料卻不是有序的序列
於是可藉由list來幫忙做排序
這篇介紹list中包dictionary,及dictionary中包list的方法
1). list中包dictionary
2). dictionary中包list
2.1). 新增資料前先檢查有沒有key
※ref:http://lucaswei.blogspot.tw/2012/05/pythondictxlist.html
對整理資料能夠有比較好的架構
但資料卻不是有序的序列
於是可藉由list來幫忙做排序
這篇介紹list中包dictionary,及dictionary中包list的方法
1). list中包dictionary
dict1={key:a} dict2={key:b} list=[dict1,dict2] or list=[] list.append(dict1)
2). dictionary中包list
dict={} dict[key]=list() dict[key].append(value)
2.1). 新增資料前先檢查有沒有key
if key not in dict: dict[key] = list() dict[key].append(value)
※ref:http://lucaswei.blogspot.tw/2012/05/pythondictxlist.html
[python] 外部指令
python需引用外部指令時,可用以下程式碼
import commands command_git='cd %s; git log' %(codebase) log=commands.getoutput(command_git)
[python] iterator與enumerate
enumerate(iterable, start=0)
回傳以 iterable 與連續整數配對的 enumerate 物件, start 為整數的起始值,預設為 0
Ex1:
Ex2:
回傳以 iterable 與連續整數配對的 enumerate 物件, start 為整數的起始值,預設為 0
Ex1:
d = ['Spring', 'Summer', 'Fall', 'Winter'] for i, j in enumerate(d, 1): print(i, j) [output] 1 Spring 2 Summer 3 Fall 4 Winter
Ex2:
for i, n in enumerate([1, 3, 5]): print i, n [output] 0 1 1 3 2 5
2012年10月11日 星期四
[python] 使用xlwt輸出excel檔
1). 下載xlwt
http://pypi.python.org/pypi/xlwt
2). 安裝xlwt
$ cd [下載的xlwt目錄]
$ sudo python setup.py install
3). 輸出excel檔
#!/usr/bin/python
※[python] 安裝套件方法
http://pypi.python.org/pypi/xlwt
2). 安裝xlwt
$ cd [下載的xlwt目錄]
$ sudo python setup.py install
3). 輸出excel檔
#!/usr/bin/python
import xlwt #要先安裝xlwt file = xlwt.Workbook() #Work的W是大寫 #table = file.add_sheet('sheet name') #新建sheet table = file.add_sheet('sheet name',cell_overwrite_ok=True) #對同個儲存格可複寫的sheet table.write(0,0,'test') #對某個儲存格寫入資料 file.save('demo.xls') #儲存為excel
※[python] 安裝套件方法
2012年10月9日 星期二
2012年9月21日 星期五
[Linux][ShellScript] grep應用
問題
一個txt內存有檔案路徑列表,對此txt中每一檔案路徑做關鍵字查詢
.
├── file.txt
├── a.txt
├── b.txt
├── c.txt
└── test.sh
解法
$ cat file.txt |xargs grep "keyword"
出來的結果是出現有搜尋到關鍵字的檔名,及關鍵字
path/a.txt:keyword
path/b.txt:keyword
只顯示又搜尋到關鍵字的檔名
$ cat file.txt |xargs grep "keyword" |awk -F: '{print $1}'
[Linux][ShellScript] awk - 取得token, 以符號切割
Data=123:aa bbb c
1). 擷取某個token
Ex1: 擷取第2個token
$ awk '{print $2}' Data
Ex2: 擷取第2.3個token
$ awk '{print $2,$3}' Data
2). 以符號切割,並取冒號之後的字串
$ awk -F: '{print $2} Data'
1). 擷取某個token
Ex1: 擷取第2個token
$ awk '{print $2}' Data
Ex2: 擷取第2.3個token
$ awk '{print $2,$3}' Data
2). 以符號切割,並取冒號之後的字串
$ awk -F: '{print $2} Data'
2012年8月21日 星期二
2012年8月15日 星期三
[Linux][ShellScript] 輸出變數
變數要從母script傳到子script
母script=1.sh
子script=2.sh
1). 在母script export需要的變數
name=John
export name
./2sh
2). 在子script就可以直接用了
母script=1.sh
子script=2.sh
1). 在母script export需要的變數
name=John
export name
./2sh
2). 在子script就可以直接用了
[Linux][ShellScript] Shell Script分隔變數
Shell Script
1). 宣告變數:name
name=John
2). 呼叫變數:$name or ${name}
echo $name
echo ${name}
※若變數一起打,沒有用{}區隔,容易有混淆
(X) echo $name_$number →僅會顯示number
(O) echo ${name}_${number}
1). 宣告變數:name
name=John
2). 呼叫變數:$name or ${name}
echo $name
echo ${name}
※若變數一起打,沒有用{}區隔,容易有混淆
(X) echo $name_$number →僅會顯示number
(O) echo ${name}_${number}
2012年8月7日 星期二
[Jenkins][Android] build Android的source環境設置
在Android build code前
需下source build/envsetup.sh設置環境變數
但由於jenkins是用/bin/sh,sh並沒有source的指令
因此需在jenkins指定使用/bin/bash
才可以正確使用source設置環境變數
需下source build/envsetup.sh設置環境變數
但由於jenkins是用/bin/sh,sh並沒有source的指令
因此需在jenkins指定使用/bin/bash
才可以正確使用source設置環境變數
2012年8月1日 星期三
2012年7月4日 星期三
[Linux] tar壓縮相對路徑之目錄檔案
問題
tar壓縮檔案時,會將給的路徑全都壓縮進去
沒有辦法只壓縮目錄底下的某個子目錄
範例
→這樣壓縮起來,會把前面的資料夾也壓縮進去
如果我只要壓縮底下的子目錄以下要怎麼做呢?
解法
tar的-C參數,能夠臨時切換目錄
tar -jcv -f [壓縮的檔名] -C [臨時切換的目錄] [要壓縮的目錄或檔案]
tar壓縮檔案時,會將給的路徑全都壓縮進去
沒有辦法只壓縮目錄底下的某個子目錄
範例
$ tree . └── a └── b └── c └── d.txt $ tar -jcv -f e.tar.bz2 a/b/c/d.txt a/b/c/d.txt
→這樣壓縮起來,會把前面的資料夾也壓縮進去
如果我只要壓縮底下的子目錄以下要怎麼做呢?
解法
tar的-C參數,能夠臨時切換目錄
tar -jcv -f [壓縮的檔名] -C [臨時切換的目錄] [要壓縮的目錄或檔案]
$ tar -jcv -f e.tar.bz2 a/b/c/d.txt↓換成
$ tar -jcv -f e.tar.bz2 -C a/b/c/ d.txt d.txt
2012年6月27日 星期三
[Linux] 檔案目錄權限
一、使用者
1). Owner
2). Group
3). Other
1). Read:4
2). Write:2
3). eXecute:1
三、特殊權限
1). Setuid:4
(檔案) 設置使文件在執行階段具有文件所有者的權限
2). Setgid:2
(目錄) 目錄被設置該位後, 任何用戶在此目錄下創建的文件都具有和該目錄所屬的組相同的組
3). sTicky:1
(檔案) 即使具有write的權限,僅有檔案使用者及root權限者才可以刪除檔案
● 設置方式:加在原本三位權限的最前方
ex: chmod 1777 /tmp
※ note:
$ ll /bin/su
drwxrwxrwt 19 root root 4096 2012-06-27 11:17 ./
$ ll /usr/bin/sudo
-rwsr-xr-x 2 root root 168800 2011-05-30 14:06 /usr/bin/sudo*
$ ll /tmp/ drwxrwxrwt 19 root root 4096 2012-06-27 17:39 ./
※ ref:
http://www.lslnet.com/linux/f/docs1/i55/big5368810.htm
2012年6月22日 星期五
[Android] [JAVA] 按鈕監聽
作法
1). 單項標準作法
2). 多項使用switch作法
//=============================================================
1). 單項標準作法
public class DeviceInfo2 extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 找到元件資源 Button button_info1 = (Button) findViewById(R.id.main_submit_info1); // 設定按鍵觸發的method button_info1.setOnClickListener(listDeviceInfo); } private Button.OnClickListener listDeviceInfo = new Button.OnClickListener() { @Override public void onClick(View v) { // 宣告intent,並指定要啟動的class Intent intent = new Intent(DeviceInfo2.this, mService.class); // 以startservice方式啟動intent startService(intent); } }; }
//=============================================================
2). 多項使用switch作法
public class DeviceInfo2 extends Activity implements OnClickListener{ /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 找到元件資源 Button button_info1 = (Button) findViewById(R.id.main_submit_info1); button_info1.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.main_submit_info1: // 宣告intent,並指定要啟動的class Intent intent = new Intent(DeviceInfo2.this, mService.class); // 以startservice方式啟動intent startService(intent); break; } }
2012年6月20日 星期三
[Example] [Android] [JAVA] JNI & NDK應用_BMI
JNI & NDK應用_BMI
JNI會將使用者輸入的身高體重傳到C
真正計算是由C來實作
C會將算完的答案回傳到JAVA
JAVA再將其顯示在UI上
流程方法
藉由java撰寫native method,JNI即可在Java中呼叫C寫的程式
C的程式藉由NDK包成.so檔,就可以被JNI呼叫
程式流程
1). (java) 撰寫native method,不需實做
2). 將寫好的.java檔,編成.class檔,再轉成.h檔
3). (C) 撰寫C程式碼,實做.h中的function標頭
4). 撰寫NDK需要的Android.mk
5). 利用NDK將C程式碼轉成.so檔
6). (java) 利用JNI呼叫C的程式
//=============================================================
[Main.java]
[Bmi.java]
參考資料:
[Android] [JAVA] JNI & NDK
JNI會將使用者輸入的身高體重傳到C
真正計算是由C來實作
C會將算完的答案回傳到JAVA
JAVA再將其顯示在UI上
流程方法
藉由java撰寫native method,JNI即可在Java中呼叫C寫的程式
C的程式藉由NDK包成.so檔,就可以被JNI呼叫
程式流程
1). (java) 撰寫native method,不需實做
2). 將寫好的.java檔,編成.class檔,再轉成.h檔
3). (C) 撰寫C程式碼,實做.h中的function標頭
4). 撰寫NDK需要的Android.mk
5). 利用NDK將C程式碼轉成.so檔
6). (java) 利用JNI呼叫C的程式
//=============================================================
[Main.java]
package com.jni; import java.text.DecimalFormat; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.view.View; import android.view.View.OnClickListener; import android.os.Bundle; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class Main extends Activity { double height, weight; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button button = (Button) findViewById(R.id.button_submit); button.setOnClickListener(calbmi); } private OnClickListener calbmi = new OnClickListener() { @Override public void onClick(View v) { DecimalFormat nf = new DecimalFormat("0.00"); EditText fieldheight = (EditText) findViewById(R.id.edit_height); EditText fieldweight = (EditText) findViewById(R.id.edit_weight); try { height = Double.parseDouble(fieldheight.getText().toString()); weight = Double.parseDouble(fieldweight.getText().toString()); } catch (NumberFormatException e) { // Toast.makeText(v.getContext(), // "Please submit height and weight.", Toast.LENGTH_LONG) // .show(); openOptionsDialog(); } if (height == 0 || weight == 0) { openOptionsDialog(); } else { TextView bmi = (TextView) findViewById(R.id.text_result); double bmi_value = new Bmi().calbmi(height, weight); bmi.setText("Your BMI is " + nf.format(bmi_value)); } } }; private void openOptionsDialog() { AlertDialog.Builder dialog = new AlertDialog.Builder(Main.this); dialog.setTitle(R.string.dialog_title); dialog.setMessage(R.string.dialog_msg); dialog.setPositiveButton(R.string.dialog_btn, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialoginterface, int i) { } }); dialog.show(); } }
[Bmi.java]
package com.jni; public class Bmi { public native String stringFromJNI(); public native double calbmi(double height, double weight); static{ System.loadLibrary("cal_bmi_c"); } }
參考資料:
[Android] [JAVA] JNI & NDK
2012年6月19日 星期二
[Android] [JAVA] JNI & NDK
Java Native Interface(JNI)
JNI 是用來讓Java跟別種語言溝通的函式庫
Android中是讓Java及C之間溝通
分為Java Call C及C Call Java
Android Native Development Tools(NDK)
將C code包成.so檔,供Java利用
流程方法
藉由java撰寫native method,JNI即可在Java中呼叫C寫的程式
C的程式藉由NDK包成.so檔,就可以被JNI呼叫
//=============================================================
程式流程
1). (java) 撰寫native method,不需實做
2). 將寫好的.java檔,編成.class檔,再轉成.h檔
3). (C) 撰寫C程式碼,實做.h中的function標頭
3). 利用NDK將C程式碼轉成.so檔
4). (java) 利用JNI呼叫C的程式
//=============================================================
步驟
1). (java) 撰寫native method,不需實做
native method前要加native
要load的.so檔是libcal_bmi_c.so,扣除掉前面的lib及後面的.so
method是calbmi,回傳是double的型態
從Java傳入使用者輸入的height, weight
[Bmi.java]
package com.jni; public class Bmi { public native double calbmi(double height, double weight); static{ //要load的.so檔。去掉開頭的lib,及結尾的.so System.loadLibrary("cal_bmi_c"); } }2). 將寫好的.java檔,編成.class檔,再轉成.h檔
Eclipse會自動編成.class檔
進入project的資料夾,新開jni資料夾
將編好的.h檔放在jni資料夾中
$ cd [project資料夾] $ mkdir jni $ cd jni $ javah -jni -classpath [放置class的資料夾] [package].[class] ex: javah -jni -classpath /home/qn_lo/develop/android/workspace/BmiJni/bin/classes com.jni.Bmi
3). (C) 撰寫C程式碼,實做.h中的function標頭在jni資料夾新增C程式碼檔案
將.h檔的JNIEXPORT複製到C並實作
[com_jni_Bmi.h]
/* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class com_jni_Bmi */ #ifndef _Included_com_jni_Bmi #define _Included_com_jni_Bmi #ifdef __cplusplus extern "C" { #endif /* * Class: com_jni_Bmi * Method: calbmi * Signature: (DD)D */ JNIEXPORT jdouble JNICALL Java_com_jni_Bmi_calbmi (JNIEnv *, jobject, jdouble, jdouble); #ifdef __cplusplus } #endif #endif
[com_jni_Bmi.c]
#include #include JNIEXPORT jdouble JNICALL Java_com_jni_Bmi_calbmi (JNIEnv *env, jobject obj, jdouble cheight, jdouble cweight) { double height,weight,bmi; height=cheight/100; weight=cweight; bmi=weight/(height*height); return bmi; }
4). 撰寫NDK需要的Android.mk在jni資料夾中新增Android.mk
LOCAL_MODULE是編成的.so檔名
LOCAL_SRC_FILES是要編的C程式碼檔名
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := cal_bmi_c LOCAL_SRC_FILES := com_jni_Bmi.c include $(BUILD_SHARED_LIBRARY)
5). 利用NDK將C程式碼轉成.so檔
a). 先到Android NDK下載NDK
b). 在project資料夾下新建libs的資料夾
如果有需要,可在Eclipse中在Project按右鍵reflesh
c). 在Eclipse的Project點右鍵[properties]
在[Builders]中new一個編譯器,選擇program
輸入Builder的Name,在Main標籤中,輸入Location及Working Directory
在Refresh標籤中,將Refresh resource upon completion勾選
並選擇Specific resource的路徑為project的libs
在Build Options標籤中
勾選Specify working set of relevant resource
並選擇Specify Resource路徑為Project的jni
d). 按下Build All的按鈕將C編成.so檔
6). (java) 利用JNI呼叫C的程式在java要呼叫,[放JNI的class]().[native method]
new Bmi().calbmi(height, weight)
參考資料:
http://ironurbane.iteye.com/blog/425513
http://kitty.2y.idv.tw/~enijmax/linux/CLib_Jni.html
[blog] Blogger加SyntaxHighlighter顯示程式碼
SyntaxHighlighter
一套可在blogger中置入整齊的程式碼的工具,僅用網頁的Java即可呈現
支援多種語言及多種風格樣板
//=============================================================
1). 至官網下載壓縮包,並將script資料夾上傳到網頁空間
或者也可以使用官網提供的Host Version
以下範例使用官網提供的Host Version
2). 到blogger後台,修改html中,找到<b:skin>標籤,將以下程式碼貼在此標籤前
3). 找到標籤,將程式碼貼在此標籤前
4). 要使用時,在文章中用此標籤將程式碼夾起來
※ brush有很多種,細節請見官網的blush列表
※ 有額外的設定檔可加在標籤內,細節請見官網的configuration
ex:
一套可在blogger中置入整齊的程式碼的工具,僅用網頁的Java即可呈現
支援多種語言及多種風格樣板
//=============================================================
1). 至官網下載壓縮包,並將script資料夾上傳到網頁空間
或者也可以使用官網提供的Host Version
以下範例使用官網提供的Host Version
2). 到blogger後台,修改html中,找到<b:skin>標籤,將以下程式碼貼在此標籤前
3). 找到標籤,將程式碼貼在此標籤前
4). 要使用時,在文章中用此標籤將程式碼夾起來
..程式碼..
※ brush有很多種,細節請見官網的blush列表
※ 有額外的設定檔可加在標籤內,細節請見官網的configuration
ex:
...
2012年6月8日 星期五
[Android] [JAVA] bindService
bindService可將Activity與Service連接
當連線成功後,會自動呼叫執行這個connection內的onServiceConnected(ComponentName className, IBinder service) function,在這function會接收到由service內的onBinde()所丟出來的Ibinder物件,利用這IBinder物件取得Service物件,就可以直接操作Service內各個public 的method
[Activity]
1). 宣告MyService的變數,用此讀取MyService的資料
2). 宣告ServiceConnection的變數,並撰寫onServiceConnected及onServiceDisconnected的method
3). 使用bindService方法連結Activity及Service
[Service]
1). 宣告MyBinder的變數
2). 定義MyBinder的類別來取得MyService的物件實例
3). 使用onBind的方法綁定Service,返回一個ibinder的對象進行操作
4). 撰寫剩下的onRebind、onUnbind
//=============================================================
[Main.xml]
//-------------------------------------------------------------------------------------------------------------
[MyService.xml]
當連線成功後,會自動呼叫執行這個connection內的onServiceConnected(ComponentName className, IBinder service) function,在這function會接收到由service內的onBinde()所丟出來的Ibinder物件,利用這IBinder物件取得Service物件,就可以直接操作Service內各個public 的method
[Activity]
1). 宣告MyService的變數,用此讀取MyService的資料
2). 宣告ServiceConnection的變數,並撰寫onServiceConnected及onServiceDisconnected的method
3). 使用bindService方法連結Activity及Service
[Service]
1). 宣告MyBinder的變數
2). 定義MyBinder的類別來取得MyService的物件實例
3). 使用onBind的方法綁定Service,返回一個ibinder的對象進行操作
4). 撰寫剩下的onRebind、onUnbind
//=============================================================
[Main.xml]
package com.servicetest2; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class Main extends Activity implements OnClickListener { private Intent intent; private MyService myService; private boolean flag; private ServiceConnection serviceconnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Toast.makeText(Main.this, "Bind Service", Toast.LENGTH_SHORT).show(); myService = ((MyService.MyBinder) service).getService(); flag = true; Log.d("Main","Bind"); } @Override public void onServiceDisconnected(ComponentName name) { Toast.makeText(Main.this, "Bind Service Failed", Toast.LENGTH_SHORT).show(); myService = null; } }; public void onClick(View view) { switch (view.getId()) { case R.id.btnStartService: startService(intent); break; case R.id.btnStopService: stopService(intent); break; case R.id.btnBindService: bindService(intent, serviceconnection, Context.BIND_AUTO_CREATE); break; case R.id.btnUnbindService: // 當有bind,才會unbind if (flag == true) { unbindService(serviceconnection); flag = false; Log.d("switch","if"); } Log.d("switch","break"); break; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); flag = false; // 取得資源 Button btnStartService = (Button) findViewById(R.id.btnStartService); Button btnBindService = (Button) findViewById(R.id.btnBindService); Button btnUnbindService = (Button) findViewById(R.id.btnUnbindService); Button btnStopService = (Button) findViewById(R.id.btnStopService); // 設置按下按鈕的物件實例 btnStartService.setOnClickListener(this); btnBindService.setOnClickListener(this); btnUnbindService.setOnClickListener(this); btnStopService.setOnClickListener(this); intent = new Intent(this, MyService.class); } }
//-------------------------------------------------------------------------------------------------------------
[MyService.xml]
package com.servicetest2; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class MyService extends Service{ public MyBinder myBinder=new MyBinder(); @Override public IBinder onBind(Intent intent) { Log.d("MyService","onBind"); return myBinder; } @Override public void onRebind(Intent intent){ Log.d("MyService","onRebind"); super.onRebind(intent); } @Override public boolean onUnbind(Intent intent){ Log.d("MyService","onUnbind"); return super.onUnbind(intent); } @Override public void onCreate(){ Log.d("MyService","onCreate"); super.onCreate(); } @Override public void onDestroy(){ Log.d("MyService","onDestory"); super.onDestroy(); } @Override public void onStart(Intent intent, int startId){ Log.d("MyService","onStart"); super.onStart(intent, startId); } public class MyBinder extends Binder{ MyService getService(){ return MyService.this; } } }
2012年6月5日 星期二
2012年5月30日 星期三
[Android] [JAVA] 顯示剩餘電量的AP
1). 在主程式中,建立BroadcastReceiver類型的變數,利用BatteryManager讀出電量的資料
2). 註冊receive,僅有此可以利外寫在這,而不用寫在AndroidManifest.xml
//=============================================================
package com.broadcasttest2;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;
import android.widget.TextView;
public class BroadcastTest2 extends Activity {
private TextView BatteryChange;
private BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
// 目前電量的值
int level = intent.getIntExtra("level", 0);
// 表示電量的總刻度
int scale = intent.getIntExtra("Scale", 100);
// 也可以寫成這樣
//int voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 100);
BatteryChange.setText("電池用量" + (level * 100 / scale) + "%" );
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
BatteryChange = (TextView) findViewById(R.id.battery);
registerReceiver(batteryReceiver, new IntentFilter(
Intent.ACTION_BATTERY_CHANGED)); }
}
2). 註冊receive,僅有此可以利外寫在這,而不用寫在AndroidManifest.xml
//=============================================================
package com.broadcasttest2;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;
import android.widget.TextView;
public class BroadcastTest2 extends Activity {
private TextView BatteryChange;
private BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
// 目前電量的值
int level = intent.getIntExtra("level", 0);
// 表示電量的總刻度
int scale = intent.getIntExtra("Scale", 100);
// 也可以寫成這樣
//int voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 100);
BatteryChange.setText("電池用量" + (level * 100 / scale) + "%" );
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
BatteryChange = (TextView) findViewById(R.id.battery);
registerReceiver(batteryReceiver, new IntentFilter(
Intent.ACTION_BATTERY_CHANGED)); }
}
[Android] [JAVA] 開機自動執行的AP
1). 寫一個主程式,Broadcast需要去啟動的程式。BroadcastTest1
2). 繼承Broadcast類別,並設定intent連到主程式。StartUpReceiver
3). 在Androidmanifest.xml設置<receive>的標籤
4). 在Androidmanifest.xml添加權限
//=============================================================
[BroadcastTest1]
package com.broadcasttest1;
import android.app.Activity;
import android.os.Bundle;
public class BroadcastTest1 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
//-------------------------------------------------------------------------------------------------------------
[StartUpReceiver]
package com.broadcasttest1;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class StartUpReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
Intent intent = new Intent(arg0, BroadcastTest1.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
arg0.startActivity(intent);
}
}
//-------------------------------------------------------------------------------------------------------------
[AndroidManifest.xml]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.broadcasttest1"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<!-- Activity -->
<activity
android:name=".BroadcastTest1"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Receiver -->
<receiver android:name=".StartUpReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
2). 繼承Broadcast類別,並設定intent連到主程式。StartUpReceiver
3). 在Androidmanifest.xml設置<receive>的標籤
4). 在Androidmanifest.xml添加權限
//=============================================================
[BroadcastTest1]
package com.broadcasttest1;
import android.app.Activity;
import android.os.Bundle;
public class BroadcastTest1 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
//-------------------------------------------------------------------------------------------------------------
[StartUpReceiver]
package com.broadcasttest1;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class StartUpReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
Intent intent = new Intent(arg0, BroadcastTest1.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
arg0.startActivity(intent);
}
}
//-------------------------------------------------------------------------------------------------------------
[AndroidManifest.xml]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.broadcasttest1"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<!-- Activity -->
<activity
android:name=".BroadcastTest1"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Receiver -->
<receiver android:name=".StartUpReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
[Android] [JAVA] Broadcast
1). 編寫一個繼承Broadcast的類別,並實現裡面的onReceive方法
2). 在AndroidManifest.xml使用<receive>標籤指定第一步的類別接收哪一個Broadcast Action
3). 如果有需要,在AndroidManifest.xml添加權限
2). 在AndroidManifest.xml使用<receive>標籤指定第一步的類別接收哪一個Broadcast Action
3). 如果有需要,在AndroidManifest.xml添加權限
2012年5月29日 星期二
[Repo] note
● repo的流程:
1). git init -u [site] 會將設定檔及source code的server型態,下載到project_dir/.repo中
2). 若有需要,修改project_dir/.repo/manifest/default.xml
此會決定要下載哪些project,版本分別是什麼
3). 再到project_dir/platform中repo sync
source code就會從server型態轉成git型態,此步不需要網路連線
server型態的存在project_dir/.repo/projects
裡面每一個.git都是一個git project
● git init 若加--mirror,出來的會是git server的型態
1). git init -u [site] 會將設定檔及source code的server型態,下載到project_dir/.repo中
2). 若有需要,修改project_dir/.repo/manifest/default.xml
此會決定要下載哪些project,版本分別是什麼
3). 再到project_dir/platform中repo sync
source code就會從server型態轉成git型態,此步不需要網路連線
server型態的存在project_dir/.repo/projects
裡面每一個.git都是一個git project
● git init 若加--mirror,出來的會是git server的型態
2012年5月25日 星期五
[Android] [JAVA] Intent介紹
一、介紹
Intent的功能類似網頁的超連結,使用者可以藉由超連結前往另一個頁面
Intent的動作是從目前的Activity執行另一個Activity。當目前的Activity執行另一個Activity,原來的Activity會進入休眠的狀態,然後將執行的工作權交給另一個Activity
二、intent流程
1). 定義intent
Intent intent=new Intent(動作, 內容)
Intent intent=new Intent(主程式類別.class, 自訂類別.class)
ex: Intent intent = new Intent(DeviceInfo.this, mService.class);
2). 決定誰要去用他
ex: startActivity(Intent)
三、使用intent傳遞資料的流程
1). 使用setClass方法指定執行類別
Intent intent = new Intent(DeviceInfo.this, mService.class);
2). 依照資料型別以Bundle物件打包
Bundle bundle=new Bundle();
bundle.putString("Name","Peter");
3). 利用intent的putExtras方法加入Bundle物件
intent.putExtras(bundle);
4). 使用startActivity方法執行intent
startActivity(intent);
四、取出intent資料的流程
1). 以getIntent()方法取得傳送的Intent
Intent intent=this.getIntent();
2). 利用intent的getExtras()方法,從intent中取得bundle物件
Bundle bundle=intent.getExtras();
3). 根據名稱取得bundle物件的資料
String Name=bundle.getString("Name");
Intent的功能類似網頁的超連結,使用者可以藉由超連結前往另一個頁面
Intent的動作是從目前的Activity執行另一個Activity。當目前的Activity執行另一個Activity,原來的Activity會進入休眠的狀態,然後將執行的工作權交給另一個Activity
二、intent流程
1). 定義intent
Intent intent=new Intent(動作, 內容)
Intent intent=new Intent(主程式類別.class, 自訂類別.class)
ex: Intent intent = new Intent(DeviceInfo.this, mService.class);
2). 決定誰要去用他
ex: startActivity(Intent)
三、使用intent傳遞資料的流程
1). 使用setClass方法指定執行類別
Intent intent = new Intent(DeviceInfo.this, mService.class);
2). 依照資料型別以Bundle物件打包
Bundle bundle=new Bundle();
bundle.putString("Name","Peter");
3). 利用intent的putExtras方法加入Bundle物件
intent.putExtras(bundle);
4). 使用startActivity方法執行intent
startActivity(intent);
四、取出intent資料的流程
1). 以getIntent()方法取得傳送的Intent
Intent intent=this.getIntent();
2). 利用intent的getExtras()方法,從intent中取得bundle物件
Bundle bundle=intent.getExtras();
3). 根據名稱取得bundle物件的資料
String Name=bundle.getString("Name");
2012年5月24日 星期四
[Example] [Android] [JAVA] Android APP應用2
按了button觸發啟動Service,顯示Toast並延遲兩秒啟動Notification
按下Notification進入到另外一個Activity
此可以列出device跟sw的資訊
參考文章:
[Android] [JAVA] Service & Notification
按了button觸發啟動Service,顯示Toast並延遲兩秒啟動Notification
按下Notification進入到另外一個Activity
1). 在Activity中設置點擊按鈕觸發的事件如下
宣告Intent所要執行的java檔(mService.java),並啟動Service
2). mService.java檔中宣告Service的lifecycle,分別是onCreate(),onStart(),onDestory
宣告handler,管理新開的thread,名為task的Runnable
宣告Runnable,執行所要做的Notification method
3). 撰寫開啟Notification Manager的method
設定要跳去哪一個Activity
參考[Android] [JAVA] Notification & PendingIntent
4). onCreate()繼承原有的onCreate()
onStart()中寫好延遲2秒去執行task,接著結束此Service,使lifecycle進入onDestory()
onDestory()繼承原有的onDestory()
5). Runnable中去執行Notification的method
//=============================================================
[string.xml]
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, DeviceInfo1!</string>
<string name="app_name">DeviceInfo2</string>
<string name="android_version">Android Version</string>
<string name="kernel_version">Kernel Version</string>
<string name="model_number">Model Number</string>
<string name="product_sku">Product Sku</string>
<string name="image_version">Image Version</string>
<string name="ec_version">EC Version</string>
<string name="cpu_vendor">CPU Vendor</string>
<string name="cpu_speed">CPU Speed</string>
<string name="cpu_version">CPU Version</string>
<string name="info_submit">Submit</string>
<string name="main_text">Please select the function as list. </string>
<string name="main_text_info1">Start service and notification bar after 2 senconds.
Then it will change activity to DeviceInfo.</string>
<string name="main_submit_info1">1. Device Info</string>
</resources>
//-------------------------------------------------------------------------------------------------------------
[info.xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/main_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.02"
android:orientation="vertical" >
<Button
android:id="@+id/main_submit_info1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/main_submit_info1" />
</LinearLayout>
<LinearLayout
android:layout_width="1028dp"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/main_text_info1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="@string/main_text_info1" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
package com.deviceinfo2;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class DeviceInfo2 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 找到元件資源
TextView text_main=(TextView)findViewById(R.id.main_text);
TextView text_main_info1=(TextView)findViewById(R.id.main_text_info1);
Button button_info1 = (Button) findViewById(R.id.main_submit_info1);
// 設定title字體大小
text_main.setTextSize(25);
text_main_info1.setTextSize(20);
// 設定按鍵觸發的method
button_info1.setOnClickListener(listDeviceInfo);
}
private Button.OnClickListener listDeviceInfo = new Button.OnClickListener() {
@Override
public void onClick(View v) {
// Toast
Toast.makeText(v.getContext(), "Please wait for notification about 2 senconds",
Toast.LENGTH_LONG).show();
// 宣告intent,並指定要啟動的class
Intent intent = new Intent(DeviceInfo2.this, mService.class);
// 以startservice方式啟動intent
startService(intent);
}
};
}
package com.deviceinfo2;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
public class mService extends Service {
private Handler handle = new Handler();
private int count=0;
@Override
public void onCreate() {
Log.d("TAG", "onCreate");
super.onCreate();
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
public void onStart(Intent intent, int startId) {
Log.d("TAG", "onStart");
handle.postDelayed(tasks, 2000);
// 停掉自己這個服務
mService.this.stopSelf();
}
private Runnable tasks = new Runnable() {
@Override
public void run() {
Log.d("TAG", "Runnable");
Log.d("RUN", "RunCount: " + Integer.toString(count++));
notification();
handle.removeCallbacks(tasks);
}
};
private void notification(){
Log.d("TAG", "Notification");
// 取得Notification服務
NotificationManager notificationManager = (NotificationManager)
getSystemService(NOTIFICATION_SERVICE);
// 設定當按下這個通知之後要執行的activity
Intent notifyIntent = new Intent(mService.this,
DeviceInfoActivity.class);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent appIntent = PendingIntent.getActivity(
mService.this, 0, notifyIntent, 0);
Notification notification = new Notification();
// 設定出現在狀態列的圖示
notification.icon = R.drawable.ic_launcher;
// 顯示在狀態列的文字
notification.tickerText = "notification on status bar.";
// Notification被點擊後,便消失
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// 會有通知預設的鈴聲、振動、light
notification.defaults |= Notification.DEFAULT_ALL;
// 設定通知的標題、內容
notification.setLatestEventInfo(mService.this, "DeviceInfo",
"Checkoout the infomation of device", appIntent);
// 送出Notification
notificationManager.notify(0, notification);
}
public void onDestroy() {
Log.d("TAG", "onDestory");
super.onDestroy();
}
}
按下Notification進入到另外一個Activity
1). 在Activity中設置點擊按鈕觸發的事件如下
宣告Intent所要執行的java檔(mService.java),並啟動Service
2). mService.java檔中宣告Service的lifecycle,分別是onCreate(),onStart(),onDestory
宣告handler,管理新開的thread,名為task的Runnable
宣告Runnable,執行所要做的Notification method
3). 撰寫開啟Notification Manager的method
設定要跳去哪一個Activity
參考[Android] [JAVA] Notification & PendingIntent
4). onCreate()繼承原有的onCreate()
onStart()中寫好延遲2秒去執行task,接著結束此Service,使lifecycle進入onDestory()
onDestory()繼承原有的onDestory()
5). Runnable中去執行Notification的method
//=============================================================
[string.xml]
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, DeviceInfo1!</string>
<string name="app_name">DeviceInfo2</string>
<string name="android_version">Android Version</string>
<string name="kernel_version">Kernel Version</string>
<string name="model_number">Model Number</string>
<string name="product_sku">Product Sku</string>
<string name="image_version">Image Version</string>
<string name="ec_version">EC Version</string>
<string name="cpu_vendor">CPU Vendor</string>
<string name="cpu_speed">CPU Speed</string>
<string name="cpu_version">CPU Version</string>
<string name="info_submit">Submit</string>
<string name="main_text">Please select the function as list. </string>
<string name="main_text_info1">Start service and notification bar after 2 senconds.
Then it will change activity to DeviceInfo.</string>
<string name="main_submit_info1">1. Device Info</string>
</resources>
//-------------------------------------------------------------------------------------------------------------
[info.xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="219dp"
android:layout_height="691dp"
android:orientation="vertical" >
<CheckBox
android:id="@+id/checkBox1_android_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/android_version" />
<CheckBox
android:id="@+id/checkBox2_kernel_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/kernel_version" />
<CheckBox
android:id="@+id/checkBox3_model_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/model_number" />
<CheckBox
android:id="@+id/checkBox4_product_sku"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/product_sku" />
<CheckBox
android:id="@+id/checkBox5_image_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/image_version" />
<CheckBox
android:id="@+id/checkBox6_ec_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/ec_version" />
<CheckBox
android:id="@+id/checkBox7_cpu_vendor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cpu_vendor" />
<CheckBox
android:id="@+id/checkBox8_cpu_speed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cpu_speed" />
<CheckBox
android:id="@+id/checkBox9_cpu_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cpu_version" />
<Button
android:id="@+id/submit"
android:layout_width="191dp"
android:layout_height="wrap_content"
android:text="@string/info_submit" />
<AbsoluteLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
</AbsoluteLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
<TextView
android:id="@+id/result"
android:layout_width="1015dp"
android:layout_height="match_parent"
android:text="" />
</LinearLayout>
</LinearLayout>
//-------------------------------------------------------------------------------------------------------------
[main.xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/main_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.02"
android:orientation="vertical" >
<Button
android:id="@+id/main_submit_info1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/main_submit_info1" />
</LinearLayout>
<LinearLayout
android:layout_width="1028dp"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/main_text_info1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="@string/main_text_info1" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
//-------------------------------------------------------------------------------------------------------------
[DeviceInfo2.java]
package com.deviceinfo2;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class DeviceInfo2 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 找到元件資源
TextView text_main=(TextView)findViewById(R.id.main_text);
TextView text_main_info1=(TextView)findViewById(R.id.main_text_info1);
Button button_info1 = (Button) findViewById(R.id.main_submit_info1);
// 設定title字體大小
text_main.setTextSize(25);
text_main_info1.setTextSize(20);
// 設定按鍵觸發的method
button_info1.setOnClickListener(listDeviceInfo);
}
private Button.OnClickListener listDeviceInfo = new Button.OnClickListener() {
@Override
public void onClick(View v) {
// Toast
Toast.makeText(v.getContext(), "Please wait for notification about 2 senconds",
Toast.LENGTH_LONG).show();
// 宣告intent,並指定要啟動的class
Intent intent = new Intent(DeviceInfo2.this, mService.class);
// 以startservice方式啟動intent
startService(intent);
}
};
}
//-------------------------------------------------------------------------------------------------------------
[mService.java]
package com.deviceinfo2;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
public class mService extends Service {
private Handler handle = new Handler();
private int count=0;
@Override
public void onCreate() {
Log.d("TAG", "onCreate");
super.onCreate();
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
public void onStart(Intent intent, int startId) {
Log.d("TAG", "onStart");
handle.postDelayed(tasks, 2000);
// 停掉自己這個服務
mService.this.stopSelf();
}
private Runnable tasks = new Runnable() {
@Override
public void run() {
Log.d("TAG", "Runnable");
Log.d("RUN", "RunCount: " + Integer.toString(count++));
notification();
handle.removeCallbacks(tasks);
}
};
private void notification(){
Log.d("TAG", "Notification");
// 取得Notification服務
NotificationManager notificationManager = (NotificationManager)
getSystemService(NOTIFICATION_SERVICE);
// 設定當按下這個通知之後要執行的activity
Intent notifyIntent = new Intent(mService.this,
DeviceInfoActivity.class);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent appIntent = PendingIntent.getActivity(
mService.this, 0, notifyIntent, 0);
Notification notification = new Notification();
// 設定出現在狀態列的圖示
notification.icon = R.drawable.ic_launcher;
// 顯示在狀態列的文字
notification.tickerText = "notification on status bar.";
// Notification被點擊後,便消失
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// 會有通知預設的鈴聲、振動、light
notification.defaults |= Notification.DEFAULT_ALL;
// 設定通知的標題、內容
notification.setLatestEventInfo(mService.this, "DeviceInfo",
"Checkoout the infomation of device", appIntent);
// 送出Notification
notificationManager.notify(0, notification);
}
public void onDestroy() {
Log.d("TAG", "onDestory");
super.onDestroy();
}
}
//-------------------------------------------------------------------------------------------------------------
[DeviceInfoActicity.java]
package com.deviceinfo2;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.util.Log;
import android.view.View;
import android.os.SystemProperties;
public class DeviceInfoActivity extends Activity {
private CheckBox checkBox1_android_version, checkBox2_kernel_version,
checkBox3_model_number, checkBox4_product_sku,
checkBox5_image_version, checkBox6_ec_version,
checkBox7_cpu_vendor, checkBox8_cpu_speed, checkBox9_cpu_version;
private Button button;
private TextView result;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.info);
// 取得資源類別中的介面元件
checkBox1_android_version = (CheckBox) findViewById(R.id.checkBox1_android_version);
checkBox2_kernel_version = (CheckBox) findViewById(R.id.checkBox2_kernel_version);
checkBox3_model_number = (CheckBox) findViewById(R.id.checkBox3_model_number);
checkBox4_product_sku = (CheckBox) findViewById(R.id.checkBox4_product_sku);
checkBox5_image_version = (CheckBox) findViewById(R.id.checkBox5_image_version);
checkBox6_ec_version= (CheckBox) findViewById(R.id.checkBox6_ec_version);
checkBox7_cpu_vendor = (CheckBox) findViewById(R.id.checkBox7_cpu_vendor);
checkBox8_cpu_speed = (CheckBox) findViewById(R.id.checkBox8_cpu_speed);
checkBox9_cpu_version = (CheckBox) findViewById(R.id.checkBox9_cpu_version);
button = (Button) findViewById(R.id.submit);
result = (TextView) findViewById(R.id.result);
// button元件要偵聽動作及觸發執行的方法名稱
button.setOnClickListener(listInfo);
}
private Button.OnClickListener listInfo = new Button.OnClickListener() {
@Override
public void onClick(View v) {
result.setText("");
result.setTextSize(20);
if (checkBox1_android_version.isChecked()) {
result.append("Android Version: "
+ SystemProperties.get("ro.build.version.release")
+ "\n\n");
}
if (checkBox2_kernel_version.isChecked()) {
Properties props = System.getProperties();
result.append("Kernel Version: "
+ props.getProperty("os.version") + "\n\n");
}
if (checkBox3_model_number.isChecked()) {
result.append("Model Number: "
+ SystemProperties.get("ro.product.model") + "\n\n");
}
if (checkBox4_product_sku.isChecked()) {
result.append("Product Sku: "
+ SystemProperties.get("ro.dinfo.sku") + "\n\n");
}
if (checkBox5_image_version.isChecked()) {
result.append("Image Version: "
+ SystemProperties.get("ro.build.display.id") + "\n\n");
}
if (checkBox6_ec_version.isChecked()) {
result.append("EC Version: " + getECVer() + "\n");
}
if (checkBox7_cpu_vendor.isChecked()) {
result.append("CPU Vendor: "
+ SystemProperties.get("ro.cpu.vendor") + "\n\n");
}
if (checkBox8_cpu_speed.isChecked()) {
result.append("CPU Speed: "
+ SystemProperties.get("ro.cpu.speed") + "\n\n");
}
if (checkBox9_cpu_version.isChecked()) {
result.append("CPU Version: "
+ SystemProperties.get("ro.cpu.version") + "\n\n");
}
}
};
private String getECVer() {
String str = "";
int len = 0;
char[] cbuf = new char[200];
try {
FileReader fn = new FileReader("EC路徑");
try {
while ((len = fn.read(cbuf, 0, cbuf.length)) >= 0) {
Log.d("***", str);
str += String.valueOf(cbuf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return str;
}
}
//-------------------------------------------------------------------------------------------------------------
[AndroidManifest.xml]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.deviceinfo2"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".DeviceInfo2"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="DeviceInfoActivity" >
</activity>
<service
android:name=".mService"
android:exported="true"
android:process=":remote" >
</service>
</application>
</manifest>
訂閱:
文章 (Atom)