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".

UI onClick callback via Layout.xml file

In my develop habit, I usually use the 'OnClickListener' to listen the button click.
In this topic, I will show you how to listen the button with xml layout file.

The sample code is following:

In MainActivity.java:
package com.example.onclicktest;

import com.example.onclicktest.R;
import android.app.Activity;
import android.widget.Toast;

public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  this.setContentView(R.layout.activity_main);
 }
 /**Called when button clicked*/
 public void onClick(View view){
  if(view.getId() == R.id.btn_test_click){
   Toast.makeText(this, "Button Clicked.", Toast.LENGTH_SHORT).show();
  }//if(view.getId() == R.id.btn_write_test_file)
 }
}

In avtivity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    
    <Button
        android:id="@+id/btn_test_click"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:text="TestBotton"
        android:onClick="onClick" />

</RelativeLayout>
The callback function has two condition:
1. the method must be 'public'.
2. the parameter of the method must only be 'View'.

2014年4月7日 星期一

Android R.java遺失補救方法

假設遇到R.java一直建置不起來的問題
以下是可以嘗試的設定:
1. 將專案清除(Eclipse→Project→Clean)
2. 自動建置方案(Eclipse→Project→Build Automatically)
3. 手動建置方案(Eclipse→Project→Build Project或專案點右鍵選Build Project[如果Build Automatically有選,專案上不會有該選項])
備註:R.java就是記錄layout相關配置參數的檔案,出現錯誤通常都是OO.xml內有錯誤,或是檔名用了大寫。

2014年4月2日 星期三

如何簡單移除UI layout中的Title bar?

以下為剛創立的Android Application project時所產生的基本layout 如下圖:
紅色框框所標註的地方即為Title bar部分,那麼要移除它該怎麼做呢?
很簡單,請依照下圖的指示選取到"AppTheme" => Theme(黑色背景) 或 Theme.Light(白色背景)
=> Theme.Black.NoTitleBar 或 Theme.Light.NoTitleBar 即可

以下為選擇Theme.Black.NoTitleBar的結果圖,惱人的Title Bar消失了~

Get Base Station Information

This topic guild how to get the sdcard information about the base station.

In BaseStationInfoHelper.java
package com.main;

import android.content.Context;
import android.telephony.CellLocation;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;

public class BaseStationInfoHelper {
 //android.permission.ACCESS_COARSE_LOCATION
 public static class BaseStationInfo {
        /** Country */
        public int mcc = -1;
        /** ISP */
        public int mnc = -1;
        /** Base Station Number*/
        public int lac = -1;
        /** Small Region Number */
        public int cid = -1;
    }
    public static BaseStationInfo getSimCardInfo(Context context) {
        final TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

        BaseStationInfo res = new BaseStationInfo();

        CellLocation clll = telephony.getCellLocation();
        if (clll == null) {
            return res;
        }

        if (clll instanceof GsmCellLocation) {
            GsmCellLocation gsm = (GsmCellLocation) clll;
            int lac = gsm.getLac();
            String mcc = telephony.getNetworkOperator().substring(0, 3);
            String mnc = telephony.getNetworkOperator().substring(3);

            res.cid = gsm.getCid();
            res.mcc = Integer.parseInt(mcc);
            res.mnc = Integer.parseInt(mnc);
            res.lac = lac;
        } else if (clll instanceof CdmaCellLocation) {
            CdmaCellLocation cdma = (CdmaCellLocation) clll;
            int lac = cdma.getNetworkId();
            String mcc = telephony.getNetworkOperator().substring(0, 3);
            String mnc = telephony.getNetworkOperator().substring(3);
            int cid = cdma.getBaseStationId();
            res.cid = cid;
            res.mcc = Integer.parseInt(mcc);
            res.mnc = Integer.parseInt(mnc);
            res.lac = lac;
        }
        return res;
    }
}

In MainActivity.java
package com.main;
import com.example.celllocation.R;
import com.main.BaseStationInfoHelper.BaseStationInfo;

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


public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  //
  TextView tv = (TextView) this.findViewById(R.id.textView1);
  //
  BaseStationInfo info = BaseStationInfoHelper.getSimCardInfo(this);
  String displayString = "";
  if(info != null){
   displayString += "Country mcc = " + info.mcc + "\r\n";
   displayString += "ISP mnc = " + info.mnc + "\r\n";
   displayString += "Base Station Number lac = " + info.lac + "\r\n";
   displayString += "Cell id = " + info.cid + "\r\n";
   //
   tv.setText(displayString);
  }
  else{
   tv.setText("Cannot get the base station information.");
  }
 }

}

In activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="TextView"
        android:textSize="20sp" />

</RelativeLayout>

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

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    <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年4月1日 星期二

Mobile network settings control

This topic is guilding Android developer to change and access mobile network settings in Android phone.

Non-Blocking TCP Server Sample

Non-Blocking TCP Server 模擬結果:
(1) 起始狀態

(2) 啟動Server

(3) Client端連線+發送訊息

(4) Client端離線
備註:當Server端收到Client端的訊息後,會發送回應給Client端


Sample code following:
package com.example.sample_niotcpserver;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;

import org.apache.http.conn.util.InetAddressUtils;

import com.example.sample_niotcpserver.R.id;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {
 //===== Debug Member Variables =====//
 private static String Class_TAG = "MainActivity";
 private static String Debug_TAG = "Debug Use";
 
 //===== UI Member Variables =====//
 private Button    mBtnBind, mBtnClose;
 private TextView  mTvHint, mTvPostMsg;
 private EditText  mEtPort;

 //===== nioTCP Member Variables =====//
 private ServerSocketChannel mServerSocketChannel = null;
 private Selector  mSelector = null;
 private String    mLocalIP = "0.0.0.0";
 private int       mLocalPort = 0;
 private boolean   isRunning = false; // Server open state. 
 
 // Record the remote socket, IP and port.
 private ArrayList<Socket> mSocketList;
 private ArrayList<String> mRemoteIPList;
 private ArrayList<Integer>mRemotePortList;
 
 // When the data can't write to client, need to record the answer data to wait for until it can write. 
 private String   mAnswerTemp = null;
 
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  mBtnBind = (Button) this.findViewById(R.id.xml_btn_bind);
  mBtnBind.setOnClickListener(this);
  mBtnBind.setEnabled(true);
  
  mBtnClose = (Button) this.findViewById(R.id.xml_btn_close);
  mBtnClose.setOnClickListener(this);
  mBtnClose.setEnabled(false);
  
  
  mTvHint = (TextView) this.findViewById(R.id.xml_tv_hint);
  mTvPostMsg = (TextView) this.findViewById(R.id.xml_tv_post_msg);
  
  mEtPort = (EditText) this.findViewById(R.id.xml_et_port);
  mEtPort.setText("8000");
  
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 // The button listener method. 
 @Override
 public void onClick(View v) {
  switch (v.getId()){
  case id.xml_btn_bind:
   // Close the bind button. 
   mBtnBind.setEnabled(false);
   
   mTvPostMsg.setText("");
   
   mSocketList = new ArrayList<Socket>();
   mSocketList.clear();
   
   mRemoteIPList = new ArrayList<String>();
   mRemoteIPList.clear();
   
   mRemotePortList = new ArrayList<Integer>();
   mRemotePortList.clear();
   
   mLocalIP = getLocalIP();
   mLocalPort = Integer.valueOf(mEtPort.getText().toString());
   
   mTvHint.setText("Starting server...");
   
   new Thread(nioTCPSetverThread).start();
   
   break;
  case id.xml_btn_close:
   // Close the close button. 
   mBtnClose.setEnabled(false);
   
   mTvHint.setText("Closing server...");
   
   // Change server state. 
   isRunning = false;
   
   mSelector.wakeup();

   break;
  }
 }

 private Runnable nioTCPSetverThread = new Runnable(){
  @Override
  public void run() {
   try { 
    // Open the seletor. 
    mSelector = Selector.open();
    
    try {
     // Open the local TCP server socket channel. 
     mServerSocketChannel = ServerSocketChannel.open();
     
     // Configure blocking mode: true(blocking) false(non-blocking). 
     mServerSocketChannel.configureBlocking(false);
     
     // Bind the server with lacal IP address and port. 
     mServerSocketChannel.socket().bind(new InetSocketAddress(mLocalIP, mLocalPort));
     
     // Server socket channel registers OP_ACCEPT command to server selector, and generate a SelectionKey. 
     mServerSocketChannel.register(mSelector, SelectionKey.OP_ACCEPT);
     
     // Change the button state. 
       runOnUiThread(new Runnable(){
      @Override
      public void run() {
       mBtnClose.setEnabled(true);
       mTvHint.setText("Server bind. IP: "+ mLocalIP + " Port: "+ mLocalPort);
     }});

     // Change server state. 
     isRunning = true;
     try {
      while(isRunning == true) {
       
       // Selector try to find the channel which has registered events. 
       mSelector.select();
       
       Set<SelectionKey> ServerChannelKeys = mSelector.selectedKeys();
          Iterator<SelectionKey> keyIter = ServerChannelKeys.iterator();
               
       while (keyIter.hasNext() && (mSelector.isOpen() == true)) {// If keyIter has any event, return true, or retun false. 
        
        // Extract the event into key from keyIter. 
        SelectionKey key = (SelectionKey) keyIter.next();
        
        // Remove keyIter when the key takes the event. 
        keyIter.remove();
        
        if (key.isAcceptable()) {// Accept connect. 
            
         // Accept the client socket from the server channel. 
         final SocketChannel ClientSocketChannel = ((ServerSocketChannel) key.channel()).accept();
         
         // Configure blocking mode: true(blocking) false(non-blocking). 
         ClientSocketChannel.configureBlocking(false);
         
         // Client socket channel registers "OP_READ" command to server selector. 
         ClientSocketChannel.register(mSelector, SelectionKey.OP_READ);
         
         // Add the connectable socket to socket list. 
         if (mSocketList.contains(ClientSocketChannel.socket()) == false) {
         
          mSocketList.add(ClientSocketChannel.socket());
          int socketIndex = mSocketList.indexOf(ClientSocketChannel.socket());
          mRemoteIPList.add(socketIndex, ClientSocketChannel.socket().getInetAddress().toString());
          mRemotePortList.add(socketIndex, ClientSocketChannel.socket().getPort());
         
         }
           
         // Post accept message to UI msg TextView. 
         runOnUiThread(new Runnable(){
         @Override
         public void run() { 
          mTvPostMsg.append("IP:"+ ClientSocketChannel.socket().getInetAddress().toString() + 
                        "(" + ClientSocketChannel.socket().getPort() + ")" + "is online.\r\n");
         }});
          }// if (key.isAcceptable())
        else if (key.isReadable()) {// Receive data. 
        
         ByteBuffer readBuffer = ByteBuffer.allocate(10 * 2048);
         final SocketChannel ClientSocketChannel = (SocketChannel) key.channel();
         int readBuffLen = ClientSocketChannel.read(readBuffer);
         if (readBuffLen < 0) {// Client side socket has disconnected. 
           
          // Remove the disconnectable socket from socket list. 
          if (mSocketList.contains(ClientSocketChannel.socket()) == true) {
             
           final int socketIndex = mSocketList.indexOf(ClientSocketChannel.socket());
           // Post close message to UI msg TextView. 
            runOnUiThread(new Runnable(){
            @Override
            public void run() {
             mTvPostMsg.append("IP:"+ mRemoteIPList.get(socketIndex) + 
                         "(" + mRemotePortList.get(socketIndex) + ")" + "is offline.\r\n");
             mRemoteIPList.remove(socketIndex);
               mRemotePortList.remove(socketIndex);
           }});
          
            mSocketList.remove(ClientSocketChannel.socket());
         
          }
 
          // Close the channel. 
          key.cancel();
          key.channel().close();
         
         } else {
          // Update the index of "position" and "limit", change position to "0"; limit to "valid data length". 
          readBuffer.flip();
          int ValidDataLen = readBuffer.limit();
          final byte[] ReceiveData = new byte[ValidDataLen];
          readBuffer.get(ReceiveData);
          // Post read message to UI msg TextView. 
          runOnUiThread(new Runnable(){
          @Override
          public void run() {
          String msg = new String(ReceiveData); 
          mTvPostMsg.append("IP:"+ ClientSocketChannel.socket().getInetAddress().toString() + 
                   "(" + ClientSocketChannel.socket().getPort() + ")" + "say: " + msg + "\r\n");
          }});
         
          // Try to answer the data to client. 
          String answer = "Server say: your message: \""+ 
                    (new String(ReceiveData)) +
                    "\"has received.\r\n";
          ByteBuffer writeBuffer = ByteBuffer.wrap(answer.getBytes());
          
          int writeLength = ((SocketChannel) key.channel()).write(writeBuffer);;
          
          if (writeLength == 0) {// The channel buffer is full. 
          
           // Record the answer data. 
           mAnswerTemp = answer;
          
           // Register the OP_WRITE command. 
           key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
           
          }
         }
        } // else if (key.isReadable())
        else if (key.isWritable()) {
           
         ByteBuffer writeBuffer = ByteBuffer.wrap(mAnswerTemp.getBytes());
         ((SocketChannel) key.channel()).write(writeBuffer);
         
         mAnswerTemp = null;
         
         // Cancel the OP_WRITE command. 
         key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
           
        } // else if (key.isWritable())
          
       }// while (keyIter.hasNext() && (mSelector.isOpen() == true))
      }// while(isRunning == true)
     } catch (IOException e) {
      e.printStackTrace();
      Log.v(Class_TAG, "nioTCPSetverThread");
      Log.e(Debug_TAG, "The selecter selects fail.");
     }
    } catch (IOException e) {
     e.printStackTrace();
     Log.v(Class_TAG, "nioTCPSetverThread");
     Log.e(Debug_TAG, "Server socket channel \"open\" or \"bind\" fail.");
    }
   } catch (IOException e) {
    e.printStackTrace();
    Log.v(Class_TAG, "nioTCPSetverThread");
    Log.e(Debug_TAG, "Selector open fail.");
   }
   
   try {
    // Close server channel and selector. 
    mServerSocketChannel.keyFor(mSelector).cancel();
    mServerSocketChannel.socket().close();
    mServerSocketChannel.close();
    mServerSocketChannel = null;
    mSelector.close();
    mSelector = null;
    
    // Change the button state. 
    runOnUiThread(new Runnable(){
     @Override
     public void run() {
      mBtnBind.setEnabled(true);
      mTvHint.setText("Server close.");
    }});
    
   } catch (IOException e) {
    e.printStackTrace();
    Log.v(Class_TAG, "nioTCPSetverThread");
    Log.e(Debug_TAG, "Close server socket channel or selector fail.");
   }
  }
 };
 
 private String getLocalIP() {
     try {
      String ipv4;
      ArrayList<NetworkInterface>  nilist = Collections.list(NetworkInterface.getNetworkInterfaces());
      for (NetworkInterface ni: nilist)
      {
       ArrayList<InetAddress>  ialist = Collections.list(ni.getInetAddresses());
       for (InetAddress address: ialist){
        if (!address.isLoopbackAddress() && InetAddressUtils.isIPv4Address(ipv4=address.getHostAddress())) 
        { 
         return ipv4;
        }
       }
      }
     } catch (SocketException ex) {
      Log.v(Class_TAG, "getLocalIP");
    Log.e(Debug_TAG, "Error: get local IP address.");
     }
     return null;
 }
 
}

activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/xml_tv_hint"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:hint="Hint"
        android:textColor="#000000"
        android:textSize="30sp" />

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Port number:"
            android:textColor="#000000"
            android:textSize="20sp" />

        <EditText
            android:id="@+id/xml_et_port"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10"
            android:hint="Enter the number 0~65535"
            android:textSize="20sp" >

            <requestFocus />
        </EditText>

        <Button
            android:id="@+id/xml_btn_bind"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0.54"
            android:text="Bind" />

        <Button
            android:id="@+id/xml_btn_close"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0.42"
            android:text="Close" />

    </LinearLayout>

    <TextView
        android:id="@+id/xml_tv_post_msg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="20dp" />

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

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <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_niotcpserver.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年3月25日 星期二

Change image when click the UI components

在按下按鈕時,時常都需要有兩張以上的圖片切換,而這篇文章,將紀錄以XML檔案的方式,按下按鈕時自動切換圖片。


首先,先將兩張圖片放置  (project)/res/drawable-mdpi/.. 的目錄下

btn.png

btn_down.png
 
 
接著在drawable-mdpi的目錄下按下右鍵 -> new Android XML,檔案名稱btn_selector,並選取selector,如下圖:
 
 
完成之後,會出現一個btn_selector.xml在drawable-mdpi目錄中,將以下程式碼貼入
 
btn_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/btn_down" />
    <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/btn_down" />
    <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/btn_down"/>
    <item android:drawable="@drawable/btn" />
</selector>
layout: activity_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" >

    <android.widget.Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/btn_selector" />

</LinearLayout>
avtivity: MainActivity.xml:
package com.main;
import com.example.android_ui_changeimagewhenclick.R;
import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
 }
}




2014年3月24日 星期一

Get Signal Strength - GSM and CDMA


MainActivity.java

package com.example.sample_phonesignalstrength;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.widget.TextView;

public class MainActivity extends Activity {
 private TextView textView1;
 private TelephonyManager mTelephonyManager;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  textView1 = (TextView) this.findViewById(R.id.textView1);
  
  mTelephonyManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
  mTelephonyManager.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
 } 
 private class MyPhoneStateListener extends PhoneStateListener{
  @Override
  public void onSignalStrengthsChanged(SignalStrength signalStrength) {
   super.onSignalStrengthsChanged(signalStrength);
   if(mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM){
    textView1.setText("GSM Strength"+signalStrength.getGsmSignalStrength());
   }
   else if(mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA){
    textView1.setText("CDMA Strength"+signalStrength.getCdmaDbm()+" dBm");
   }
   else{
    textView1.setText("Unknown PhoneType: "+mTelephonyManager.getPhoneType());
   }
  }
 }

}


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/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="TextView"
        android:textSize="30sp" />

</RelativeLayout>


2014年3月21日 星期五

Debug Log - print className, methodName and lineNumber

StackTraceElement t = Thread.currentThread().getStackTrace()[2];
//fullClassName contains the package name.
String fullClassName = t.getClassName();            
String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
String methodName = t.getMethodName();



int lineNumber = Thread.currentThread().getStackTrace()[2].getLineNumber();

Gallery use BaseAdapter

Gallery 模擬結果:
備註:向左向右均可滑動,滑動長度趨近於無限,大約可滑動2^30/選項次

MainActivity.java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Gallery;
import android.app.Activity;

public class MainActivity extends Activity implements OnItemClickListener
{
 private Gallery gvCam;
 private ImageAdapter mAdapter;
// private int[] image = {R.drawable.dafault_video, R.drawable.dafault_video, R.drawable.dafault_video, R.drawable.dafault_video};
 private String[] imgText = {"CH1", "CH2", "CH3", "CH4"};
 private ArrayList<Map<String,Object>> List = new ArrayList<Map<String,Object>>();
 @Override
 protected void onCreate(Bundle savedInstanceState) 
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  //insert the image or the bitmap or the text
  for(int i = 0;i<4;i++)
  {
    Map<String, Object> map = new HashMap();
//    map.put("CamImage", image[i]);
    map.put("CamName", imgText[i]);
    List.add(map);
  }
  //
  
  //initial UI
  gvCam = (Gallery) findViewById(R.id.xml_gyCam);
  mAdapter = new ImageAdapter(this ,
                         List,
                         R.layout.gallery_view,
                         new String[]{"CamImage", "CamName"},
                         new int[]{R.id.xml_ivCamImage,
                         R.id.xml_tvCamName});
  gvCam.setOnItemClickListener(this);
  gvCam.setAdapter(mAdapter);
  gvCam.setSelection((Integer.MAX_VALUE / 2) - (Integer.MAX_VALUE / 2) % List.size());
  //
 }
 
 
 
 @Override
 public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) 
 {
  // TODO Auto-generated method stub
  //check click item
  Log.e("GalleryExample","Your clicked item = "+position % List.size());
  //
 }
}

ImageAdapter.java
import java.util.ArrayList;
import java.util.Map;
import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class ImageAdapter extends BaseAdapter
{
    private LayoutInflater mInflater;  
    private ArrayList<Map<String, Object>> list;
    private int layoutID;
    private String flag[];  
    private int ItemIDs[];
 
    public ImageAdapter(Context context, ArrayList<Map<String, Object>> listItems, int layoutID, String flag[], int ItemIDs[]) 
    {     
        this.mInflater = LayoutInflater.from(context);  
        this.list = listItems;  
        this.layoutID = layoutID;  
        this.flag = flag;  
        this.ItemIDs = ItemIDs;
    }
 
 @Override
 public int getCount() 
 {
  // TODO Auto-generated method stub
  return Integer.MAX_VALUE;
 }

 @Override
 public Object getItem(int position) 
 {
  // TODO Auto-generated method stub
  if (position >= list.size()) 
  {
   position = position % list.size();
  }
  return position;
 }

 @Override
 public long getItemId(int position) 
 {
  // TODO Auto-generated method stub
  if (position >= list.size()) 
  {
   position = position % list.size();
  }
  return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) 
 {
  // TODO Auto-generated method stub
     if (position >= list.size()) 
     {
      position = position % list.size();
     }
        convertView = mInflater.inflate(layoutID, null); 
         for (int i = 0; i < flag.length; i++)
         {  
             if (convertView.findViewById(ItemIDs[i]) instanceof ImageView) 
             {  
                 ImageView iv = (ImageView) convertView.findViewById(ItemIDs[i]);
                 if(list.get(position).get(flag[i]) != null)
                 {
                  if(list.get(position).get(flag[i]) instanceof Bitmap)
                  {
                   iv.setImageBitmap((Bitmap) list.get(position).get(flag[i]));
                  }
                  else
                  {
                   iv.setImageResource((Integer) list.get(position).get(flag[i]));
                  }
                 }
             } 
             else if (convertView.findViewById(ItemIDs[i]) instanceof TextView) 
             {  
                 TextView tv = (TextView) convertView.findViewById(ItemIDs[i]);
                 tv.setText((String) list.get(position).get(flag[i]));
             }
         }
         return convertView;  
 }

}

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" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:orientation="vertical" >

        <Gallery
            android:id="@+id/xml_gyCam"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>

</RelativeLayout>

gallery_view.xml
<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"
    tools:context=".MainActivity" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:background="#000000" >

        <ImageView
            android:id="@+id/xml_ivCamImage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:layout_margin="10dp"
            android:src="@drawable/dafault_video" />

        <TextView
            android:id="@+id/xml_tvCamName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignRight="@+id/xml_ivCamImage"
            android:layout_alignTop="@+id/xml_ivCamImage"
            android:layout_marginRight="15dp"
            android:text="CH"
            android:textColor="#00FF54"
            android:textSize="10sp" />

    </RelativeLayout>

</LinearLayout>

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

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.gallery_example.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>

default_video.png

2014年3月17日 星期一

Non-Blocking UDP Client Sample

Non-Blocking UDP Client 模擬結果:
備註:輸入IP與Port後啟動Client,發送任意訊息後,Client會收到Server的回覆

MainActivity.java

Non-Blocking UDP Server Sample

Non-Blocking UDP Server 模擬結果:
備註:選定Port後啟動Server等待Client發送,收到Client訊息後,Server會回覆給Client

Non-Blocking UDP Server範例如下:

Get the version name and version code from AndroidMenifest.xml


通常我們都會在AndroidManifest.xml中,添加程式版本名稱和版本資訊,如下圖



In the MainActivity.java
 
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 //toast version
 try {
  int versionCode = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionCode;
  String versionName = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName;
  String toastString = versionCode + "/" + versionName;
  Toast.makeText(this, toastString, Toast.LENGTH_SHORT).show();
 } catch (NameNotFoundException e) {
  Toast.makeText(this, "NameNotFoundException", Toast.LENGTH_SHORT).show();
 }
 //
}

2014年3月10日 星期一

ListView use SimpleAdapter

JTimer

Ping

Ping指令使用方法如下:


// -c : the times for execute ping.
// -w : timeout to wait for ping response
Process p = Runtime.getRuntime().exec("ping -c 1 -w 10 www.google.com");
// send 1 packet to "www.google.com", waiting for response in 10 seconds.
if(p.waitFor() == 0) {//blocking 
 //ping succeeded
 ...   
}
else {
 //ping failed
 ...   
}


張貼範例

在撰寫文章時,有"撰寫"和"HTML"兩個選項,
選用HTML編輯,
張貼程式碼時,
依照下面格式張貼:

<pre class="brush: java;" name="code">
 ....撰寫程式碼
</pre>

輸出結果會如下:
class DemoApp {
    public static void main(String[] args) {
        Demo d = new Demo();
        d.printMessage();
    }
}
 
class Demo {
    String message = "NTUT 214 無敵";
     
    public void printMessage() {
        System.out.println(message);
    }
}
其中比較常用到的特殊符號要置換成別的字元:
'&' (ampersand) becomes '&amp;'
"' (double quote) becomes '&quot;' when ENT_NOQUOTES is not set.     
''' (single quote) becomes '&#039;' only when ENT_QUOTES is set.     
'<' (less than) becomes '&lt;'
'>' (greater than) becomes '&gt;'