2015年7月30日 星期四

如何使用DatePickerDialog

出處: http://givemepass.blogspot.tw/2011/11/datepickerdialog.html

如果你想要讓你的某個元件加入目前的日期,
可是如果使用EditText讓使用者填入時間,那真的是非常的麻煩,
而且使用者的格式也會出錯,
只要利用DatePickerDialog就可以避免以上的麻煩。



首先你先建立好一個Button跟一個TextView
XML如下:

<?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:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:text="Date" 
 android:id="@+id/dateButton" />
 <TextView 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:id="@+id/dateText" /> 
</LinearLayout>




接著你將一些資料初始化

private Button dateButton; 
 private Calendar calendar; 
 private int mYear, mMonth, mDay; 
 private TextView dateText; 
 private DatePickerDialog datePickerDialog; 

 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main); 

 calendar = Calendar.getInstance(); 

 mYear = calendar.get(Calendar.YEAR); 
 mMonth = calendar.get(Calendar.MONTH);
 mDay = calendar.get(Calendar.DAY_OF_MONTH);
 dateText = (TextView)findViewById(R.id.dateText); 

 dateButton = (Button)findViewById(R.id.dateButton); 
 dateButton.setOnClickListener(new OnClickListener(){ 

 @Override
 public void onClick(View view) { 

 showDialog(0); 
 datePickerDialog.updateDate(mYear, mMonth, mDay); 
 }
 });
 }







然後在自己的Activity裡面overwrite onCreateDialog,
上面的showDialog方法就是呼叫我們建立的Dialog,

@Override
 protected Dialog onCreateDialog(int id) { 

datePickerDialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
 
@Override
 public void onDateSet(DatePicker view, int year, int month, int day) { 
mYear = year; 
mMonth = month; 
mDay = day; 
dateText.setText("你設定的日期為"+setDateFormat(year,month,day));
 }
 }, mYear,mMonth, mDay); return datePickerDialog; }


onDateSet方法表示當你按下確定的時候, 就會跳進這個方法
因此我們將選取的時間全部存起來,
接著上面有多一個setDateFormat的方法,
這個方法是可以設置你想要設置的日期格式

private String setDateFormat(int year,int monthOfYear,int dayOfMonth){ 

return String.valueOf(year) + "-" + String.valueOf(monthOfYear + 1) + "-" + 

String.valueOf(dayOfMonth); }

這樣一來,你想要的日期就會變成 "年-月-日"的呈現方式在View上面

一開始你會看到這樣的畫面









當你按下Button就會跳出




















ps. 如果不想跳出DatePickerDialog的時候, 任選一個時間, 按下"取消", 系統記住你目前選的日期,只要在onClick方法裡面加上datePickerDialog.updateDate()這個方法 就可以即時更新時間了

@Override
 public void onClick(View view) { 

showDialog(0);
 datePickerDialog.updateDate(mYear, mMonth, mDay); 

}










Android上日期與時間的處理 - Calendar

出處: http://hhliu-skills.blogspot.tw/2012/04/android-calendar.html

在Android系統裡面可以使用到關於時間的類別有三種


java.util.Calendar
java.util.Date
java.sql.Timestamp


主要使用Calendar類別,Date類別在Android中不建議使用然而我們會用到java.text.SimpleDateFormat這個類別來處理Date和String間的轉換所以Data類別常用來當作Calendar類別和String類別轉換的中介類別。

Timestamp類別在Android當中有兩個同名類別,分別是java.sql.Timestamp以及java.security.Timestamp。使用的時候要注意不要import錯誤的package。Timestamp類別使用在SQLite資料庫中。SQLite對於記錄日期時間的方式有兩種欄位宣告的程式撰寫方式,一種是將欄位宣告成為long,直接記錄Calendar.getTimeInMillis()後的數值;另一種則是宣告成為Timestamp,預設值是使用yyyy-MM-dd hh:mm:ss.SSS的字串型式儲存。

整理一些常用的寫法如下:


建立一個新的Calendar物件,預設初值為系統現在時間
Calendar c = Calendar.getInstance();

這是一個隱式的敘述,如果追蹤程式碼可以發現它創立了一個新的物件而不是和別人共用物件。Calendar所建立的時間是以1970年1月1日開始計算到目前為止的格林威治標準時間的milliseconds,所以不管在哪一個時區所儲存的時間都是一樣的。如果要顯示出不同時區和不同地區的時間則需要在輸出的時候由SimpleDateFormat擔任轉換的工作。
設定Calendar物件到特定的時間
Calendar c = Calendar.getInstance();
c.set(2012, 11, 12); //設定日期為2012年12月12日,
//在Calendar類別中月份的編號是由0~11

c.set(calendar.YEAR, 2013); //將年改成2013年
c.set(Calendar.MONTH, Calendar.JANUARY); //將月份改成1月
c.set(Calendar.DAY_OF_MONTH, 31); // 將日改成31日

c.set(Calendar.HOUR_OF_DAY, 18); //將hour改成下午六點

c.set(Calendar.AM_PM, Calendar.PM); //將hour改成下午六點
c.set(Calendar.HOUR, 6);
*** 有上面這些範例,其他時間的設定應該可以找出規律來了。
取得Calendar物件資訊
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR); //取出年
int month = c.get(Calendar.MONTH) + 1; //取出月,月份的編號是由0~11 故+1
int day = c.get(Calendar.DAY_OF_MONTH); //取出日

int weekday = c.get(Calendar.DAY_OF_WEEK); //取出星期幾,編號由Sunday(1)~Saturday(7)


Calendar和Date間的互轉
Calendar類別提供getTime()和setTime()兩個方法和Date類別互轉,由函式原型來看

public final Date getTime ()
public final void setTime (Date date)要記得c.getTime()所傳回的型別就是Date類別了,在使用上要稍微留意一下。
Calendar to Date
Date date = c.getTime();
Date to Calendar
c.setTime(date);
Calendar和Timestamp間的互轉
Calendar和Timestamp之間是利用milliseconds來轉換,利用getTimeInMillis()

public long getTimeInMillis ()
Calendar to Timestamp
Timestamp time = new Timestamp(c.getTimeInMillis());
Timestamp to Calendar
c.setTime(time)

Calendar和String間的互轉
SimpleDateFormat可以用來在String和Date間互轉,透過Date做中介使得Calendar和String間可以互相轉換。
SimpleDateFormat的樣式表可以由這裡查到,基本用法如下:
Calendar to String:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); Calendar c = Calendar.getInstance();
String str = df.format(c.getTime());
String to Calendar:
SimpleDateFormat df2 = new SimpleDateFormat("yyyy/MM/dd");
Calendar cc = Calendar.getInstance();
try {
cc.setTime(df2.parse("2012/12/12"));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();}

simpleDateFormat的模板裡面用大寫的"MM"表示月份,小寫的"mm"表示分鐘;大寫的"HH"表示24小時制的hour (0~23),小寫的"hh"表示12小時制的hour (1~12),大寫的"KK"表示 12小時制的hour (0~11),小寫的"kk"表示24小時制的hour (1~24)。
常用的SimpleDateFormat格式
取出日期
SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
String str = df.format(c.getTime());
取出時間(24 hr)
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
String str = df.format(c.getTime());
取出時間(12 hr am/pm)
SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss a");
String str = df.format(c.getTime());

這個型式會輸出類似:10:25:30 上午 的格式,如果想要輸出成為 10:25:30 AM則需要使用地區設定來幫忙
SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss a", Locale.US);
String str = df.format(c.getTime());
模板中如果使用超過3個字符表示需要用全名來印出
取出月份,以文字模式
SimpleDateFormat df = new SimpleDateFormat("MMMM dd yy, EEEE");
會印出 "4月 06 12, 星期五"




Calendar常用計算
加減日期 (使用add())
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, 2); //加上兩天
c.add(Calendar.MONTH, -1); // 減一個月
在加減日期運算時不需要考慮到是否有跨月份或是跨年度的問題,Calendar會幫我們處理好。
只針對特別欄位作加減運算(使用roll())
Calendar c = Calendar.getInstance();
c.roll(Calendar.MONTH, 10); // 若目前日期是2012/6/12
// 運算過後會變成 2012/4/12
// 表示只會更改月份,不會影響其他欄位 ( 6 + 10 - 12 = 4)
計算兩個日期間的間隔 ( I )
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.set(2012, Calendar.JANUARY, 31);
c2.set(2012, Calendar.MAY, 5);

int day1 = c1.get(Calendar.DAY_OF_YEAR);
int day2 = c2.get(Calendar.DAY_OF_YEAR);
int dayDiff = day2 - day1;

上面的運算中,如果兩個日期不在同一年度則需要先判斷年度再進行日期計算
計算兩個日期間的間隔 ( II ),利用millisecond來計算。
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.set(2012, Calendar.JANUARY, 31);
c2.set(2012, Calendar.MAY, 5);

long aDayInMilliSecond = 60 * 60 * 24 * 1000; //一天的毫秒數
long dayDiff = (c2.getTimeInMillis() - c1.getTimeInMillis()) / aDayInMilliSecond;
取得這個月有幾天
c.set(Calendar.MONTH, Calendar.FEBRUARY);
int daysInMonth = c.getActualMaximum(Calendar.DAY_OF_MONTH);
這個函式會傳回特定欄位的最大值,可以用來傳回一個月有幾天。包含閏年的2月有29天都可以正確的回傳。
利用cursor取得SQLite內的Timestamp內容

Timestamp c = Timestamp.valueOf(cursor.getString(ColumnIndex);

2015年5月24日 星期日

偵測耳機硬體鍵單擊雙擊判斷

以上一篇為例,還需準備一個共用class,在共用的class裡設置一個int count = 0;

當點擊硬體鍵時,共用class裡的count++,再搭配cTimer.schedule(cTimerTask,500);

執行後500毫秒才開始判斷count ==1 或==2 在傳遞訊息給主程式執行播放、暫停、下一首。



首先要在MainFest添加共用class:

<application
        android:name=".PP"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:launchMode="singleInstance" >
<activity
.
.


共用class:

public class PP extends Application {

int count =0;
private MyHandler handler ;


    // 傳遞訊息的方法  
    public void setHandler(MyHandler handler) {
        this.handler = handler;
    }
     
    // 得到訊息方法  
    public MyHandler getHandler() {
        return handler;
    }
   
    //點擊硬體鍵count++
    public void addcount(){
    count++;
    }
   
    //得到硬體鍵點擊的次數
    public int getcount(){
    return count;
    }
   
    //回復count初始化
    public void recovercount(){
    count = 0;
    }
}



BroadcastReceiver.java

public class MediaButtonReceiver extends BroadcastReceiver {
private static final String TAG = "MediaButtonReceiver";
private PP pp ; //共用class
private static final int CHANGED = 0x0010;
private static final int CHANGEDNEXTSONG = 0x0011;
private MyHandler mHandler ;  
private boolean isStart = true;
private Timer cTimer = null;


@Override
public void onReceive(final Context context, Intent intent) {

// 獲得Action
String intentAction = intent.getAction();
// 獲得KeyEvent对象
KeyEvent keyEvent = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
// 按下 / 鬆開按鈕
int keyAction = keyEvent.getAction();
pp = (PP)context.getApplicationContext();
mHandler = pp.getHandler();  

if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction) && (KeyEvent.ACTION_DOWN == keyAction)) {

// 獲得按鍵字節碼
int keyCode = keyEvent.getKeyCode();

if (KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE == keyCode) {

}
if (KeyEvent.KEYCODE_HEADSETHOOK == keyCode) {
pp.addcount();
if (cTimer == null){
cTimer = new Timer();
cTimer.schedule(cTimerTask,500);
}
cTimer=null;

}
if (KeyEvent.KEYCODE_MEDIA_PREVIOUS == keyCode) {
}
if (KeyEvent.KEYCODE_MEDIA_STOP == keyCode) {
}
// 輸出點擊的按鍵碼
} else if (KeyEvent.ACTION_UP == keyAction) {

}

}

private TimerTask cTimerTask = new TimerTask() {
@Override
public void run() {
isStart = true;

if (isStart) {
if (pp.getcount() == 1 ){

// 發送消息,判斷當點1下,發送CHANGED到class,再由Activity接收
mHandler.sendEmptyMessage(CHANGED); 

} else if (pp.getcount() == 2 || pp.getcount() > 2){

                 // 發送消息,判斷當點2下,發送CHANGEDNEXTSONG到class,再由 Activity接收
mHandler.sendEmptyMessage(CHANGEDNEXTSONG);

}
pp.recovercount();//初始化共用count=0;

}
isStart = false;
}
};

}



Activity.java

public class PlayListActivity extends Activity {

private static final int CHANGED = 0x0010;
private static final int CHANGEDNEXTSONG = 0x0011;
        private MyHandler handler ; 

.
.


protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
                setContentView(R.layout.playlist);
listView = (ListView) findViewById(R.id.listView);
imgFront = (ImageView) findViewById(R.id.front);
imgPlay = (ImageView) findViewById(R.id.play);
imgPause = (ImageView) findViewById(R.id.pause);
.
.
.


                pp = (PP) getApplicationContext();
handler = new MyHandler();{
pp.setHandler(handler); 


}

.
.
.



public class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what == CHANGED) {

  // 當接收的訊息為CHANGED,也就是點一下,播放歌曲
           
}
            }  else if (msg.what == CHANGEDNEXTSONG){

 // 當接收的訊息為CHANGEDNEXTSONG,也就是點兩下,下一首
         
            }
        }
}










監聽耳機硬體鍵事件

出處:http://blog.csdn.net/shineflowers/article/details/44857549

在工作​​中,我們有時候會處理到耳機按鍵的邏輯,主要分為兩類,一種是短按,一種是長按。

監聽耳機的按鍵事件的方法有兩種:

方法一:註冊監聽Media Button的按鍵事件
此方法即使程式在背景情況下或鎖屏情況下,按線控耳機按鈕依然可控制歌曲播放。

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;

public class MainActivity extends Activity {

private AudioManager mAudioManager;
private ComponentName mComponentName;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// AudioManager註冊一個MediaButton對象
mComponentName = new ComponentName(getPackageName(), MediaButtonReceiver.class.getName());
}



@Override
protected void onResume() {
mAudioManager.registerMediaButtonEventReceiver(mComponentName); //註冊
registerReceiver(headSetReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); 
//註冊
super.onResume();
}

@Override
protected void onPause() { 


//取消註冊,但若要背景下依然可控制歌曲播放的話,這兩項務必要移除掉。
mAudioManager.unregisterMediaButtonEventReceiver(mComponentName);
unregisterReceiver(headSetReceiver);
super.onPause();
}

@Override
protected void onDestroy() {
mAudioManager = null;
mComponentName = null;
super.onDestroy();
}

private final BroadcastReceiver headSetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
// phone headset plugged
if (intent.getIntExtra("state", 0) == 1) {
// do something
// Log.d(TAG, "耳機檢測:插入");
// Toast.makeText(context, "耳機檢測:插入", Toast.LENGTH_SHORT) .show();
mAudioManager.registerMediaButtonEventReceiver(mComponentName);
// phone head unplugged
} else {
// do something
// Log.d(TAG, "耳機檢測:没有插入");
// Toast.makeText(context, "耳機檢測:没有插入", Toast.LENGTH_SHORT).show();

mAudioManager.unregisterMediaButtonEventReceiver(mComponentName);
}
}
}
};



MediaButtonReceiver.java

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;

public class MediaButtonReceiver extends BroadcastReceiver {

private static String TAG = "MediaButtonReceiver";

@Override
public void onReceive(Context context, Intent intent) {
獲得
// 獲得Action
String intentAction = intent.getAction();
// KeyEvent對象 
KeyEvent keyEvent = (KeyEvent) intent
.getParcelableExtra(Intent.EXTRA_KEY_EVENT);

Log.i(TAG, "Action ---->" + intentAction + " KeyEvent----->" + keyEvent.toString());
// 按下 / 鬆開 按鈕 
int keyAction = keyEvent.getAction();

if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)
&& (KeyEvent.ACTION_DOWN == keyAction)) {
// 獲得按鍵字結碼 
int keyCode = keyEvent.getKeyCode();

// 獲得事件的時間
// long downtime = keyEvent.getEventTime();

// 獲得按件碼 keyCode
// StringBuilder sb = new StringBuilder();
//這些都是可能的按鍵碼,打印出來用戶按下的鍵
// if (KeyEvent.KEYCODE_MEDIA_NEXT == keyCode) {
// sb.append("KEYCODE_MEDIA_NEXT");
// }
// 說明:當我們按下MEDIA_BUTTON中間按鈕時,實際出發的是KEYCODE_HEADSETHOOK 而不是
// KEYCODE_MEDIA_PLAY_PAUSE

if (KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE == keyCode) {
// sb.append("KEYCODE_MEDIA_PLAY_PAUSE");

}
if (KeyEvent.KEYCODE_HEADSETHOOK == keyCode) {
// sb.append("KEYCODE_HEADSETHOOK");
}
if (KeyEvent.KEYCODE_MEDIA_PREVIOUS == keyCode) {
// sb.append("KEYCODE_MEDIA_PREVIOUS");
}
if (KeyEvent.KEYCODE_MEDIA_STOP == keyCode) {
// sb.append("KEYCODE_MEDIA_STOP");
}
//輸出點擊的按鍵碼
// Log.i(TAG, sb.toString());
// Toast.makeText(context, sb.toString(), Toast.LENGTH_SHORT).show();

} else if (KeyEvent.ACTION_UP == keyAction) {
Log.i("chengjie", "aaa");
}
}
}
注意,在AndroidManifest.xml中定義

<receiver android:name="com.lenovo.longexposure.MediaButtonReceiver" >
<intent-filter android:priority="2147483647" >
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>


注意這種方法只能監聽耳機的短按事件,如果想監聽長按事件,請用方法二。

方法二:直接監聽onKeyDown方法



@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (KeyEvent.KEYCODE_HEADSETHOOK == keyCode) { //按下了耳機鍵
if (event.getRepeatCount() == 0) { //如果長按的话,getRepeatCount值會一值變大
//短按
} else {
//長按
}
}
}

--------------------------------分隔線-------------------------------------------------------------------

BroadcastReceiver基本使用方法:

BroadcastReceiver用於監聽被廣播的事件(Intent)

為了達到這個目的,BroadcastReceiver必須進行註冊,註冊方法有以下2種:

1. 在AndroidManifest.xml當中進行註冊

2. 在應用程式的代碼當中進行註冊

第一種方法:

activity_test.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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.testbroadcastreceiver.TestActivity" >

    <Button
        android:id="@+id/sendButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="sendBroadcaster" />

</RelativeLayout>


TestActivity.java :

public class TestActivity extends Activity {

private Button sendButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);

sendButton = (Button) findViewById(R.id.sendButton);
sendButton.setOnClickListener(new BroadcastListener());
}

class BroadcastListener implements OnClickListener {

@Override
public void onClick(View v) {
System.out.println("發送intent");
    //宣告一個intent,把需要用到的廣播裝入intent再送出給Receive
    //,讓Receiver根據收到的廣播來處理自訂要做的事
Intent intent = new Intent();
intent.setAction(Intent.ACTION_EDIT);
TestActivity.this.sendBroadcast(intent);

}
}
}

TestReceiver.java:

public class TestReceiver extends BroadcastReceiver{

public TestReceiver(){
System.out.println("啟動TestReceiver");
}

@Override
public void onReceive(Context context, Intent intent) {
System.out.println("執行OnReceiver");
}

}

AndroidManifest.xml:

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

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="21" />

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

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
     
          在這裡寫入TestReceiver,並把廣播動作都寫進去。
        <receiver android:name=".TestReceiver">
<intent-filter>
   <action android:name="android.intent.action.EDIT"/>
</intent-filter>            
        </receiver>
     
    </application>

</manifest>

執行結果:

發送intent

啟動TestReceiver

執行OnReceiver

第二種方法:

1 註冊BroadcastReceiver:

registerReceiver(receiver,filter);

2 取消註冊BroadcastReceiver(receiver);

如果一個BroadcastReceiver用於更新UI,那麼通常會使用這種方法進行註冊

在Activity啟動的時候註冊BroadcastReceiver,在Activity被摧毀以後取消註冊

activity_test.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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.testbroadcastreceiver.TestActivity" >

    <Button
        android:id="@+id/registerButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="regBroadcaster" />

       <Button
        android:id="@+id/unregisterButton"
        android:layout_width="wrap_content"
        android:layout_below="@+id/registerButton"
        android:layout_height="wrap_content"
        android:text="UnBroadcaster" />
   
</RelativeLayout>

TestActivity.java:

public class TestActivity extends Activity {

private Button registerButton;
private Button unregisterButton;
private SMSReceiver smsReceiver = null ;
private static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);

registerButton = (Button) findViewById(R.id.registerButton);
unregisterButton = (Button) findViewById(R.id.unregisterButton);
registerButton.setOnClickListener(new RegisterButtonListener());
unregisterButton.setOnClickListener(new UnRegisterButtonListener());
}

class RegisterButtonListener implements OnClickListener {

@Override
public void onClick(View v) {
smsReceiver = new SMSReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(SMS_ACTION);
TestActivity.this.registerReceiver(smsReceiver, filter);
System.out.println("註冊廣播");
}
}

class UnRegisterButtonListener implements OnClickListener {

@Override
public void onClick(View v) {

System.out.println("取消註冊");


}
}
}

BroadcastReceiver.java

public class SMSReceiver extends BroadcastReceiver{

public SMSReceiver(){
System.out.println("啟動TestReceiver");
}

@Override
public void onReceive(Context context, Intent intent) {
System.out.println("執行OnReceiver");
}

}

當到DDMS的Emulator Control去記一封訊息,模擬器會收到訊息

2015年5月21日 星期四

權限大全

  1 android.permission.ACCESS_CHECKIN_PROPERTIES
  2 //允許讀寫訪問”properties”表在checkin數據庫中,改值可以修改上傳
  3
  4 android.permission.ACCESS_COARSE_LOCATION
  5 //允許一個程序訪問CellID或WiFi熱點來獲取粗略的位置
  6
  7 android.permission.ACCESS_FINE_LOCATION
  8 //允許一個程序訪問精良位置(如GPS)
  9
 10 android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
 11 //允許應用程序訪問額外的位置提供命令
 12
 13 android.permission.ACCESS_MOCK_LOCATION
 14 //允許程序創建模擬位置提供用於測試
 15
 16 android.permission.ACCESS_NETWORK_STATE
 17 //允許程序訪問有關GSM網絡信息
 18
 19 android.permission.ACCESS_SURFACE_FLINGER
 20 //允許程序使用SurfaceFlinger底層特性
 21
 22 android.permission.ACCESS_WIFI_STATE
 23 //允許程序訪問Wi-Fi網絡狀態信息
 24
 25 android.permission.ADD_SYSTEM_SERVICE
 26 //允許程序發布系統級服務
 27
 28 android.permission.BATTERY_STATS
 29 //允許程序更新手機電池統計信息
 30
 31 android.permission.BLUETOOTH
 32 //允許程序連接到已配對的藍牙設備
 33
 34 android.permission.BLUETOOTH_ADMIN
 35 //允許程序發現和配對藍牙設備
 36
 37 android.permission.BRICK
 38 //請求能夠禁用設備(非常危險
 39
 40 android.permission.BROADCAST_PACKAGE_REMOVED
 41 //允許程序廣播一個提示消息在一個應用程序包已經移除後
 42
 43 android.permission.BROADCAST_STICKY
 44 //允許一個程序廣播常用intents
 45
 46 android.permission.CALL_PHONE
 47 //允許一個程序初始化一個電話撥號不需通過撥號用戶界面需要用戶確認
 48
 49 android.permission.CALL_PRIVILEGED
 50 //允許一個程序撥打任何號碼,包含緊急號碼無需通過撥號用戶界面需要用戶確認
 51
 52 android.permission.CAMERA
 53 //請求訪問使用照相設備
 54
 55 android.permission.CHANGE_COMPONENT_ENABLED_STATE
 56 //允許一個程序是否改變一個組件或其他的啟用或禁用
 57
 58 android.permission.CHANGE_CONFIGURATION
 59 //允許一個程序修改當前設置,如本地化
 60
 61 android.permission.CHANGE_NETWORK_STATE
 62 //允許程序改變網絡連接狀態
 63
 64 android.permission.CHANGE_WIFI_STATE
 65 //允許程序改變Wi-Fi連接狀態
 66
 67 android.permission.CLEAR_APP_CACHE
 68 //允許一個程序清楚緩存從所有安裝的程序在設備中
 69
 70 android.permission.CLEAR_APP_USER_DATA
 71 //允許一個程序清除用戶設置
 72
 73 android.permission.CONTROL_LOCATION_UPDATES
 74 //允許啟用禁止位置更新提示從無線模塊
 75
 76 android.permission.DELETE_CACHE_FILES
 77 //允許程序刪除緩存文件
 78
 79 android.permission.DELETE_PACKAGES
 80 //允許一個程序刪除包
 81
 82 android.permission.DEVICE_POWER
 83 //允許訪問底層電源管理
 84
 85 android.permission.DIAGNOSTIC
 86 //允許程序RW診斷資源
 87
 88 android.permission.DISABLE_KEYGUARD
 89 //允許程序禁用鍵盤鎖
 90
 91 android.permission.DUMP
 92 //允許程序返回狀態抓取信息從系統服務
 93
 94 android.permission.EXPAND_STATUS_BAR
 95 //允許一個程序擴展收縮在狀態欄,android開發網提示應該是一個類似Windows Mobile中的托盤程序
 96
 97 android.permission.FACTORY_TEST
 98 //作為一個工廠測試程序,運行在root用戶
 99
100 android.permission.FLASHLIGHT
101 //訪問閃光燈,android開發網提示HTC Dream不包含閃光燈
102
103 android.permission.FORCE_BACK
104 //允許程序強行一個後退操作是否在頂層activities
105
106 android.permission.FOTA_UPDATE
107 //暫時不了解這是做什麼使用的,android開發網分析可能是一個預留權限.
108
109 android.permission.GET_ACCOUNTS
110 //訪問一個帳戶列表在Accounts Service中
111
112 android.permission.GET_PACKAGE_SIZE
113 //允許一個程序獲取任何package佔用空間容量
114
115 android.permission.GET_TASKS
116 //允許一個程序獲取信息有關當前或最近運行的任務,一個縮略的任務狀態,是否活動等等
117
118 android.permission.HARDWARE_TEST
119 //允許訪問硬件
120
121 android.permission.INJECT_EVENTS
122 //允許一個程序截獲用戶事件如按鍵、觸摸、軌跡球等等到一個時間流,android 開發網提醒算是hook技術吧
123
124 android.permission.INSTALL_PACKAGES
125 //允許一個程序安裝packages
126
127 android.permission.INTERNAL_SYSTEM_WINDOW
128 //允許打開窗口使用系統用戶界面
129
130 android.permission.INTERNET
131 //允許程序打開網絡套接字
132
133 android.permission.MANAGE_APP_TOKENS
134 //允許程序管理(創建、催後、 z- order默認向z軸推移)程序引用在窗口管理器中
135
136 android.permission.MASTER_CLEAR
137 //目前還沒有明確的解釋,android開發網分析可能是清除一切數據,類似硬格機
138
139 android.permission.MODIFY_AUDIO_SETTINGS
140 //允許程序修改全局音頻設置
141
142 android.permission.MODIFY_PHONE_STATE
143 //允許修改話機狀態,如電源,人機接口等
144
145 android.permission.MOUNT_UNMOUNT_FILESYSTEMS
146 //允許掛載和反掛載文件系統可移動存儲
147
148 android.permission.PERSISTENT_ACTIVITY
149 //允許一個程序設置他的activities顯示
150
151 android.permission.PROCESS_OUTGOING_CALLS
152 //允許程序監視、修改有關播出電話
153
154 android.permission.READ_CALENDAR
155 //允許程序讀取用戶日曆數據
156
157 android.permission.READ_CONTACTS
158 //允許程序讀取用戶聯繫人數據
159
160 android.permission.READ_FRAME_BUFFER
161 //允許程序屏幕波或和更多常規的訪問幀緩衝數據
162
163 android.permission.READ_INPUT_STATE
164 //允許程序返回當前按鍵狀態
165
166 android.permission.READ_LOGS
167 //允許程序讀取底層系統日誌文件
168
169 android.permission.READ_OWNER_DATA
170 //允許程序讀取所有者數據
171
172 android.permission.READ_SMS
173 //允許程序讀取短信息
174
175 android.permission.READ_SYNC_SETTINGS
176 //允許程序讀取同步設置
177
178 android.permission.READ_SYNC_STATS
179 //允許程序讀取同步狀態
180
181 android.permission.REBOOT
182 //請求能夠重新啟動設備
183
184 android.permission.RECEIVE_BOOT_COMPLETED
185 //允許一個程序接收到
186
187 android.permission.RECEIVE_MMS
188 //允許一個程序監控將收到MMS彩信,記錄或處理
189
190 android.permission.RECEIVE_SMS
191 //允許程序監控一個將收到短信息,記錄或處理
192
193 android.permission.RECEIVE_WAP_PUSH
194 //允許程序監控將收到WAP PUSH信息
195
196 android.permission.RECORD_AUDIO
197 //允許程序錄製音頻
198
199 android.permission.REORDER_TASKS
200 //允許程序改變Z軸排列任務
201
202 android.permission.RESTART_PACKAGES
203 //允許程序重新啟動其他程序
204
205 android.permission.SEND_SMS
206 //允許程序發送SMS短信
207
208 android.permission.SET_ACTIVITY_WATCHER
209 //允許程序監控或控制activities已經啟動全局系統中
210
211 android.permission.SET_ALWAYS_FINISH
212 //允許程序控制是否活動間接完成在處於後台時
213
214 android.permission.SET_ANIMATION_SCALE
215 //修改全局信息比例
216
217 android.permission.SET_DEBUG_APP
218 //配置一個程序用於調試
219
220 android.permission.SET_ORIENTATION
221 //允許底層訪問設置屏幕方向和實際旋轉
222
223 android.permission.SET_PREFERRED_APPLICATIONS
224 //允許一個程序修改列表參數PackageManager.addPackageToPreferred() 和PackageManager.removePackageFromPreferred()方法
225
226 android.permission.SET_PROCESS_FOREGROUND
227 //允許程序當前運行程序強行到前台
228
229 android.permission.SET_PROCESS_LIMIT
230 //允許設置最大的運行進程數量
231
232 android.permission.SET_TIME_ZONE
233 //允許程序設置時間區域
234
235 android.permission.SET_WALLPAPER
236 //允許程序設置壁紙
237
238 android.permission.SET_WALLPAPER_HINTS
239 //允許程序設置壁紙hits
240
241 android.permission.SIGNAL_PERSISTENT_PROCESSES
242 //允許程序請求發送信號到所有顯示的進程中
243
244 android.permission.STATUS_BAR
245 //允許程序打開、關閉或禁用狀態欄及圖標Allows an application to open, close, or disable the status bar and its icons.
246
247 android.permission.SUBSCRIBED_FEEDS_READ
248 //允許一個程序訪問訂閱RSS Feed內容提供
249
250 android.permission.SUBSCRIBED_FEEDS_WRITE
251 //系統暫時保留改設置,android開發網認為未來版本會加入該功能。
252
253 android.permission.SYSTEM_ALERT_WINDOW
254 //允許一個程序打開窗口使用TYPE_SYSTEM_ALERT,顯示在其他所有程序的頂層(Allows an application to open windows using the type TYPE_SYSTEM_ALERT, shown on top of all other applications. )
255
256 android.permission.VIBRATE
257 //允許訪問振動設備
258
259 android.permission.WAKE_LOCK
260 //允許使用PowerManager的WakeLocks保持進程在休眠時從屏幕消失
261
262 android.permission.WRITE_APN_SETTINGS
263 //允許程序寫入API設置
264
265 android.permission.WRITE_CALENDAR
266 //允許一個程序寫入但不讀取用戶日曆數據
267
268 android.permission.WRITE_CONTACTS
269​​ //允許程序寫入但不讀取用戶聯繫人數據
270
271 android.permission.WRITE_GSERVICES
272 //允許程序修改Google服務地圖
273
274 android.permission.WRITE_OWNER_DATA
275 //允許一個程序寫入但不讀取所有者數據
276
277 android.permission.WRITE_SETTINGS
278 //允許程序讀取或寫入系統設置
279
280 android.permission.WRITE_SMS
281 //允許程序寫短信
282
283 android.permission.WRITE_SYNC_SETTINGS
284 //允許程序寫入同步設置

來電事件處理

以mp3Player為例:

先在AndroidMainfest裡設定攔截號碼權限:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

Activity:

public class MainActivity extends Activity {

private boolean isCellPlay;

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.playlist);
.
.
.


//偵聽來電事件
TelephonyManager phoneyMana = (TelephonyManager)

getSystemService(this.TELEPHONY_SERVICE);

phoneyMana.listen(new myPhoneStateListener(),PhoneStateListener.LISTEN_CALL_STATE);

}


/* 來電事件處理 */
private class myPhoneStateListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING://來電時,要處理的動作
if (mediaplayer.isPlaying()) {

mediaplayer.pause(); //音樂暫停
isCellPlay = true;//標記來電時暫停

}
break;
case TelephonyManager.CALL_STATE_IDLE://掛斷電話時要處理的動作
if (isCellPlay) {
isCellPlay = false;
mediaplayer.start(); //音樂繼續播放
}
break;
}
}
}

MP3進度bar

在xml上建立一個seekbar:

 <SeekBar
          android:id="@+id/seekbar"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_marginBottom="5dp"
           />

Activity主要有幾個關鍵:

boolean isStart ; 紀錄TimerTask是否要運行
boolean isfirst = true; 紀錄若是第一次開啟就new Timer();
總之當歌曲播完時就先暫停TimerTask運行,等到開始播放再運行TimerTask,不然bar會亂掉

public class PlayListActivity extends Activity {


private MediaPlayer mediaplayer;

private SeekBar seekbar;

private boolean isStart ;  //讓mTimerTask是否開始運行

private boolean isfirst = true;

private Timer mTimer ;
.
.
略...

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.playlist);

seekbar = (SeekBar) findViewById(R.id.seekbar);
.
.
略...

seekbar.setOnSeekBarChangeListener(new MySeekbar()); //bar綁定偵聽
.
.
.

//在播放部分
private void playSong(String path) {
try {
mediaplayer.reset();
mediaplayer.setDataSource(path); // 播放歌曲路徑
mediaplayer.prepare();
seekbar.setMax(mediaplayer.getDuration());//bar長度設為歌曲長度
if (isfirst) {  //第一次啟用產生new Timer();
mTimer = new Timer();
mTimer.schedule(mTimerTask, 0, 300);
isfirst=false;
}
isStart = true;
mediaplayer.start(); // 開始播放
mediaplayer.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {//撥放完後暫停TimerTask
isStart = false;
nextSong(); // 播放完後播下一首
}
});
} catch (IOException e) {
}
}

private TimerTask mTimerTask = new TimerTask() {  
        @Override  
        public void run() {    
            if(isStart) {   //如果isStart = true,開始運行
            seekbar.setProgress(mediaplayer.getCurrentPosition());
            }  //TimerTask會一直更新,使bar會隨著歌曲播放而改變bar位置
           
        }  
    };

         //進度條處理
class MySeekbar implements OnSeekBarChangeListener {

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub

}
               
                 //拖移進度條時,TimerTask暫停運行,不然在你沒放開手指前bar會一直亂跳
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
isStart = false; 
}
               
                //放開進度條時,TimerTask運行,歌曲會因為你拖移進度條放開後改變播放位置
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
isStart = true;
mediaplayer.seekTo(seekbar.getProgress());
}

}