2014年9月17日 星期三

Use Fragment to generate Tab

MainActivity.java:
package com.main;

import com.example.tabfragment.R;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.app.ActionBar.Tab;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.util.Log;

public class MainActivity extends FragmentActivity {
    
 private MyPagerAdapter mMyPagerAdapter;
 private ViewPager mViewPager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        mMyPagerAdapter = new MyPagerAdapter(this.getSupportFragmentManager());
        
        final ActionBar actionBar = this.getActionBar();
        actionBar.setHomeButtonEnabled(false);
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        
        mViewPager = (ViewPager) this.findViewById(R.id.pager);
        mViewPager.setAdapter(mMyPagerAdapter);
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
   @Override
   public void onPageSelected(int position) {
    super.onPageSelected(position);
    actionBar.setSelectedNavigationItem(position);
   }
        }); // mViewPager.setOnPageChangeListener
        
        // generate tab items
        actionBar.addTab(
          actionBar
           .newTab()
           .setText("Frag1")
           .setTabListener(OnTabListener));
        actionBar.addTab(
          actionBar
           .newTab()
           .setText("Frag2")
           .setTabListener(OnTabListener));
        actionBar.addTab(
          actionBar
           .newTab()
           .setText("Frag3")
           .setTabListener(OnTabListener));
    }
    
    private class MyPagerAdapter extends FragmentPagerAdapter {

  public MyPagerAdapter(FragmentManager fm) {
   super(fm);
  }

  @Override
  public Fragment getItem(int position) {
   Log.d("Yeh", "FragmentPagerAdapter >> getItem item position="+position);
   
   Fragment fragment = new TabFragment();
   
   Bundle args = new Bundle();
   fragment.setArguments(args);
   args.putInt("position", position);
   
   return fragment;
  }

  @Override
  public int getCount() {
   // Number of items in the tab.
   return 3;
  }
     
    }
    
    private ActionBar.TabListener OnTabListener = new ActionBar.TabListener() {
  
  @Override
  public void onTabUnselected(Tab tab, FragmentTransaction ft) {
   // TODO Auto-generated method stub
   
  }
  
  @Override
  public void onTabSelected(Tab tab, FragmentTransaction ft) {
   mViewPager.setCurrentItem(tab.getPosition());
  }
  
  @Override
  public void onTabReselected(Tab tab, FragmentTransaction ft) {
   // TODO Auto-generated method stub
   
  }
 };
}
TabFragment.java
package com.main;

import com.example.tabfragment.R;

import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class TabFragment extends Fragment {
 
 
 int mPosition;
 
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  View rootView = inflater.inflate(R.layout.frag_view, container, false);
  TextView tv = (TextView) rootView.findViewById(R.id.textView);
  
  
  mPosition = this.getArguments().getInt("position", -1);
  Log.d("Yeh","Frag"+mPosition+" >> onCreateView");
  tv.setText("This is Fragment "+mPosition);
  
  
  return rootView;
 }

 @Override
 public void onDestroyView() {
  super.onDestroyView();
  Log.d("Yeh","Frag"+mPosition+" >> onDestroyView");
 }

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  Log.d("Yeh","Frag"+mPosition+" >> onCreate");
 }

 @Override
 public void onDestroy() {
  super.onDestroy();
  Log.d("Yeh","Frag"+mPosition+" >> onDestroy");
 }

 
}

activity_main.xml
<android.support.v4.view.ViewPager 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    
frag_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".DeviceFragment" >

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Tab1" />

</LinearLayout>
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.tabfragment"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity android:name="com.main.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

2014年9月1日 星期一

ADB Useful Command

# In the adb shell
dmesg -查看 Android Linux Kernel 運作訊息
ls -顯示檔案目錄
cd -進入目錄
rm -刪除檔案
mv -移動檔案
mkdir -產生目錄
rmdir -刪除目錄


# In the command line terminal
adb logcat -監控模擬器運作紀錄,以Ctrl + c 離開監控模式
adb bugreport -產生 adb 除錯報告
adb get-state - 獲得 adb 伺服器運作狀態
adb start-server -啟動 adb 伺服器
adb kill-server -關掉 adb 伺服器
adb forward tcp:6100 tcp:7100 -更改模擬器網路 TCP 通訊埠
adb shell ps -x -顯示所有正在執行的Process
adb version -顯示 adb 版本
adb help -顯示 adb 指令參數

2014年8月11日 星期一

Perform key event via ADB

使用Android手機時,都有鍵盤可以直接按按鈕,執行相對應的按鈕行為。


例如:
1. 按下 Return 鍵,Android系統就會返回上一頁。
2. 按下 Home 鍵,Android系統就會回到桌面。

用ADB輸入Command也可以達到相同的效果,Command格式如下:

adb shell intput keyevent KEYCODE

KEYCODE is specified to every key in the android keypad.

Eample:

adb shell intput keyevent 4         # for key return.

KEYCODE Table:


00 ->  "KEYCODE_UNKNOWN"
01 ->  "KEYCODE_MENU"
02 ->  "KEYCODE_SOFT_RIGHT"
03 ->  "KEYCODE_HOME"
04 ->  "KEYCODE_BACK"
05 ->  "KEYCODE_CALL"
06 ->  "KEYCODE_ENDCALL"
07 ->  "KEYCODE_0"
08 ->  "KEYCODE_1"
09 ->  "KEYCODE_2"
10 ->  "KEYCODE_3"
11 ->  "KEYCODE_4"
12 ->  "KEYCODE_5"
13 ->  "KEYCODE_6"
14 ->  "KEYCODE_7"
15 ->  "KEYCODE_8"
16 ->  "KEYCODE_9"
17 ->  "KEYCODE_STAR"
18 ->  "KEYCODE_POUND"
19 ->  "KEYCODE_DPAD_UP"
20 ->  "KEYCODE_DPAD_DOWN"
21 ->  "KEYCODE_DPAD_LEFT"
22 ->  "KEYCODE_DPAD_RIGHT"
23 ->  "KEYCODE_DPAD_CENTER"
24 ->  "KEYCODE_VOLUME_UP"
25 ->  "KEYCODE_VOLUME_DOWN"
26 ->  "KEYCODE_POWER"
27 ->  "KEYCODE_CAMERA"
28 ->  "KEYCODE_CLEAR"
29 ->  "KEYCODE_A"
30 ->  "KEYCODE_B"
31 ->  "KEYCODE_C"
32 ->  "KEYCODE_D"
33 ->  "KEYCODE_E"
34 ->  "KEYCODE_F"
35 ->  "KEYCODE_G"
36 ->  "KEYCODE_H"
37 ->  "KEYCODE_I"
38 ->  "KEYCODE_J"
39 ->  "KEYCODE_K"
40 ->  "KEYCODE_L"
41 ->  "KEYCODE_M"
42 ->  "KEYCODE_N"
43 ->  "KEYCODE_O"
44 ->  "KEYCODE_P"
45 ->  "KEYCODE_Q"
46 ->  "KEYCODE_R"
47 ->  "KEYCODE_S"
48 ->  "KEYCODE_T"
49 ->  "KEYCODE_U"
50 ->  "KEYCODE_V"
51 ->  "KEYCODE_W"
52 ->  "KEYCODE_X"
53 ->  "KEYCODE_Y"
54 ->  "KEYCODE_Z"
55 ->  "KEYCODE_COMMA"
56 ->  "KEYCODE_PERIOD"
57 ->  "KEYCODE_ALT_LEFT"
58 ->  "KEYCODE_ALT_RIGHT"
59 ->  "KEYCODE_SHIFT_LEFT"
60 ->  "KEYCODE_SHIFT_RIGHT"
61 ->  "KEYCODE_TAB"
62 ->  "KEYCODE_SPACE"
63 ->  "KEYCODE_SYM"
64 ->  "KEYCODE_EXPLORER"
65 ->  "KEYCODE_ENVELOPE"
66 ->  "KEYCODE_ENTER"
67 ->  "KEYCODE_DEL"
68 ->  "KEYCODE_GRAVE"
69 ->  "KEYCODE_MINUS"
70 ->  "KEYCODE_EQUALS"
71 ->  "KEYCODE_LEFT_BRACKET"
72 ->  "KEYCODE_RIGHT_BRACKET"
73 ->  "KEYCODE_BACKSLASH"
74 ->  "KEYCODE_SEMICOLON"
75 ->  "KEYCODE_APOSTROPHE"
76 ->  "KEYCODE_SLASH"
77 ->  "KEYCODE_AT"
78 ->  "KEYCODE_NUM"
79 ->  "KEYCODE_HEADSETHOOK"
80 ->  "KEYCODE_FOCUS"
81 ->  "KEYCODE_PLUS"
82 ->  "KEYCODE_MENU"
83 ->  "KEYCODE_NOTIFICATION"
84 ->  "KEYCODE_SEARCH"
85 ->  "TAG_LAST_KEYCODE"

2014年6月4日 星期三

TLS Socket Sample

Uses Permission:
android.permission.INTERNET


MainActivity.java:
package com.example.sample_sslsocket;

import java.io.IOException;
import java.net.UnknownHostException;
import java.security.cert.Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;



public class MainActivity extends Activity {
 private TextView textView;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  //get UI view
  textView = (TextView) this.findViewById(R.id.textView1);
  textView.setText("");
  //start SSL test sample.
  new Thread(new Runnable(){
   @Override
   public void run() {
    mainTest();
   }}).start();
  
 }
 private void TRACE(final String log){
  this.runOnUiThread(new Runnable(){
   @Override
   public void run() {
    Log.w("MainActivity", log);
    textView.append(log+"\r\n");   
   }}
  );
 }
 private void mainTest(){
  /**
  * 443 is the network port number used by the SSL https: URi scheme.
  */
  int port = 443;
  String hostname = "www.google.com";
  SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory();

TRACE("Creating a SSL Socket For "+hostname+" on port "+port);
  
  SSLSocket socket = null;
  try {
   socket = (SSLSocket) factory.createSocket(hostname, port);
  } catch (UnknownHostException e) {
TRACE("factory.createSocket >> UnknownHostException");
  } catch (IOException e) {
TRACE("factory.createSocket >> IOException");
  }
TRACE("factory.createSocket >> successful");
  /**
  * Starts an SSL handshake on this connection. Common reasons include a
  * need to use new encryption keys, to change cipher suites, or to
  * initiate a new session. To force complete reauthentication, the
  * current session could be invalidated before starting this handshake.
  * If data has already been sent on the connection, it continues to flow
  * during this handshake. When the handshake completes, this will be
  * signaled with an event. This method is synchronous for the initial
  * handshake on a connection and returns when the negotiated handshake
  * is complete. Some protocols may not support multiple handshakes on an
  * existing socket and may throw an IOException.
  */
  try {
   socket.startHandshake();
  } catch (IOException e) {
TRACE("socket.startHandshake >> IOException");
  }
TRACE("Handshaking Complete");
  
  /**
  * Retrieve the server's certificate chain
  *
  * Returns the identity of the peer which was established as part of
  * defining the session. Note: This method can be used only when using
  * certificate-based cipher suites; using it with non-certificate-based
  * cipher suites, such as Kerberos, will throw an
  * SSLPeerUnverifiedException.
  *
  *
  * Returns: an ordered array of peer certificates, with the peer's own
  * certificate first followed by any certificate authorities.
  */
  Certificate[] serverCerts = null;
  try {
   serverCerts = socket.getSession().getPeerCertificates();
  } catch (SSLPeerUnverifiedException e) {
TRACE(" socket.getSession().getPeerCertificates >> SSLPeerUnverifiedException");
  }
TRACE("Retreived Server's Certificate Chain");
TRACE(serverCerts.length + "Certifcates Found\n\n\n");
  for (int i = 0; i < serverCerts.length; i++) {
   Certificate myCert = serverCerts[i];
TRACE("====Certificate:" + (i+1) + "====");
TRACE("-Public Key-\n" + myCert.getPublicKey());
TRACE("-Certificate Type-\n " + myCert.getType());
TRACE("");
  }
  
  
  String packet = "GET / HTTP/1.1\r\n\r\n";
TRACE("sending packet = "+packet);
  try {
   socket.getOutputStream().write(packet.getBytes());
TRACE("sending packet succeeded");
  } catch (IOException e1) {
TRACE("socket.getOutputStream().write >> IOException");
  }
TRACE("recving packet");
  byte[] recv = new byte[10000];
  try {
   int recvLen = socket.getInputStream().read(recv, 0, recv.length);
   String str = new String(recv, 0, recvLen);
TRACE("recv packet = "+str);
  } catch (IOException e1) {
TRACE("socket.getInputStream().read >> IOException");
  }
  
  
  try {
TRACE("closing socket");
   socket.close();
TRACE("socket closed");
  } catch (IOException e) {
TRACE("socket.close >> IOException");
  }
 }
}


activity_main.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.sample_sslsocket.MainActivity"
    tools:ignore="MergeRootFrame" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <ScrollView
            android:id="@+id/scrollView1"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" >

            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="vertical" >

                <TextView
                    android:id="@+id/textView1"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:text="TextView" />

            </LinearLayout>
        </ScrollView>

    </LinearLayout>

</FrameLayout>

AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sample_sslsocket"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.sample_sslsocket.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


2014年4月16日 星期三

Notification Sample

Notification 模擬結果:
按下按鈕會發出通知和聲響,若程式在特殊手機上執行LED會亮綠燈

MainActivity.java
import android.media.AudioManager;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {
 Context mContext = this;
 EditText etTitle,etText;
 Button btNotify;
 @Override
 protected void onCreate(Bundle savedInstanceState) 
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mContext = this;
  etTitle  = (EditText) findViewById(R.id.xml_etTitle);
  etText  = (EditText) findViewById(R.id.xml_etText);
  btNotify = (Button) findViewById(R.id.xml_btSend);
 }
 
 public void onClick(View view)
 {
  if(view.getId()==R.id.xml_btSend)
  {
   if(etTitle.length()==0 || etText.length()==0)
    return;
   //initial notification manager and audio manager
   NotificationManager nm = (NotificationManager) mContext.getSystemService(android.content.Context.NOTIFICATION_SERVICE);
   NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
   AudioManager mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
   //
   int ring_mode = mAudioManager.getRingerMode();
   int DrawableId = android.R.drawable.sym_call_missed;
   String Title = etTitle.getText().toString();
   String Text = etText.getText().toString();
   //set the activity of the trigger
   Intent intent_missCall= new Intent(mContext, MainActivity.class);
   intent_missCall.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
   intent_missCall.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   PendingIntent pIntent = PendingIntent.getActivity(mContext, 0,
      intent_missCall, PendingIntent.FLAG_UPDATE_CURRENT);
   //
   boolean AutoCancel = true;
   boolean OnGoing = false;
   //light the LED. color is green.(It's not action on every cellphone)
   builder.build().ledARGB = 0x00FF00;
   builder.build().ledOnMS = 100;
   builder.build().ledOffMS = 100;
   builder.build().flags = Notification.FLAG_SHOW_LIGHTS; 
   //
   //change the notify effect by checking the ring mode
   if(ring_mode == AudioManager.RINGER_MODE_NORMAL ) {
     Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
     builder.setSound(notification);
   }
   if(ring_mode == AudioManager.RINGER_MODE_VIBRATE) {
     builder.setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 });
   }
   //
   //set the notification and notify
   builder.setTicker(Title)
   .setContentTitle(Title)
   .setContentText(Text)
   .setSmallIcon(DrawableId)
   .setAutoCancel(AutoCancel)
   .setOngoing(OnGoing)
   .setContentIntent(pIntent);
   nm.notify(0, builder.build());
   //
  }
 }
}

activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/xml_btSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/editText1"
        android:layout_marginTop="90dp"
        android:onClick="onClick"
        android:text="Notify" />

    <EditText
        android:id="@+id/xml_etTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:ems="10" >

        <requestFocus />
    </EditText>

    <EditText
        android:id="@+id/xml_etText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/xml_tvNotifyText"
        android:layout_alignParentRight="true"
        android:ems="10" />

    <TextView
        android:id="@+id/xml_tvNotifyText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/xml_tvNotifyTitle"
        android:layout_below="@+id/xml_etTitle"
        android:layout_marginTop="16dp"
        android:text="NotifyText:"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/xml_tvNotifyTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/xml_etTitle"
        android:layout_alignParentLeft="true"
        android:text="Notify Title:"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.notify_test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />
    <uses-permission android:name="android.permission.VIBRATE"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.notify_test.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

2014年4月10日 星期四

GetScreenWidth&Height

獲取Nexus7螢幕尺寸模擬結果:

MainActivity.java
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity 
{
 int width,height,statusBarHight = 0;
 TextView tvHeight,tvWidth;
 @Override
 protected void onCreate(Bundle savedInstanceState) 
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  //get the screen width and height
  DisplayMetrics dm = new DisplayMetrics();
  getWindowManager().getDefaultDisplay().getMetrics(dm);
  //calculate status bar height
  int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
  if (resourceId > 0)
   statusBarHight = getResources().getDimensionPixelSize(resourceId);
  
        int vWidth = dm.widthPixels;
        int vHeight = dm.heightPixels - statusBarHight;
        if(vWidth < vHeight) 
        {
         width = vWidth;
         height = vHeight;
        } 
        else 
        {
         width = vHeight;
         height = vWidth;
        }
        //show the screen width and height 
        tvHeight = (TextView) this.findViewById(R.id.xml_tvHeight);
        tvWidth = (TextView) this.findViewById(R.id.xml_tvWidth);
        tvHeight.setText("Height: "+height);
        tvWidth.setText("Width: "+width);
 }
}

activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/xml_tvHeight"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignRight="@+id/xml_tvWidth"
        android:layout_marginTop="172dp"
        android:text="Height: "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/xml_tvWidth"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/xml_tvHeight"
        android:layout_alignParentLeft="true"
        android:layout_marginBottom="29dp"
        android:layout_marginLeft="70dp"
        android:text="Width: "
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

2014年4月9日 星期三

Get real external storage path for lower Android 4.4

The new Android version has emulated sdcard.
We usually get external storage path by  API - 'Environment.getExternalStorageDirectory();' .
Sometimes, the API apply a internal storage that means it's emulated external storage.
So I find a way to get real external storage on the Internet, the full code is following:
/**
 * Get real external storage  path.
 * @return Real external storage path or null for no external storage.
 */
private static String getSdcardPath(){
 File file = new File("/system/etc/vold.fstab");
        FileReader fr = null;
        BufferedReader br = null;
        try {
            fr = new FileReader(file);
            if (fr != null) {
                br = new BufferedReader(fr);
                String s = br.readLine();
                while (s != null) {
                    if (s.startsWith("dev_mount")) {
                        String[] tokens = s.split("\\s");
                        String path = tokens[2]; //mount_point
                        br.close();
                        fr.close();
                        return path;
                    }
                    s = br.readLine();
                }
                br.close();
                fr.close();
            }//if (fr != null)
        } 
        catch (FileNotFoundException e) {} 
        catch (IOException e) {} 
        return null;
}
If you want to read file from external storage, remember to add user-permission "android.permission.READ_EXTERNAL_STORAGE".
For writing file, adding user-permission "android.permission.WRITE_EXTERNAL_STORAGE".

If you add "android.permission.WRITE_EXTERNAL_STORAGE", it explicitly add "android.permission.READ_EXTERNAL_STORAGE".