2013年8月2日 星期五

$nice man true love

在linux下 $ nice man true love No manual entry for love. 蠻有趣的XD nice: run a program with modified scheduling priority man: format and display the on-line manual pages ture: do nothing, successfully

2013年7月13日 星期六

Android save file to external storage

在External storage下開一個app專屬資料夾並且儲存檔案:

首先建立資料夾

final String writeDir= Environment.getExternalStorageDirectory()+ "/YourAppName/log/"; File dir = new File(writeDir); dir.mkdirs();
case1. 寫入文字檔案
mFileWriter = new FileWriter(writeDir+ "/logFile.txt", true); mFileWriter.write("yayahihihello"); mFileWriter.flush(); mFileWriter.close();

case2. 使用FileOutputStream儲存圖檔


//這個路徑可以被內建的gallery app 找到 final String writePath = Environment.getExternalStorageDirectory()+"/Pictures/YourAPPName"; Bitmap bitmap = (拿到你要存的bitmap); //將Bitmap轉成bytes才能儲存 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes); //使用FileOutputStream儲存bytes FileOutputStream fo = new FileOutputStream(f); fo.write(bytes.toByteArray()); bytes.close(); fo.close();

接著最後儲存的檔案編號繼續下去


String fileName,fileNameBase = "CanvasNetPic" ; int counter =1; fileName = "CanvasNetPic0"; File f = new File(savePath+"/"+fileName+".jpg"); while(f.exists()) { fileName = fileNameBase + Integer.toString(counter); f = new File(savePath+"/"+fileName+".jpg"); counter++; }



通知Android media scanner file system被改變過, 這樣新儲存的檔案才會馬上被gallery或其他content reader讀到


sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));

但這樣子media scanner會去重新掃描整個ExternalStroage, 或是檔案很多或是device比較慢的話要掃很久, 會導致打開gallery以後要放著一段時間新儲存的檔案才會出來

只掃描儲存檔案的資料夾可以大幅減掃掃描時間:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ "你的儲存路徑")));

2013年7月6日 星期六

Android http post (file) + responsed json handling

以下code包含:建立一個連線, post file or value, 處理回傳的json 首先是http request post的部分: //設定連線timeout HttpParams httpParameters = new BasicHttpParams(); int timeoutConnection = 5000; HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); //設定等待socket回傳timeout int timeoutSocket = 8000; HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); HttpClient httpclient = new DefaultHttpClient(httpParameters); httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); //建立post request HttpPost httppost = new HttpPost("http://xxxxx.php"); //要傳送的檔案 File file = new File(filePath); //android post傳送檔案內建好像只提供自己建立http header然後再手動在content中包入檔案的方式,頗麻煩,這邊使用apache的library來加入檔案. MultipartEntity mpEntity = new MultipartEntity(); ContentBody cbFile = new FileBody(file); mpEntity.addPart("File", cbFile); httppost.setEntity(mpEntity); //執行 HttpResponse response = httpclient.execute(httppost); 如果沒有要傳送檔案的話可以這樣: List nameValuePairs = new ArrayList(2); nameValuePairs.add(new BasicNameValuePair("id", "12345")); nameValuePairs.add(new BasicNameValuePair("stringdata", "AndDev is Cool!")); httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); 接著拿到response以後做json處理. BasicResponseHandler handler = new BasicResponseHandler(); String responseString = handler.handleResponse(response); //將回應的string parse成json 物件 JSONObject json = new JSONObject(responseString); //取值範例 if(json.has("Status")) { String status = json.getString("Status"); }

2013年7月1日 星期一

Ios animation sample (CABasicAnimation)

To start animation:

ImageView wave1,wave2 //basic sample CABasicAnimation *wave1ScaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; wave1ScaleAnimation.toValue = [NSNumber numberWithFloat:1.5]; wave1ScaleAnimation.duration = 1; //infinity loop wave1ScaleAnimation.repeatCount = HUGE_VALF; //totally 2 second per cycle wave1ScaleAnimation.autoreverses = YES; wave1ScaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; [wave1.layer addAnimation:wave1ScaleAnimation forKey:@"RecordingAnimation"]; //group animation sample CABasicAnimation *wave2ScaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; wave2ScaleAnimation.toValue = [NSNumber numberWithFloat:2.1]; CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; alphaAnimation.toValue = [NSNumber numberWithFloat:0.0]; //begin time and duration relative to group alphaAnimation.beginTime = 0.5; alphaAnimation.duration =0.5; CAAnimationGroup *group = [CAAnimationGroup animation]; //use CACurrentMediaTime() to get absolute begin Time group.beginTime = CACurrentMediaTime()+ 1; group.duration = 1; group.repeatCount = HUGE_VALF; group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; group.animations = [NSArray arrayWithObjects:wave2ScaleAnimation, alphaAnimation,nil]; [wave2.layer addAnimation:group forKey:@"groupAnimation"];

To stop animation:

[wave1.layer removeAllAnimations]; [wave2.layer removeAnimationForKey:@"groupAnimation"];

[CABasicAnimation animationWithKeyPath:@"transform.scale"]中的keyPath如下表:


另一種較舊的animation用法:

[UIView animateWithDuration:0.5 delay:1.0 options: UIViewAnimationCurveEaseOut animations:^{ self.basketTop.frame = basketTopFrame; self.basketBottom.frame = basketBottomFrame; } completion:^(BOOL finished){ NSLog(@"Done!"); }]; }

順便附上很方便的alpha transition animation:

[UIView transitionWithView:myImageView duration:0.25f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ [rotateView setImage:[UIImage imageNamed:@"record_rotate_red.png"]]; } completion:nil];

2013年6月21日 星期五

Android NDK 使用C++與 STL(Standard Template Library)

最近有一份使用STL的c++ code要port到android上面, 最後決定採用NDK而不改寫成java

一點點筆記:

就算code都是用c style寫的, 但只要用了STL之類的c++ library就要視為c++處理, 以下是編譯步驟.

1. 和往常一樣在project之中建立jni資料夾, 關鍵是資料夾中的c++檔案要以.cpp附檔名,

如此一來使用ndk-build script的時候就會自動選用c++的compiler來編譯. 不然build的時候會先遇到找不到header的error. 因為c++ compiler和c compiler 的搜尋header路徑不同.

2. 建立Android.mk在jni資料夾中, 內容大概像這樣

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := temp_jni LOCAL_SRC_FILES := test.cpp LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS) -> 開始一段全新乾淨的編譯

LOCAL_MODULE := temp_jni -> 指定編出來的library名稱, 這樣會編出 libtemp_jni.so

LOCAL_SRC_FILES := test.cpp -> 當然就是要編譯的source file了

LOCAL_LDLIBS := -llog -> 在這邊我們多link一個log的library之後debug用,不是必須但是很方便,等等介紹怎麼用.

include $(BUILD_SHARED_LIBRARY) -> 最後呼叫Android負責編譯shared library的script開始編譯

3(Optional). 使用liblog.so的print log debug 功能: (即上述LOCAL_LDLIBS := -llog)

在.cpp source file內加入以下內容


#define LOG_TAG "TEST_JNI" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)


之後只要在c++ Code中使用 LOGE("hello world");就可以像在android java program 中使用Log.e(LOG_TAG,"hello world")一樣印log在logcat中! 同理LOGI,LOGV等.


4.在jni資料夾下建立一個Application.mk檔案, 內容如下面一行

APP_STL := stlport_static

目的是這樣的, 因為Android NDK預設只會link一份最簡陋的STL, 但其實NDK中有還是有放一份完整的STL, 所以要告訴編譯器編譯時去使用這份完整的STL.

附帶一提APP_STL的值有以下四種:
system -->預設,簡陋
stlport_static
stlport_shared
gnustl_static

5. 寫一個使用STL的 .cpp file吧!
像這樣

#include <vector> #include <jni.h> #include <android/log.h> //見第3點 #define LOG_TAG "FEATRUEEXTRACTION" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) using namespace std; void runTest(const char* in) { vector<const char*> tt; tt.push_back("hello"); tt.push_back("world"); tt.push_back(in); LOGE(tt[2]);//會在logcat中印出從java端呼叫JNITestFunction時所傳入的String } extern "C"{ //注意 void Java_com_example_temp_MainActivity_JNITestFunction( JNIEnv* env, jobject thiz , jstring inString) { //should be released const char *in = (env)->GetStringUTFChars(inString,0); runTest(in); } } //注意


有兩點要特別注意:

一,一定要用extren "C"{}包住jni function,不然runtime會找不到這個jni function.

二,使用C++的時候jni.h的function會被一層wrapper包住,所以呼叫的方法和使用c的時候不一樣,

如上面使用GetStringUTFChars function 在c的版本會是這樣使用:
(*env)->GetStringUTFChars(env,inString,0); 

細節只要去NDK的platforms/android-(隨便一個版本)/arch-arm/usr/included/jni.h中看就瞭解.

6.java的部分大概長這樣
package com.example.temp; import android.os.Bundle; import android.app.Activity; import android.view.Menu; public class MainActivity extends Activity { public static native void JNITestFunction(String inString); static { System.loadLibrary("temp_jni"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); JNITestFunction("cyy"); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
7.切換目錄到jni/下面使用 <NDKROOT>/ndk-build 指令.

這樣會編出shared library. 這些編出來的library之後會被包進.apk中一併燒進手機中

8. 在Eclipse中像平常一樣執行這個app, 搞定收工!



2013年6月18日 星期二

ios project中使用STL(Standard Template Library)

ios中使用c: 直接用

ios中使用c++,STL:

因為STL是c++的library所以直接編譯含有STL的code會發生找不到header之類的問題.

古早一點版本的x code似乎需要手動去設定編譯使使用c++的compiler.

但現在只要將reference到 c++ code的檔案副檔名從.m改成.mm, 則編譯的時候會自動使用c++ compiler來處理,並且STL header等c++的header也會被加入搜尋路徑, 相當方便!

舉個例子, 我有foo.h foo.cpp main.m,

則直接在main.m中 import foo.h並且把檔名改成main.mm就搞定了!




2013年6月15日 星期六

Android app的status bar高度

status bar就是android手機最上面那一條有顯示電量與時間的bar,

為了寫一個可以在不同size螢幕上面都能按照同比例顯示view的layout需要得到status bar的高度來幫助計算.

一開始google都是找到類似如下的答案

Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight= rectgle.top;
int contentViewTop= 
    window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight= contentViewTop - StatusBarHeight;

   Log.i("*** Jorgesys :: ", "StatusBar Height= " + StatusBarHeight + " , TitleBar Height = " + TitleBarHeight);
( from http://stackoverflow.com/questions/3355367/height-of-statusbar/3356263#3356263)

雖然這樣可以拿到我要的status bar高度, 但是有一個大缺點, 就是這個方法要等到整個畫面被畫出來以後才根據畫出來的結果來計算status bar高度.

偏偏android的life cycle中, 畫面被畫出來是在onCreate(), onResume(), onRestart()等步驟之後,

所以在這些override function內是不能拿到正確的status bar heigth的!!

很不方便.

直到最近偶然發現了更好的方法:

public int getStatusBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; }

from http://mrtn.me/blog/2012/03/17/get-the-height-of-the-status-bar-in-android/

真是太猛了這樣一來就可以在onCreate()等處得到status bar的高度,

Comments中還有提到

<sdk-root>/platforms/android-<version>/data/res/values/dimens.xml

內還有一堆參數也都拿的到啊!!!