基本上 Emulator /system 目錄是唯讀的,要解除其唯讀屬性可以透過下列方法:

adb remount
adb push libmy.so /system/lib

但是,在 Android 2.0 (Eclair) 以後,上面的作法會出現這樣的錯誤:
failed to copy 'hosts' to '/system/etc/hosts': No space left on device

failed to copy 'hosts' to '/system/etc/hosts': Out of memory

解決方法是,開啟模擬器時不要直接從 AVD Manager介面開,請下指令:
emulator -avd youravdname -partition-size 128
接著再對這個模擬器使用上面的方法就不會出現錯誤了。

深究其原因是 partition size 預設是 64MB。從 adb shell 用 df 指令觀察的結果,/system 在2.x 的 image mount 之後剩下空間是 0K。因此即使 remount 之後也無法寫入。

Filesystem           1k-blocks      Used Available Use% Mounted on
tmpfs                   128276         0    128276   0% /dev
tmpfs                   128276         0    128276   0% /mnt/asec
/dev/block/mtdblock0     77568     77568         0 100% /system
/dev/block/mtdblock1    129152     54988     74164  43% /data
/dev/block/mtdblock2     65536      1156     64380   2% /cache
/dev/block/vold/179:0
                       1044472     65608    978864   6% /mnt/sdcard
/dev/block/vold/179:0
                       1044472     65608    978864   6% /mnt/secure/asec

可惜AVD Manager 沒地方可以設定 partition size。所以目前只能在 console 以手動下指定開emulator囉。

有用過 Android adb shell 的人應該都知道這個 shell 的功能實在是食之無味棄之可惜的雞肋,一些常用的 linux command 幾乎都不支援,所以今天要介紹 busybox 這個工具,它的支援相當豐富,以下是執行的畫面:

$ busybox
BusyBox v1.16.0 (2010-01-27 20:00:00 CET) multi-call binary.
Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko
and others. Licensed under GPLv2.
See source distribution for full notice.

Usage: busybox [function] [arguments]...
   or: function [arguments]...

 BusyBox is a multi-call binary that combines many common Unix
 utilities into a single executable.  Most people will create a
 link to busybox for each function they wish to use and BusyBox
 will act like whatever it was invoked as.

Currently defined functions:
 [, [[, acpid, addgroup, adduser, adjtimex, ar, arp, arping, ash, awk,
 basename, beep, blkid, brctl, bunzip2, bzcat, bzip2, cal, cat, catv,
 chat, chattr, chgrp, chmod, chown, chpasswd, chpst, chroot, chrt, chvt,
 cksum, clear, cmp, comm, cp, cpio, crond, crontab, cryptpw, cttyhack,
 cut, date, dc, dd, deallocvt, delgroup, deluser, depmod, devmem, df,
 dhcprelay, diff, dirname, dmesg, dnsd, dnsdomainname, dos2unix, du,
 dumpkmap, dumpleases, echo, ed, egrep, eject, env, envdir, envuidgid,
 ether-wake, expand, expr, fakeidentd, false, fbset, fbsplash, fdflush,
 fdformat, fdisk, fgrep, find, findfs, flash_eraseall, flash_lock,
 flash_unlock, flashcp, fold, free, freeramdisk, fsck, fsck.minix,
 fsync, ftpd, ftpget, ftpput, fuser, getopt, getty, grep, gunzip, gzip,
 halt, hd, hdparm, head, hexdump, hostid, hostname, httpd, hush,
 hwclock, id, ifconfig, ifdown, ifenslave, ifplugd, ifup, inetd, init,
 inotifyd, insmod, install, ionice, ip, ipaddr, ipcalc, ipcrm, ipcs,
 iplink, iproute, iprule, iptunnel, kbd_mode, kill, killall, killall5,
 klogd, last, length, less, linux32, linux64, linuxrc, ln, loadfont,
 loadkmap, logger, login, logname, logread, losetup, lpd, lpq, lpr, ls,
 lsattr, lsmod, lspci, lsusb, lzmacat, lzop, lzopcat, makedevs,
 makemime, man, md5sum, mdev, mesg, microcom, mkdir, mkdosfs, mke2fs,
 mkfifo, mkfs.ext2, mkfs.minix, mkfs.vfat, mknod, mkpasswd, mkswap,
 mktemp, modprobe, more, mount, mountpoint, msh, mt, mv, nameif, nc,
 netstat, nice, nmeter, nohup, nslookup, ntpd, od, openvt, passwd,
 patch, pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill,
 popmaildir, poweroff, printenv, printf, ps, pscan, pwd, raidautorun,
 rdate, rdev, readahead, readlink, readprofile, realpath, reboot,
 reformime, renice, reset, resize, rm, rmdir, rmmod, route, rpm,
 rpm2cpio, rtcwake, run-parts, runlevel, runsv, runsvdir, rx, script,
 scriptreplay, sed, sendmail, seq, setarch, setconsole, setfont,
 setkeycodes, setlogcons, setsid, setuidgid, sh, sha1sum, sha256sum,
 sha512sum, showkey, slattach, sleep, softlimit, sort, split,
 start-stop-daemon, stat, strings, stty, su, sulogin, sum, sv, svlogd,
 swapoff, swapon, switch_root, sync, sysctl, syslogd, tac, tail, tar,
 taskset, tcpsvd, tee, telnet, telnetd, test, tftp, tftpd, time,
 timeout, top, touch, tr, traceroute, traceroute6, true, tty, ttysize,
 tunctl, tune2fs, udhcpc, udhcpd, udpsvd, umount, uname, uncompress,
 unexpand, uniq, unix2dos, unlzma, unlzop, unzip, uptime, usleep,
 uudecode, uuencode, vconfig, vi, vlock, volname, wall, watch, watchdog,
 wc, wget, which, who, whoami, xargs, yes, zcat, zcip

網路上已經有人幫忙把 busybox comile 成 android 可以用的 binary 檔了,有需要的人可以到這裡下載。

安裝 busybox 的步驟如下:

1. 建立安裝的目錄
adb shell mkdir /data/busybox

2. 複製 busybox 的 binary 檔到前一個步驟所建立的目錄:
adb push busybox /data/busybox/busybox

3. 開始安裝 busybox
adb shell
cd /data/busybox
./busybox --install. 
然後你可以檢查 /data/busybox 目錄,裡面應該有許多links.
但是預設的路徑並沒有被指定到 /data/busybox 為了讓用起來方便一點,可以修改 init.rc 多加進去 busybox 的安裝路徑,但如果是在 emulator 上 run 那就要去修改 ramdisk.img 才能達到一勞永逸的效果,否則每次開啟 emulator 後 init.rc 會被覆蓋掉。

修改 ramdisk.img 的步驟:

2.6內核開始,initrd.img採用cpio壓縮,ramdisk.img也一樣,使用gunzip解壓縮,然後再使用 cpio解包。

1. 將 ramdisk.img 從 android sdk 的 platroms\android-xx 目錄下複製到 linux 的作業環境其他目錄(如果已經在 linux 下則此一步驟省略)

2. 名稱改為 ramdisk.img.gz 並用 gunzip 解壓
mv ramdisk.img ramdisk.img.gz
gunzip ramdisk.img.gz

3. 新建一個文件夾 ramdisk 並進入此目錄後用 cpio 解開
mkdir ramdisk
cd ramdisk
cpio -i -F ../ramdisk.img
此時現在目錄已經是解開後的 ramdisk 檔案目錄了

4. 修改 init.rc 在 PATH 中加上 /data/busybox 路徑
## Global environment setup
##
env {
#其中, /data/busybox 為busybox安裝路徑,bash也是放在其中
PATH /data/busybox:/sbin:/system/sbin:/system/bin
...
}

5. 重新打包 ramdisk
find . | cpio -o -H newc -O ../new_ramdisk.img
gzip ../new_ramdisk.img

6. 把 new_ramdisk.img.gz 改成 ramdisk.img 並複製到 emulator 原來放置 ramdisk.img 的目錄覆蓋掉。大功告成...^^

應該很多人都知道 Android Dalvik 的 Maximum Heap Size 一般都是 16M,如果你的程式非常龐大可能這 16M 連跑都跑不起來,這時就要把 Heap Size 放寬才行,那麼該如何放寬限制呢?以下提供幾種方法把 heap size 從 16M 改成 64M:

1. 第一種方法是提供給想在實機上執行程式並且有能力修改 android framework 的朋友,直接到 android source code 目錄,打開 frameworks\base\core\jni\AndroidRuntime.cpp 找到有關建字"16m"這一行,改成"64m":

property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "64m");
重新產生 android image 就大功告成了。

2. 第二種方法是提供給想在 Emulator 上執行程式的朋友,請修改 config.ini 並加入這一行(註1):
vm.heapSize=64

3. 如果上述兩種辦法都不可行,試試看第三種方法,在 /data 目錄下產生 local.prop 並修改檔案內容,加入 dalvik.vm.heapsize=64m ,例如在 shell 模式下輸入:
cd /data
echo dalvik.vm.heapsize=64m > local.prop


註1:
如果在你是 Windows 底下開發的話,這個檔案一般會放在 "C:\Documents and Settings\YourAccount\.android\avd\YourAVD\"

其實 Android 製作 .apk 的 Private Key 是放在 \build\target\product\security 這個目錄下,這裡有好幾組 Key 而其主要的差異如下:

testkey -- a generic key for packages that do not otherwise specify a key.
platform -- a test key for packages that are part of the core platform.
shared -- a test key for things that are shared in the home/contacts process.
media -- a test key for packages that are part of the media/download system.

因此,如果你希望在 Android 建制 Framework 的過程中把你寫的 Application 改成你所指定的 Private Key ,基本上你需要改動的就是 testkey ,這個目錄下還有個 mkkey.sh 來協助你作這樣的工作, mkkey.sh 的內容如下:

if ["$1" == ""]; then
 echo "Create a test certificate key."
 echo "Usage: $0 NAME"
 echo "Will generate NAME.pk8 and NAME.x509.pem"
 echo "  /C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com"
 return
fi

openssl genrsa -3 -out $1.pem 2048

openssl req -new -x509 -key $1.pem -out $1.x509.pem -days 10000 \
    -subj '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'

openssl pkcs8 -in $1.pem -topk8 -outform DER -out $1.pk8 -nocrypt

說穿了,就是利用 openssl 來產生新的 Private Key,所以更改的方法很簡單,你可以把 openssl req -new ... 這一行改成你所需要的格式, 接著你只要執行 mkkey.sh 就可以產生新的 Private Key 了! 讚吧!

上一個方法是把 Private Key 跟 Certificate 直接換掉,如果你已經有現成的 Certificate 可以使用,令一個比較簡單的方法是更改 Android.mk 的設定,加一行:


LOCAL_CERTIFICATE := vendor/example/certs/app

如此,在 build system 的時候就可以使用指定的 Certificate 了。

可是這樣還離完美差一點點,你也許想把這個 Private Key 放到 Java 的 .keystore 檔案去,關於這個問題可以參考這篇文章http://www.agentbob.info/agentbob/79-AB.html,裡面有很詳細的說明。

OK, 到這裡為止一切就算是大功告成囉!

<有背景音樂,請打開喇叭,音樂檔很大,請耐心等候>

好久以前曾經寫過同事 Catherine 的婚禮紀錄,後來寫紀錄的網站關了,紀錄也就跟著消失了...嗚...好想哭啊...~>_<~ 現在只好重寫了, 話說美麗的 Catherine 小姐要結婚了,作為同事兼攝影社社長的我能給予最大的祝福,莫過是盡心幫她完成一個美好的婚禮紀錄了,看到她那幸福的模樣讓我也覺得很幸福。

在化妝室的時候幫 Catherine 拍了幾張,看得出來有一點小緊張喔!呵呵...







同事 Phil 的小孩來充當小花童,是個小帥哥呢!



小妹妹也很討喜...真可愛...呵呵...so cute...



新郎新娘進場囉!大家掌聲鼓勵鼓勵...





Catherine 發巧克力給大家,為了捕捉現場的氣氛我衝到人群裡近拍,差一點跌個四腳朝天,終於能體會新聞記者有多辛苦了



切蛋糕儀式...



終於到了大家期待的敬酒儀式,嘿嘿...有仇報仇啦...



「得即高歌失即休,多愁多恨亦悠悠;今朝有酒今朝醉,明日愁來明日愁」...大家一起舉杯祝福這對新人吧!乾啦!ㄏㄡ搭啦!



怎麼可以放過這個千載難逢的機會,讓這對新人來個「愛的親親」...嘻嘻...





哇...這個火辣的熱吻真是太激情了...可以確定這對新人增產報國的戰鬥力應該也不在我之下呢...呵呵...



透過酒杯人的表情變得很有趣,有哈哈鏡的效果...^^



這張也是,呵呵...只不過苦主變成新娘了...



新娘的飾品很美麗,我特地拍了幾張...



送客囉!呷甜甜生豪生...



終於結束了,有一個傳說是:「人一生下來就只有一半,於是每個人窮其一生都在找尋那失落的另一半」。如今你找到了妳的另一半,完美了他也完美了妳。看到你們幸福的模樣真替妳感到高興,恭喜ㄋㄟ!一定要永遠幸福下去喔!




Java for-each Loop


簡介

很多程式語言都有支援for-each這類的語法,簡單的說for-each語法就是當我們想要存取一個 Array 或 Collection 裡面所有的元時可以更方便、更有效率的語法。for-each 也有人稱為 enhanced for 或 for-in。
使用上要注意的事項有:
  • 只適用於 Java 5.0 以後的版本
  • 只適用於有 implement Iterable  的類別基本上 Array 與 Collection 類別都沒問題。
  • 只能存取裡面元素而不能置換掉它,記住,for-each 裡面的變數是 local 變數離開 for-each 之後就會消失。
  • 只能同時針對一個 Array 或 Collection 進行操作。
  • 只能同時針對一個元素操作。
  • 只能從頭開始訪問每個元素。


語法


底下針對 Array 與 Collection 分別說明:
for-each 迴圈for 迴圈
for (type var : arr) {
    body-of-loop
}
for (int i = 0; i < arr.length; i++) { 
    type var = arr[i];
    body-of-loop
}
for (type var : coll) {
    body-of-loop
}
for (Iterator<type> iter = coll.iterator(); iter.hasNext(); ) {
    type var = iter.next();
    body-of-loop
}

範例


這是一個使用 for-each 迴圈的程式碼:
double[] ar = {1.2, 3.0, 0.8};
int sum = 0;
for (double d : ar) {  // d gets successively each value in ar.
    sum += d;
}
這是一個使用一般 for 迴圈的程式碼:
double[] ar = {1.2, 3.0, 0.8};
int sum = 0;
for (int i = 0; i < ar.length; i++) {  // i indexes each element successively.
    sum += ar[i];
}

Resource Type Location Description XML Java
Id /res/values/any-file  
<resources>
<item type="id" name="text"/>
</resources>

 
Color /res/values/any-file Represents color identifiers pointing to color codes. These
resource IDs are exposed in R.java as R.color.*.
<resources>
    <color name="red">#f00</color>
    <color name="blue">#0000ff</color>
    <color name="green">#f0f0</color>
    <color name="main_back_ground_color">#ffffff00</color>
</resources>
<TextView android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textColor="@color/ red"
          android:text="Sample Text to Show Red Color"/>
int mainBackGroundColor
= activity.getResources.getColor(R.color.main_back_ground_color);
String /res/values/any-file Represents string resources. String resources
allow
Java-formatted strings and raw HTML in addition
to simple
strings. These resource IDs are exposed in
R.java as R.string.*.
<resources>
    <string name="simple_string">simple string</string>
    <string name="quoted_string">"quoted'string"</string>
    <string name="double_quoted_string">\"double quotes\"</string>
    <string name="java_format_string">
           hello %2$s java format string. %1$s again
     </string>
     <string name="tagged_string">
         Hello <b><i>Slanted Android</i></b>, You are bold.
     </string>
</resources>
 
 
<TextView android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textAlign="center"
          android:text="@string/tagged_string"/>
//Read a simple string and set it in a text view
String 
      simpleString = 
      activity.getString(R.string.simple_string);
textView.setText(simpleString);
//Read 
      a quoted string and set it in a text view
String quotedString = 
      activity.getString(R.string.quoted_string);
textView.setText(quotedString);
//Read 
      a double quoted string and set it in a text view
String 
      doubleQuotedString = 
      activity.getString(R.string.double_quoted_string);
textView.setText(doubleQuotedString);
//Read 
      a Java format string
String javaFormatString = 
      activity.getString(R.string.java_format_string);
//Convert the 
      formatted string by passing in arguments
String substitutedString = 
      String.format(javaFormatString, "Hello" , "Android");
//set the output 
      in a text view
textView.setText(substitutedString);
//Read an html 
      string from the resource and set it in a text view
String 
      htmlTaggedString = 
      activity.getString(R.string.tagged_string);
//Convert it to a text span 
      so that it can be set in a text view
//android.text.Html class allows 
      painting of "html" strings
//This is strictly an Android class and does 
      not support all html tags
Spanned textSpan = 
      android.text.Html.fromHtml(htmlTaggedString);
//Set it in a text 
      view
textView.setText(textSpan);
Dimension /res/values/any-file

Represents dimensions or sizes of various elements
or views in
Android. Supports pixels, inches, mil-
limeters, density-independent
pixels, and scale-
independent pixels. These resource IDs are
exposed
in R.java as R.dimen.*.

  • px: Pixels
  • in: Inches
  • mm: Millimeters
  • pt: Points
  • dp: Density-independent pixels based on a 160-dpi (pixel density per
    inch) screen
    (dimensions adjust to screen density)
  • sp: Scale-independent pixels (dimensions that allow for user sizing;
    helpful for use in
    fonts)


<resources>
    <dimen name="mysize_in_pixels">1px</dimen>
    <dimen name="mysize_in_dp">5dp</dimen>
    <dimen name="medium_size">100sp</dimen>
</resources>
 
 
<TextView android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textSize="@dimen/medium_size"/>
float dimen = 
      activity.getResources().getDimension(R.dimen.mysize_in_pixels);
Image /res/drawable/multiple-
files
Represents image resources. Supported images
include
.jpg, .gif, and .png. Each image is in a
separate file and gets its own
ID based on the file
name. These resource IDs are exposed in R.java
as
R.drawable.*. The image support also includes an
image type
called a stretchable image that allows
portions of an image to stretch
while other portions
of that image stay static.
<Button
      android:id="@+id/button1"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="Dial"
      android:background="@drawable/sample_image"
/>
//Call getDrawable to get the image
BitmapDrawable d = 
      activity.getResources().getDrawable(R.drawable.sample_image);
//You can 
      use the drawable then to set the 
      background
button.setBackgroundDrawable(d);
//or you can set the 
      background directly from the Resource 
      Id
button.setBackgroundResource(R.drawable.icon);
Color
Drawable
/res/values/any-file Represents rectangle of colors to be used as
view
backgrounds or general drawables like bitmaps.
You can use this
instead of specifying a single
colored bitmap as a background. In Java,
this is
equivalent to creating a colored rectangle and set-
ting it
as a background for a view.
The <drawable> value tag in the
values subdirec-
tory supports this. These resource IDs are
exposed
in R.java as R.drawable.*.
Android also supports rounded
rectangles and
gradient rectangles through XML files placed
in
/res/drawable with the root XML tag <shape>.
These resource
IDs are also exposed in R.java as
R.drawable.*. Each file name in this
case translates
to a unique drawable ID.
<resources>
    <drawable name="red_rectangle">#f00</drawable>
    <drawable name="blue_rectangle">#0000ff</drawable>
    <drawable name="green_rectangle">#f0f0</drawable>
</resources>

<TextView android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textAlign="center"
          android:background="@drawable/red_rectangle"/>
// Get a drawable
ColorDrawble redDrawable 
      =
(ColorDrawable)
activity.getResources().getDrawable(R.drawable.red_rectnagle);
//Set 
      it as a background to a text 
    view
textView.setBackground(redDrawable);
Shape /res/drawable/multiple-
files
 
<shape>
    <solid android:color="#f0600000"/>
    <stroke android:width="3dp" color="#ffff8080"/>
    <corners android:radius="13dp" />
    <padding android:left="10dp" android:top="10dp"
        android:right="10dp" android:bottom="10dp" />
</shape>
// Get a drawable
GradientDrawable roundedRectangle 
      =
(GradientDrawable)
activity.getResources().getDrawable(R.drawable.red_rectnagle);
//Set 
      it as a background to a text 
      view
textView.setBackground(roundedRectangle);
Layout /res/layout/any-file  
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView    android:id="@+id/text1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello"
    />
 <Button    android:id="@+id/b1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@+string/hello"
   />  
</LinearLayout>
public void onCreate(Bundle 
      savedInstanceState)
    
      {
        
      super.onCreate(savedInstanceState);
        
      setContentView(R.layout.main);
        
      TextView tv = 
      (TextView)this.findViewById(R.id.text1);
        
      tv.setText("Try this text instead");
    }
Arbitrary
XML Files
/res/xml/*.xml Android allows arbitrary XML files as resources.
These
files will be compiled by the AAPT com-
piler. These resource IDs are
exposed in R.java as
R.xml.*.
<rootelem1>
   <subelem1>
      Hello World from an xml sub element
   </subelem1>
</rootelem1>
Resources res = 
      activity.getResources();
XmlResourceParser xpp = 
      res.getXml(R.xml.test);
 
private String 
      getEventsFromAnXMLFile(Activity activity)
throws 
      XmlPullParserException, IOException
{
   StringBuffer sb = 
      new StringBuffer();
   Resources res = 
      activity.getResources();
   XmlResourceParser xpp = 
      res.getXml(R.xml.test);
  
   
      xpp.next();
   int eventType = 
      xpp.getEventType();
    while (eventType != 
      XmlPullParser.END_DOCUMENT)
    
      {
        if(eventType == 
      XmlPullParser.START_DOCUMENT)
        
      {
           
      sb.append("******Start 
      document");
        
      }
        else if(eventType == 
      XmlPullParser.START_TAG)
        
      {
           
      sb.append("\nStart tag 
      "+xpp.getName());
        
      }
        else if(eventType == 
      XmlPullParser.END_TAG)
        
      {
           
      sb.append("\nEnd tag 
      "+xpp.getName());
        
      }
        else if(eventType == 
      XmlPullParser.TEXT)
        
      {
           
      sb.append("\nText 
      "+xpp.getText());
        
      }
        eventType = 
      xpp.next();
    }//eof-while
    
      sb.append("\n******End document");
    return 
      sb.toString();
}//eof-function
Arbitrary Raw
Resources
/res/raw/*.* Android allows arbitrary noncompiled binary or
text
files under this directory. Each file gets a unique
resource
ID. These resource IDs are exposed in
R.java as R.raw.*.
String getStringFromRawFile(Activity 
      activity)
{
    Resources r = 
      activity.getResources();
    InputStream is = 
      r.openRawResource(R.raw.test);
    String myText = 
      convertStreamToString(is);
    
      is.close();
    return myText;
}
String 
      convertStreamToString(InputStream is)
{  
    
      ByteArrayOutputStream baos = new 
      ByteArrayOutputStream();
    int i = 
      is.read();
    while (i != -1)
    
      {
        
      baos.write(i);
        i = 
      baos.read();
    }
    return 
      baos.toString();
}
Arbitrary Raw
Assets
/assets/*.*/*.* Android allows arbitrary files in arbitrary
subdirec-
tories, starting at the /assets subdirectory. These
are
not really resources, but raw files. This directo-
ry, unlike the /res
subdirectory, allows an arbitrary
depth of subdirectories. These files
do not generate
any resource IDs. You have to use a relative
path
name starting at and excluding /assets.

 
//Note: Exceptions are not shown in the code
String 
      getStringFromAssetFile(Activity activity)
{
    
      AssetManager am = activity.getAssets();
    InputStream 
      is = am.open("test.txt");
    String s = 
      convertStreamToString(is);
    
      is.close();
    return s;
}