2010年12月7日 星期二

GAE/J - Appstats(測量App的效能)

Appstats主要是用來測量App在Google App Engine上的效能表現。做法很簡單只要掛上Google提供的Appstats的Filter即可使用。
  • 在web.xml中加入
<filter>
        <filter-name>appstats</filter-name>
        <filter-class>com.google.appengine.tools.appstats.AppstatsFilter</filter-class>
        <init-param>
            <param-name>logMessage</param-name>
            <param-value>Appstats available: /appstats/details?time={ID}</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>appstats</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

  • 連線到http://xxx.appspot.com/appstats/

  • 限制只有管理者可以連線,需在web.xml加入以下的code
<servlet>
        <servlet-name>appstats</servlet-name>
        <servlet-class>com.google.appengine.tools.appstats.AppstatsServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>appstats</servlet-name>
        <url-pattern>/appstats/*</url-pattern>
    </servlet-mapping>

    <security-constraint>
        <web-resource-collection>
            <url-pattern>/appstats/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>


2010年12月6日 星期一

Tomcat中限制只有特定IP可以連線

修改在Tomcat目錄下conf\Catalina\localhost\yourApp.xml中的內容:

 以下設定只允許本端電腦和192.168.1.*這個子網路可以進行連線
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/yourApp">
   <Valve className="org.apache.catalina.valves.RemoteHostValve" allow="127.0.0.1,192.168.1.*"/>
</Context>


2010年7月27日 星期二

Android學習筆記 - 模擬器快速鍵

Home鍵 - Home

Back鍵 - Esc

Menu鍵 - F2

撥號鍵 - F3

掛斷鍵 - F4

搜尋鍵 - F5

網絡開關 - F8

旋轉螢幕 - Ctrl+F11


2010年7月14日 星期三

Android學習筆記 - WIFI控制(開啟、關閉)

1. WIFI的控制,主要是透過WifiManager來管理WIFI。

2.WifiManagerExample.java
package tw.nicky.WifiManagerExample;
import android.app.Activity;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class WifiManagerExample extends Activity {
 private WifiManager wiFiManager;
 private Button turnOnWifiButn;
 private Button turnOffWifiButn;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  // 取得WifiManager
  wiFiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
  turnOnWifiButn = (Button) findViewById(R.id.turnOnWifiButn);
  turnOffWifiButn = (Button) findViewById(R.id.turnOffWifiButn);

  // 開啟wifi
  turnOnWifiButn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    //若wifi狀態為關閉則將它開啟
    if (!wiFiManager.isWifiEnabled()) {
     wiFiManager.setWifiEnabled(true);
    }
   }
  });

  // 關閉wifi
  turnOffWifiButn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    //若wifi狀態為開啟則將它關閉
    if (wiFiManager.isWifiEnabled()) {
     wiFiManager.setWifiEnabled(false);
    }
   }
  });
 }
}

3. main.xml(Layout)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<Button 
android:text="開啟Wifi" 
android:id="@+id/turnOnWifiButn" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content">
</Button>

<Button 
android:text="關閉Wifi" 
android:id="@+id/turnOffWifiButn" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content">
</Button>
</LinearLayout>
4. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="tw.nicky.WifiManagerExample"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".WifiManagerExample"
                  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>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
    <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
</manifest> 


5. 執行畫面


2010年7月12日 星期一

Android學習筆記 - 撥打電話(PhoneCall)

1. 要能夠透過程式撥打電話,需要先取得CALL_PHONE的權限,因此需在AndroidManifest.xml允許存取android.permission.CALL_PHONE這個權限。

2.PhoneCall.java
package tw.nicky.PhoneCall;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class PhoneCall extends Activity {
 private Button callButton;
 private EditText editText;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        callButton = (Button)findViewById(R.id.callButton);
        editText = (EditText)findViewById(R.id.editText);
        
        //按下call按鈕
        callButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    String phoneNumber = editText.getText().toString();
    //啟動撥打電話程式
    Intent intentDial = new Intent("android.intent.action.CALL",Uri.parse("tel:"+phoneNumber));
    startActivity(intentDial);
   }
  });
    }
}

3. main.xml(Layout)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
<EditText 
android:id="@+id/editText" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content">
</EditText>
<Button 
android:id="@+id/callButton" 
android:text="Call" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content">
</Button>
</LinearLayout>

4. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="tw.nicky.PhoneCall"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".PhoneCall"
                  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>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
</manifest> 


5. 執行畫面


2010年7月11日 星期日

Android學習筆記 - 接收SMS訊息(SMSReceiver)

1. 需繼承BroadcastReceiver並覆寫onReceive方法,將所有接收到SMS訊息要處理的動作寫在這個方法內。要接收SMS訊息需要使用者先同意接收SMS訊息的權限,因此需在AndroidManifest.xml允許存取android.permission.RECEIVE_SMS這個權限。

2.SMSReceiver.java
package tw.nicky.ReceiveSMSExample;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;

public class SMSReceiver extends BroadcastReceiver{
 @Override
 public void onReceive(Context context, Intent intent) {
  //判斷這個是接收到SMS的Broadcast
  if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
   Bundle bundle = intent.getExtras();
   Object[] pdus = (Object[]) bundle.get("pdus");
   SmsMessage[] smsMessages = new SmsMessage[pdus.length];
   //將pdu轉成SmsMessage
   for(int i=0;i
3. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="tw.nicky.ReceiveSMSExample" android:versionCode="1"
 android:versionName="1.0">
 <application android:icon="@drawable/icon" android:label="ReceiveSMSExample">
  <receiver android:name=".SMSReceiver">
   <intent-filter>
    <action android:name="android.provider.Telephony.SMS_RECEIVED" />
   </intent-filter>
  </receiver>
 </application>
 <uses-permission android:name="android.permission.RECEIVE_SMS" />
</manifest> 
5. 執行畫面


2010年7月7日 星期三

Android學習筆記 - 錄音(MediaRecorder)

1. 要進行錄音需先取得錄音的權限,加上需將錄音檔寫到記憶卡,因此需在AndroidManifest.xml允許存取android.permission.RECORD_AUDIO及android.permission.WRITE_EXTERNAL_STORAGE這二個權限。

2.MediaRecorderExample.java
package tw.nicky;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;

public class MediaRecorderExample extends Activity {
 private Button recordButn;
 private Button stopButn;
 private MediaRecorder mediaRecorder = null;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  recordButn = (Button) findViewById(R.id.recordButn);
  stopButn = (Button) findViewById(R.id.stopButn);

  //錄音
  recordButn.setOnClickListener(new View.OnClickListener() {
   public void onClick(View v) {
    //設定錄音檔名
    String fileName = "record.amr";
    try {
     File SDCardpath = Environment.getExternalStorageDirectory();
                    File myDataPath = new File( SDCardpath.getAbsolutePath() + "/download" );
                    if( !myDataPath.exists() ) myDataPath.mkdirs();
     File recodeFile = new File(SDCardpath.getAbsolutePath() + "/download/"+fileName);
     
     mediaRecorder = new MediaRecorder();

     //設定音源
     mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
     //設定輸出檔案的格式
     mediaRecorder
       .setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
     //設定編碼格式
     mediaRecorder
       .setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
     //設定錄音檔位置
     mediaRecorder
       .setOutputFile(recodeFile.getAbsolutePath());

     mediaRecorder.prepare();

     //開始錄音
     mediaRecorder.start();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  });

  //停止錄音
  stopButn.setOnClickListener(new View.OnClickListener() {
   public void onClick(View v) {
    if(mediaRecorder != null) {
     mediaRecorder.stop();
     mediaRecorder.release();
     mediaRecorder = null;
    }
   }
  });

 }
}
3. main.xml(Layout)
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout
android:id="@+id/widget0"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<Button
android:id="@+id/recordButn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="錄音"
android:layout_x="68px"
android:layout_y="44px"
>
</Button>
<Button
android:id="@+id/stopButn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止"
android:layout_x="170px"
android:layout_y="43px"
>
</Button>
</AbsoluteLayout>

4. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="tw.nicky"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MediaRecorderExample"
                  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>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>
</manifest> 


5. 執行畫面


Android學習筆記 - 音量調整(AudioManager)

1. 音量調整主要是透過AudioManager來對手機音量進行調整,可以調整的模式有:正常模式、靜音模式、震動模式、音量增大、音量減少。

2.AudioManagerExample .java
package tw.nicky;
import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class AudioManagerExample extends Activity {
    private Button normalButn;
    private Button vibrateButn;
    private Button silentButn;
    private Button upButn;
    private Button downButn;
    private AudioManager audioManager;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        normalButn = (Button)findViewById(R.id.normalButn);
        vibrateButn = (Button)findViewById(R.id.vibrateButn);
        silentButn = (Button)findViewById(R.id.silentButn);
        upButn = (Button)findViewById(R.id.upButn);
        downButn = (Button)findViewById(R.id.downButn);
        
        //取得音量控制器
        audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
        
        //正常模式
        normalButn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
   }
  });
        
        //震動模式
        vibrateButn.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    audioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
   }
  });
        
        //靜音模式
        silentButn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
   }
  });
        
        //增大音量
        upButn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    audioManager.adjustVolume(AudioManager.ADJUST_RAISE, 0);
   }
  });
        
        //減少音量
        downButn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    audioManager.adjustVolume(AudioManager.ADJUST_LOWER, 0);
   }
  });
    }
}

3. main.xml(Layout)
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout
android:id="@+id/widget0"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<Button
android:id="@+id/vibrateButn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="震動"
android:layout_x="106px"
android:layout_y="16px"
>
</Button>
<Button
android:id="@+id/silentButn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="靜音"
android:layout_x="189px"
android:layout_y="14px"
>
</Button>
<Button
android:id="@+id/normalButn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正常"
android:layout_x="28px"
android:layout_y="17px"
>
</Button>
<Button
android:id="@+id/upButn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="大聲"
android:layout_x="66px"
android:layout_y="97px"
>
</Button>
<Button
android:id="@+id/downButn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小聲"
android:layout_x="144px"
android:layout_y="97px"
>
</Button>
</AbsoluteLayout>



4. 執行畫面


2010年7月6日 星期二

Android學習筆記 - 存取SD卡

1. 由於寫入資料到SD卡是有需要額外的權限,因此需在AndroidManifest.xml允許存取android.permission.WRITE_EXTERNAL_STORAGE這個權限。

2.AccessSDCardExample.java
package tw.nicky;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;

public class AccessSDCardExample extends Activity {

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        //判斷SD卡是否存在
        if(!Environment.getExternalStorageState().equals(Environment.MEDIA_REMOVED) ){
            try {
             //取得SD卡路徑
                File SDCardpath = Environment.getExternalStorageDirectory();
                File myDataPath = new File( SDCardpath.getAbsolutePath() + "/myData" );
                if( !myDataPath.exists() ) myDataPath.mkdirs();
                //將資料寫入到SD卡
                FileWriter myFile = new FileWriter( SDCardpath.getAbsolutePath() + "/myData/test.txt" );
                myFile.write("This is a test.");
                myFile.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
         }
    }
}

3. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="tw.nicky"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".AccessSDCardExample"
                  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>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest> 


4. SD卡內容


2010年6月27日 星期日

Android學習筆記 - 通知(Notification)

1. 一般在使用通知的時候,是不需要額外的權限。但此範例設定在通知的時候需發出預設的通知震動,因此需在AndroidManifest.xml允許存取android.permission.VIBRATE這個權限。

2.NotificationExample.java
package tw.nicky;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class NotificationExample extends Activity {
    private Button notifyButn;
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        notifyButn = (Button)findViewById(R.id.notifyButn);
        notifyButn.setOnClickListener(new View.OnClickListener() {
           
            @Override
            public void onClick(View v) {
                //取得Notification服務
                NotificationManager notificationManager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
                //設定當按下這個通知之後要執行的activity
                Intent notifyIntent = new Intent(NotificationExample.this,NotificationExample.class); 
                notifyIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK);
                PendingIntent appIntent=PendingIntent.getActivity(NotificationExample.this,0,
                                                                  notifyIntent,0);
                Notification notification = new Notification();
                //設定出現在狀態列的圖示
                notification.icon=R.drawable.icon;
                //顯示在狀態列的文字
                notification.tickerText="notification on status bar.";
                //會有通知預設的鈴聲、振動、light
                notification.defaults=Notification.DEFAULT_ALL;
                //設定通知的標題、內容
                notification.setLatestEventInfo(NotificationExample.this,"Title","content",appIntent);
                //送出Notification
                notificationManager.notify(0,notification);
               
            }
        });
    }
}
3. main.xml(Layout)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello"
    />
<Button
    android:text="Notify"
    android:id="@+id/notifyButn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
</Button>
</LinearLayout>

4. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="tw.nicky"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".NotificationExample"
                  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>
    <uses-permission android:name="android.permission.VIBRATE" />
</manifest>


5. 執行畫面


2010年6月22日 星期二

Android學習筆記 - 發送SMS訊息

1. 若需使用發送SMS的服務,需在AndroidManifest.xml允許存取android.permission.SEND_SMS這個權限。

2.SendSMSExample.java
package tw.nicky.SendSMSExample;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class SendSMSExample extends Activity {
 private EditText phoneNumEditText;
 private EditText msgEditText;
 private Button sendButton;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //電話號碼
        phoneNumEditText = (EditText)findViewById(R.id.phoneNumEditText);
        //訊息
        msgEditText = (EditText)findViewById(R.id.msgEditText);
        sendButton = (Button)findViewById(R.id.sendButton);
        
        //按下發送按鈕
        sendButton.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    //取得預設的SmsManager
    SmsManager smsManager = SmsManager.getDefault();
    PendingIntent pendingIntent = PendingIntent.getBroadcast(SendSMSExample.this, 0, new Intent(), 0);
    //傳送SMS
    smsManager.sendTextMessage(phoneNumEditText.getText().toString(), null, msgEditText.getText().toString(), pendingIntent, null);
   }
  });
    }
}
3. main.xml(Layout)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <TextView 
     android:layout_width="fill_parent"
  android:layout_height="wrap_content" 
  android:text="@string/hello" />
 <EditText 
     android:id="@+id/phoneNumEditText"
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content"></EditText>
 <EditText 
     android:id="@+id/msgEditText"
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content"></EditText>
 <Button 
     android:id="@+id/sendButton"
     android:text="發送"
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content"></Button>
</LinearLayout>

4. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="tw.nicky.SendSMSExample"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".SendSMSExample"
                  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>
    <uses-permission android:name="android.permission.SEND_SMS" />
</manifest> 


5. 執行畫面


2010年6月3日 星期四

HTC Hero終於要升級Android 2.1了

來自官方Plurk的消息,確定於2010.06.04起開發軟體無線更新…

而這次更新的內容就是大家所期待的Android 2.1作業系統升級…

大家趕快去升級吧!



2010年5月27日 星期四

建立Facebook應用程式 Java API (8) - 取得「張貼訊息到塗鴨牆」的權限

1. 如果你想要張貼訊息到使用者的塗鴨牆,則需要先取得使用者的同意才能夠張貼。

    2. 要取得這個權限也不難,只要將網頁導到權限同意頁面而使用者按下同意的按鈕即可。

      3. 至於怎麼取得「權限同意頁面」的網址,做法如下:
        //API_KEY為App的KEY
        //FB_APP_ADDRESS即是使用者按下同意後要導到的網址
        String url = Permission.authorizationUrl(API_KEY, Permission.PUBLISH_STREAM) + "&next=" + FB_APP_ADDRESS;
        //利用Javascript導到權限同意頁面
        response.getWriter().println("<script type='text/javascript'>
        parent.location.href='" + url + "'
        </script>");
        


        2010年5月18日 星期二

        Android Market線上搜尋(AndroSeek)

        • AndroSeek是利用關鍵字查詢,即時的從Android Market上搜尋你所要的App。


        • 在搜尋結果頁面上會呈現每個App的名稱、圖示、下載量、評比、費用…等資訊。


        • 再點進行其中一個App,則可以看到此App的縮圖、描述以及QR Code。


        2010年4月26日 星期一

        Android學習筆記 - 震動(Vibrator)

        1. 若要在應用程式內使用到震動這個服務,需先在AndroidManifest.xml允許存取android.permission.VIBRATE這個權限。


        2. MainActivity.java
        package org.me.android_vibrate;
        import android.app.Activity;
        import android.app.Service;
        import android.os.Bundle;
        import android.os.Vibrator;
        import android.view.View;
        import android.widget.AdapterView;
        import android.widget.ArrayAdapter;
        import android.widget.Spinner;
        import android.widget.Toast;
        
        public class MainActivity extends Activity {
        
            @Override
            public void onCreate(Bundle icicle) {
                super.onCreate(icicle);
                setContentView(R.layout.main);
                Spinner spinner = (Spinner) findViewById(R.id.spinnner);
                ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_spinner_item,new String[]{"長震動","短震動","連續短震動"});
                adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                spinner.setAdapter(adapter);
        
                spinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener(){
                    public void onItemSelected(AdapterView adapterView, View view, int position, long id){
                        //取得震動服務
                        Vibrator myVibrator = (Vibrator) getApplication().getSystemService(Service.VIBRATOR_SERVICE);
                        switch(position) {
                            case 0:
                                //震動3秒
                                myVibrator.vibrate(3000);
                                break;
                            case 1:
                                //震動0.1秒
                                myVibrator.vibrate(100);
                                break;
                            case 2:
                                //停0.01秒之後震動0.1秒(重覆三次)
                                myVibrator.vibrate(new long[]{10, 100, 10, 100, 10, 100}, -1);
                                break;
                            default:
                                break;
                        }
                    }
                    public void onNothingSelected(AdapterView arg0) {
                        Toast.makeText(MainActivity.this, "您沒有選擇任何項目", Toast.LENGTH_LONG).show();
                    }
                });
            }
        }
        



        3. main.xml(Layout)
        <?xml version="1.0" encoding="UTF-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent">" 
            <Spinner
                android:id="@+id/spinnner"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
            </Spinner>
        </LinearLayout>
        


        4. AndroidManifest.xml
        <?xml version="1.0" encoding="UTF-8"?>
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
             package="org.me.android_vibrate">
            <application>
                 <activity android:name=".MainActivity" android:label="Vibrate">
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN"/>
                        <category android:name="android.intent.category.LAUNCHER"/>
                    </intent-filter>
                </activity>
            </application>
            <uses-permission android:name="android.permission.VIBRATE" />
        </manifest>
        



        5. 執行之後的畫面。


        Android學習筆記 - 背景執行服務(Service)

        1. 大部分使用者在手機上看到的畫面都是前端的程式(Activity),但是還是要有很多的服務需在背景執行。
        如果是要在背景執行的程式,則需要寫成Service並繼承android.app.Service,由於是在背景執行所以是
        要寫成Service而不是Activity,因此需在AndroidManifest新增一個Service。以下範例是按下Start Service之後會
        在背景每隔一秒Log目前的時間,按下Stop Service後會停止Log的動作。



        2. MainActivity.java
        package org.me.android_service;
        import android.app.Activity;
        import android.content.Intent;
        import android.os.Bundle;
        import android.view.View;
        import android.widget.Button;
        
        public class MainActivity extends Activity {
            private Button startButton;
            private Button stopButton;
        
            @Override
            public void onCreate(Bundle icicle) {
                super.onCreate(icicle);
                setContentView(R.layout.main);
                startButton = (Button) findViewById(R.id.startButton);
                stopButton = (Button) findViewById(R.id.stopButton);
                startButton.setOnClickListener(startClickListener);
                stopButton.setOnClickListener(stopClickListener);
            }
        
            private Button.OnClickListener startClickListener = new Button.OnClickListener() {
                public void onClick(View arg0) {
                    //啟動服務
                    Intent intent = new Intent(MainActivity.this, NickyService.class);
                    startService(intent);
                }
            };
        
            private Button.OnClickListener stopClickListener = new Button.OnClickListener() {
                public void onClick(View arg0) {
                    //停止服務
                    Intent intent = new Intent(MainActivity.this, NickyService.class);
                    stopService(intent);
                }
            };
        }
        


        3. NickyService.java
        package org.me.android_service;
        import android.app.Service;
        import android.content.Intent;
        import android.os.Handler;
        import android.os.IBinder;
        import android.util.Log;
        import java.util.Date;
        
        //繼承android.app.Service
        public class NickyService extends Service {
            private Handler handler = new Handler();
        
            @Override
            public IBinder onBind(Intent intent) {
                return null;
            }
        
            @Override
            public void onStart(Intent intent, int startId) {
                handler.postDelayed(showTime, 1000);
                super.onStart(intent, startId);
            }
        
            @Override
            public void onDestroy() {
                handler.removeCallbacks(showTime);
                super.onDestroy();
            }
            
            private Runnable showTime = new Runnable() {
                public void run() {
                    //log目前時間
                    Log.i("time:", new Date().toString());
                    handler.postDelayed(this, 1000);
                }
            };
        }
        


        4. main.xml(Layout)
        <?xml version="1.0" encoding="utf-8"?>
        <AbsoluteLayout
        android:id="@+id/widget0"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        xmlns:android="http://schemas.android.com/apk/res/android"
        >
        <Button
        android:id="@+id/startButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Service"
        android:layout_x="40px"
        android:layout_y="67px"
        >
        </Button>
        <Button
        android:id="@+id/stopButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Stop Service"
        android:layout_x="140px"
        android:layout_y="67px"
        >
        </Button>
        </AbsoluteLayout>
        


        5. AndroidManifest.xml
        <?xml version="1.0" encoding="UTF-8"?>
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
             package="org.me.android_spinner">
            <application>
                 <activity android:name=".MainActivity" android:label="MainActivity">
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN"/>
                        <category android:name="android.intent.category.LAUNCHER"/>
                    </intent-filter>
                </activity>
                <service android:name=".NickyService"/>
            </application>
        </manifest>
        



        6. 執行之後的畫面。


        2010年4月23日 星期五

        Android 必裝軟體-應用程式分類(Apps Organizer)

        你是不是常常因為安裝太多軟體,而導致常常找不到你要的軟體…
        介紹一個軟體分類的工作Apps Organizer…
        它可以將所有已安裝的軟體依照你的喜好進行分類…


        • QR Code


        • 安裝後的畫面


        • 直接點選要歸類的應用程式,並選擇要歸類的標籤


        • 也可以透過點選標籤Tab再按下Menu鍵並選擇New Label新增標籤


        • 再透過新增捷徑將你要標籤新增到桌面


        • 之後只要點選此標籤,就能秀出所有該標籤的應用程式

        Apps Organizer


        Android 必裝軟體-批次解除安裝軟體(AppManager)

        如果你覺得一個一個解除已安裝的軟體太浪費時間…
        可以試試AppManager,它可以讓你一次選擇所有要解除安裝的軟體…

        • QR Code


        • 安裝完後的畫面


        • 執行之後直接點選所有要解除安裝的軟體


        • 點選Menu並選擇Batch uninstall,進行批次解除安裝


        Android 必裝軟體-安裝記憶卡上的apk檔(appInstaller)

        如果你從網路上下載了一個apk檔…
        或是你自己寫了一隻程式想要安裝在自己的手機上…
        如果你有以上的需求,可以透過appInstaller直接安裝apk檔…

        • QR Code


        • 安裝完之後的畫面


        • 開啟後會自動搜尋記憶卡所有的apk檔


        • 直接點選欲安裝的程式進行安裝


        Android必裝軟體-快速開關3G/2G網路(APNdroid)

        APNdroid能夠讓你在不需使用網路的時候快速關閉網路,以延長電池待機時間。

        • QR Code



        • 安裝完後的畫面



        • 可以透過在桌面新增小工具來達到一鍵開關網路


        2010年4月15日 星期四

        Android學習筆記 - 計時器(Timer)

        1. 由於若不是Main Thread則無法去變更畫面的Widget內容,需透過android.os.Handler來達到此效果。

        2. MainActivity.java
        package org.me.android_timer;
        import android.app.Activity;
        import android.os.Bundle;
        import android.os.Handler;
        import android.widget.TextView;
        
        public class MainActivity extends Activity {
            private Long startTime;
            private Handler handler = new Handler();
        
            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
                //取得目前時間
                startTime = System.currentTimeMillis();
                //設定定時要執行的方法
                handler.removeCallbacks(updateTimer);
                //設定Delay的時間
                handler.postDelayed(updateTimer, 1000);
            }
        
            //固定要執行的方法
            private Runnable updateTimer = new Runnable() {
                public void run() {
                    final TextView time = (TextView) findViewById(R.id.timer);
                    Long spentTime = System.currentTimeMillis() - startTime;
                    //計算目前已過分鐘數
                    Long minius = (spentTime/1000)/60;
                    //計算目前已過秒數
                    Long seconds = (spentTime/1000) % 60;
                    time.setText(minius+":"+seconds);
                    handler.postDelayed(this, 1000);
                }
            };
        }
        


        3. main.xml(Layout)
        <?xml version="1.0" encoding="utf-8"?>
        <AbsoluteLayout
            android:id="@+id/widget0"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            xmlns:android="http://schemas.android.com/apk/res/android"
            >
            <TextView
                android:id="@+id/timer"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="0:0"
                android:textSize="70sp"
                android:layout_x="90px"
                android:layout_y="160px"
                >
            </TextView>
        </AbsoluteLayout>
        


        4. 執行之後的畫面。


        2010年4月14日 星期三

        Android學習筆記 - 儲存偏好設定(Preference)

        1. 此範例是利用SharedPreferences來儲存使用者在某個程式內的偏好設定。

        2. MainActivity.java
        package org.me.android_preference;
        import android.app.Activity;
        import android.content.SharedPreferences;
        import android.os.Bundle;
        import android.view.View;
        import android.widget.Button;
        import android.widget.EditText;
        
        public class MainActivity extends Activity {
            private EditText nameEditText;
            private Button saveButton;
            private Button restoreButton;
        
            @Override
            public void onCreate(Bundle icicle) {
                super.onCreate(icicle);
                setContentView(R.layout.main);
                nameEditText = (EditText) findViewById(R.id.nameEditText);
                saveButton = (Button) findViewById(R.id.saveButton);
                restoreButton = (Button) findViewById(R.id.restoreButton);
                saveButton.setOnClickListener(saveClickListener);
                restoreButton.setOnClickListener(restoreClickListener);
            }
        
            //按下Save按鈕
            private Button.OnClickListener saveClickListener = new Button.OnClickListener() {
        
                public void onClick(View arg0) {
                    //取得SharedPreference設定("Preference"為設定檔的名稱)
                    SharedPreferences settings = getSharedPreferences("Preference", 0);
                    //置入name屬性的字串
                    settings.edit().putString("name", nameEditText.getText().toString()).commit();
                }
            };
        
            //按下Restore按鈕
            private Button.OnClickListener restoreClickListener = new Button.OnClickListener() {
        
                public void onClick(View arg0) {
                    //取得SharedPreference設定("Preference"為設定檔的名稱)
                    SharedPreferences settings = getSharedPreferences("Preference", 0);
                    //取出name屬性的字串
                    String name = settings.getString("name", "");
                    nameEditText.setText(name);
                }
            };
        }
        


        3. main.xml(Layout)
        <?xml version="1.0" encoding="utf-8"?>
        <AbsoluteLayout
        android:id="@+id/widget0"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        xmlns:android="http://schemas.android.com/apk/res/android"
        >
        <TextView
        android:id="@+id/nameView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Name:"
        android:layout_x="22px"
        android:layout_y="34px"
        >
        </TextView>
        <EditText
        android:id="@+id/nameEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:layout_x="90px"
        android:layout_y="20px"
        >
        </EditText>
        <Button
        android:id="@+id/saveButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Save"
        android:layout_x="20px"
        android:layout_y="86px"
        >
        </Button>
        <Button
        android:id="@+id/restoreButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Restore"
        android:layout_x="98px"
        android:layout_y="84px"
        >
        </Button>
        </AbsoluteLayout>
        


        4. 執行之後的畫面。(按下Store將Name的值儲存在偏好設定,按下Restore會將儲存在偏好設定的值取回)