BroadcastReceiver 是android四大組件的一個,本質上是一種全局的監聽器,用於監聽全局的廣播消息。下面實現了后台監聽android手機通話記錄。本demo分兩個程序,第一個程序是設置監聽器,然后模擬器重啟后就會有一個全局的service在后台監聽你的來電顯示,大多數通話管理軟件都是這么干的,第二個項目是獲取通話記錄的,由於只是做一個小實驗,所以是根據某個項目改的,里面涉及到一些ContentPrivler的知識,還有sqllite數據庫,里面定義名稱並非其意思。
第一個程序代碼配置文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android" android:versionCode="1" android:versionName="1.0" > <application android:icon="@drawable/ic_launcher" android:label="@string/app_name"> <service android:name=".TtActivity"> </service> <!-- 定義一個BroadcastReceiver,監聽系統開機廣播 --> <receiver android:name=".LaunchReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <provider android:name=".DictProvider" android:authorities="org.crazyit.providers.dictprovider"/> </application> <!-- 授予應用程序訪問系統開機事件的權限 --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> </manifest>
/** * */ package com.android; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class LaunchReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent tIntent = new Intent(context , TtActivity.class); // 啟動指定Service context.startService(tIntent); } }
/** * */ package com.android; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class MyDatabaseHelper extends SQLiteOpenHelper { final String CREATE_TABLE_SQL = "create table dict(_id integer primary key autoincrement , word , detail)"; /** * @param context * @param name * @param version */ public MyDatabaseHelper(Context context, String name, int version) { super(context, name, null, version); } @Override public void onCreate(SQLiteDatabase db) { // 第一個使用數據庫時自動建表 db.execSQL(CREATE_TABLE_SQL); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { System.out.println("--------onUpdate Called--------" + oldVersion + "--->" + newVersion); } }
package com.android; import java.io.FileNotFoundException; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Service; import android.content.Context; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; import android.os.IBinder; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; public class TtActivity extends Service { MyDatabaseHelper dbHelper; TelephonyManager tManager; SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String word=format.format(new Date()); @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { tManager = (TelephonyManager) getSystemService (Context.TELEPHONY_SERVICE); dbHelper = new MyDatabaseHelper(this , "myDict.db3" , 1); // 創建一個通話狀態監聽器 PhoneStateListener listener = new PhoneStateListener() { @Override public void onCallStateChanged(int state , String detail) { switch (state) { // 無任何狀態 case TelephonyManager.CALL_STATE_IDLE: break; case TelephonyManager.CALL_STATE_OFFHOOK: break; // 來電鈴響時 case TelephonyManager.CALL_STATE_RINGING: OutputStream os = null; try { os = openFileOutput("phoneList", MODE_APPEND); } catch (FileNotFoundException e) { e.printStackTrace(); } insertData(dbHelper.getReadableDatabase() , word , detail); // PrintStream ps = new PrintStream(os); // // 將來電號碼記錄到文件中 // ps.println(new Date() + " 來電:" + incomingNumber); // ps.close(); break; default: break; } super.onCallStateChanged(state, detail); } }; //監聽電話通話狀態的改變 tManager.listen(listener , PhoneStateListener.LISTEN_CALL_STATE); } private void insertData(SQLiteDatabase db , String word , String detail) { //執行插入語句 db.execSQL("insert into dict values(null , ? , ?)" , new String[]{word , detail}); } @Override public void onDestroy() { super.onDestroy(); //退出程序時關閉MyDataBaseHelper里的SQLiteDatabase if (dbHelper != null) { dbHelper.close(); } } }
/** * */ package com.android; import android.net.Uri; import android.provider.BaseColumns; /** * @version 1.0 */ public final class Words { // 定義該ContentProvider的Authority public static final String AUTHORITY = "org.crazyit.providers.dictprovider"; //定義一個靜態內部類 public static final class Word implements BaseColumns { // 定義Content所允許操作的3個數據列 public final static String _ID = "_id"; public final static String WORD = "word"; public final static String DETAIL = "detail"; // 定義該Content提供服務的兩個Uri public final static Uri DICT_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/words"); public final static Uri WORD_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/word"); } }
/** * */ package com.android; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; /** * @version 1.0 */ public class DictProvider extends ContentProvider { private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int WORDS = 1; private static final int WORD = 2; private MyDatabaseHelper dbOpenHelper; static { // 為UriMatcher注冊兩個Uri matcher.addURI(Words.AUTHORITY, "words", WORDS); matcher.addURI(Words.AUTHORITY, "word/#", WORD); } // 第一次調用該DictProvider時,系統先創建DictProvider對象,並回調該方法 @Override public boolean onCreate() { dbOpenHelper = new MyDatabaseHelper(this.getContext(), "myDict.db3", 1); return true; } // 插入數據方法 @Override public Uri insert(Uri uri, ContentValues values) { // 獲得數據庫實例 SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); // 插入數據,返回行ID long rowId = db.insert("dict", Words.Word._ID, values); // 如果插入成功返回uri if (rowId > 0) { // 在已有的 Uri的后面追加ID數據 Uri wordUri = ContentUris.withAppendedId(uri, rowId); // 通知數據已經改變 getContext().getContentResolver().notifyChange(wordUri, null); return wordUri; } return null; } // 刪除數據的方法 @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); // 記錄所刪除的記錄數 int num = 0; // 對於uri進行匹配。 switch (matcher.match(uri)) { case WORDS: num = db.delete("dict", selection, selectionArgs); break; case WORD: // 解析出所需要刪除的記錄ID long id = ContentUris.parseId(uri); String where = Words.Word._ID + "=" + id; // 如果原來的where子句存在,拼接where子句 if (selection != null && !selection.equals("")) { where = where + " and " + selection; } num = db.delete("dict", where, selectionArgs); break; default: throw new IllegalArgumentException("未知Uri:" + uri); } // 通知數據已經改變 getContext().getContentResolver().notifyChange(uri, null); return num; } // 修改數據的方法 @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); // 記錄所修改的記錄數 int num = 0; switch (matcher.match(uri)) { case WORDS: num = db.update("dict", values, selection, selectionArgs); break; case WORD: // 解析出想修改的記錄ID long id = ContentUris.parseId(uri); String where = Words.Word._ID + "=" + id; // 如果原來的where子句存在,拼接where子句 if (selection != null && !selection.equals("")) { where = where + " and " + selection; } num = db.update("dict", values, where, selectionArgs); break; default: throw new IllegalArgumentException("未知Uri:" + uri); } // 通知數據已經改變 getContext().getContentResolver().notifyChange(uri, null); return num; } // 查詢數據的方法 @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); switch (matcher.match(uri)) { case WORDS: // 執行查詢 return db.query("dict", projection, selection, selectionArgs, null, null, sortOrder); case WORD: // 解析出想查詢的記錄ID long id = ContentUris.parseId(uri); String where = Words.Word._ID + "=" + id; // 如果原來的where子句存在,拼接where子句 if (selection != null && !"".equals(selection)) { where = where + " and " + selection; } return db.query("dict", projection, where, selectionArgs, null, null, sortOrder); default: throw new IllegalArgumentException("未知Uri:" + uri); } } // 返回指定uri參數對應的數據的MIME類型 @Override public String getType(Uri uri) { switch (matcher.match(uri)) { // 如果操作的數據是多項記錄 case WORDS: return "vnd.android.cursor.dir/org.crazyit.dict"; // 如果操作的數據是單項記錄 case WORD: return "vnd.android.cursor.item/org.crazyit.dict"; default: throw new IllegalArgumentException("未知Uri:" + uri); } } }
下面貼出第二個程序的代碼,調用第一個程序ContentProvidler的接口
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.crazyit.resolver" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".DictResolver" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ResultActivity" android:theme="@android:style/Theme.Dialog" android:label="找到的來電記錄"> </activity> </application> </manifest>
/** * */ package org.crazyit.content; import android.net.Uri; import android.provider.BaseColumns; /** * @version 1.0 */ public final class Words { // 定義該ContentProvider的Authority public static final String AUTHORITY = "org.crazyit.providers.dictprovider"; //定義一個靜態內部類 public static final class Word implements BaseColumns { // 定義Content所允許操作的3個數據列 public final static String _ID = "_id"; public final static String WORD = "word"; public final static String DETAIL = "detail"; // 定義該Content提供服務的兩個Uri public final static Uri DICT_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/words"); public final static Uri WORD_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/word"); } }
package org.crazyit.resolver; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.crazyit.content.Words; import org.crazyit.resolver.R; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; /** * @author Yeeku.H.Lee kongyeeku@163.com * @version 1.0 */ public class DictResolver extends Activity { ContentResolver contentResolver; Button search = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 獲取系統的ContentResolver對象 contentResolver = getContentResolver(); search = (Button)findViewById(R.id.search); // 為insert按鈕的單擊事件綁定事件監聽器 search.setOnClickListener(new OnClickListener() { @Override public void onClick(View source) { // 獲取用戶輸入 String key = ""; // 執行查詢 Cursor cursor = getContentResolver().query( Words.Word.DICT_CONTENT_URI, null , null , null , null); //創建一個Bundle對象 Bundle data = new Bundle(); data.putSerializable("data", converCursorToList(cursor)); //創建一個Intent Intent intent = new Intent(DictResolver.this , ResultActivity.class); intent.putExtras(data); //啟動Activity startActivity(intent); } }); } private ArrayList<Map<String, String>> converCursorToList( Cursor cursor) { ArrayList<Map<String, String>> result = new ArrayList<Map<String, String>>(); // 遍歷Cursor結果集 while (cursor.moveToNext()) { // 將結果集中的數據存入ArrayList中 Map<String, String> map = new HashMap<String, String>(); // 取出查詢記錄中第2列、第3列的值 map.put(Words.Word.WORD, cursor.getString(1)); map.put(Words.Word.DETAIL, cursor.getString(2)); result.add(map); } return result; } }
/** * */ package org.crazyit.resolver; import java.util.List; import java.util.Map; import org.crazyit.content.Words; import org.crazyit.resolver.R; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.widget.ListView; import android.widget.SimpleAdapter; /** * @version 1.0 */ public class ResultActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.popup); ListView listView = (ListView)findViewById(R.id.show); Intent intent = getIntent(); //獲取該intent所攜帶的數據 Bundle data = intent.getExtras(); //從Bundle數據包中取出數據 @SuppressWarnings("unchecked") List<Map<String , String>> list = (List<Map<String , String>>)data.getSerializable("data"); //將List封裝成SimpleAdapter SimpleAdapter adapter = new SimpleAdapter( ResultActivity.this , list , R.layout.line , new String[]{Words.Word.WORD , Words.Word.DETAIL} , new int[]{R.id.word , R.id.detail}); //填充ListView listView.setAdapter(adapter); } }