Android通話記錄備份實現代碼

來源:互聯網
上載者:User

(一) 前言

Android預設提供了連絡人備份到sd卡的功能(代碼在com.android.vcard包裡面),我們可以把連絡人匯出成.vcf檔案存在sd卡中;如果換手機了,我們又可以把連絡人從sd卡檔案中匯入進來。那麼,通話記錄我們也能不能做出類似的功能呢?答案是肯定的!

(二) 匯出通話記錄

既然是備份通話記錄,那就肯定包括匯出和匯入的功能,這裡我們先講匯出通話記錄。

1. 根據通話記錄匯出的規範,匯出的檔案一般以.vcl尾碼結尾,中間的內容是 複製代碼 代碼如下:BEGIN:VCALL
SLOT:0 //卡槽號 0:單卡手機 1: 雙卡手機卡槽1 2: 雙卡手機卡槽2
TYPE:1 //電話類型 1:接入電話,2: 呼出電話 3: 未接電話
Date: 2013/02/12 14:11:12 GMT //來電或者去點的時間 備份時以GMT時間記錄,恢複時顯示手機時區對應時間
NUMBER:+86134xxxxx //對方號碼
DURATION:5 //期間,秒數
END:VCALL

那麼這裡就是一條通話記錄的儲存格式了,以BEGIN:VCALL 開始 END:VCALL結束。 //表示的是該欄位的含義,只是為了讓大家理解,不會匯入到實際的檔案中去。那麼我們來看實際怎麼匯出的。

2. 查詢通話記錄列表

ok.. 既然是儲存通話記錄,那麼首先要查詢通話記錄
Android裡面提供了一個CallLogProvider來滿足大家的這個需求,它在系統中配置的名字是“call_log”, 所以大家只要提供一個這樣的Uri就可以查詢了,比如:

複製代碼 代碼如下:Uri uri = Uri.parse("context://call_log/calls");
Cursor c = mContext.getContentResolver().query(uri, xxx, xxx );

這樣就可以查詢出所有的通話記錄,得到遊標。。

3. 從遊標中剝離出想要儲存的欄位和資料,寫入檔案

既然找到了遊標,那麼接下來就是從遊標中找到我們想要寫入檔案的欄位資料,比如,基本如下:

複製代碼 代碼如下:protected Object doInBackground(Object... params) { //後台非同步Task,後台查詢資料和寫入檔案,每匯出一條記錄,更新一次進度條
super.doInBackground(params);
String path = (String)params[0];

Uri queryUri = Uri.parse("content://call_log/calls");
Cursor queryedCursor = mContext.getContentResolver().query(queryUri,
null,
null,
null,
null);
if (queryedCursor == null || queryedCursor.getCount() == 0){
return -1;
}

Object[] message = new Object[1];
message[0] = queryedCursor.getCount();
publishProgress(message);

StringBuilder sb = new StringBuilder();
OutputStream outputStream = null;
Writer writer = null;
try {
outputStream = new FileOutputStream(path);
writer = new BufferedWriter(new OutputStreamWriter(outputStream));

for (queryedCursor.moveToFirst(); !queryedCursor.isAfterLast();
queryedCursor.moveToNext()) {
if (mCancel){
break;
}
sb.setLength(0);
sb.append("BEGIN:VCALL").append("\n");
int subId = queryedCursor.getInt(queryedCursor.getColumnIndex("sub_id"));
int callType = queryedCursor.getInt(
queryedCursor.getColumnIndex("type")); //incall/outcall/missed call
long date = queryedCursor.getLong(queryedCursor.getColumnIndex("date"));
String gmtData = getGTMDatetimeString(date);
String number = queryedCursor.getString(queryedCursor.getColumnIndex("formatted_number"));
String duration = queryedCursor.getString(queryedCursor.getColumnIndex("duration"));

sb.append("SLOT:").append(subId).append("\n");
sb.append("TYPE:").append(callType).append("\n");
sb.append("DATE:").append(gmtData).append("\n");
sb.append("NUMBER:").append(number).append("\n");
sb.append("DURATION:").append(duration).append("\n");
sb.append("END:VCALL").append("\n");
writer.write(sb.toString()); //寫入一條記錄到檔案中
message[0] = -1;
publishProgress(message); //發布訊息,讓主線程更新進度條
}

} catch (Exception e) {
Log.d(TAG, "", e);
return 0;
}finally{
try {
if (writer != null){
writer.close();
}
if (outputStream != null){
outputStream.close();
}
} catch (Exception e2) {
Log.d(TAG, "", e2);
return 0;
}
}
return 1;
}

這個只是大體代碼,大家如果以後有需求,可以在上面任意修改而無需知會作者。。無需著作權的哈~~~

(三) 匯入通話記錄到資料庫

1. 嗯,匯入的話,首先得搜尋sd卡裡面以.vcl尾碼結尾的檔案,嗯!起個線程吧,迭代搜尋。如下: 複製代碼 代碼如下:private class VCLScanThread extends Thread implements OnCancelListener, OnClickListener { //啟動線程進行搜尋,同時彈出進度條給使用者
private boolean mCanceled; //變數標誌使用者是否已經cancel這個搜尋過程
private boolean mGotIOException;
private File mRootDirectory;
private static final String LOG_TAG = "VCLScanThread";

// To avoid recursive link.
private Set<String> mCheckedPaths;

private class CanceledException extends Exception {
}

public VCLScanThread(File sdcardDirectory, String scanType) {
mCanceled = false;
mGotIOException = false;
mRootDirectory = sdcardDirectory;
mCheckedPaths = new HashSet<String>();
mProgressDialogForScanVCard = new ProgressDialog(Main.this);
mProgressDialogForScanVCard.setTitle(R.string.dialog_scan_calllist_progress_title);
mProgressDialogForScanVCard.show(); //彈出搜尋進度條
}

@Override
public void run() {
if (mAllVclFileList == null){
mAllVclFileList = new Vector<VCLFile>(); //開始搜尋,首先清空list,這個list用來儲存找到的.vcl檔案(包括檔案名稱,檔案路徑,等等)
}else{
mAllVclFileList.clear();
}

try {
getVCardFileRecursively(mRootDirectory); //迭代搜尋sd卡中所有的.vcl檔案
} catch (CanceledException e) {
mCanceled = true;
} catch (IOException e) {
mGotIOException = true;
}

if (mCanceled) {
mAllVclFileList = null;
}

mProgressDialogForScanVCard.dismiss();
mProgressDialogForScanVCard = null;

if (mGotIOException) {
// runOnUiThread(new DialogDisplayer(R.id.dialog_io_exception));
} else if (mCanceled) {
// finish();
} else {
int size = mAllVclFileList.size();
if (size == 0) {
Toast.makeText(Main.this, R.string.error_scan_vcl_not_found,
Toast.LENGTH_SHORT).show();
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
startVCardSelectAndImport(); //搜尋完畢,彈出對話方塊讓使用者選擇匯入那些檔案
}
});

}
}
}

private void getVCardFileRecursively(File directory)
throws CanceledException, IOException {
if (mCanceled) {
throw new CanceledException();
}

// e.g. secured directory may return null toward listFiles().
final File[] files = directory.listFiles();
if (files == null) {
final String currentDirectoryPath = directory.getCanonicalPath();
final String secureDirectoryPath =
mRootDirectory.getCanonicalPath().concat(SECURE_DIRECTORY_NAME);
if (!TextUtils.equals(currentDirectoryPath, secureDirectoryPath)) {
Log.w(LOG_TAG, "listFiles() returned null (directory: " + directory + ")");
}
return;
}
for (File file : directory.listFiles()) {
if (mCanceled) {
throw new CanceledException();
}
String canonicalPath = file.getCanonicalPath();
if (mCheckedPaths.contains(canonicalPath)) {
continue;
}

mCheckedPaths.add(canonicalPath);

String endFix = ".vcl";
if (file.isDirectory()) {
getVCardFileRecursively(file); //如果是目錄,就繼續迭代搜尋
} else if (canonicalPath.toLowerCase().endsWith(endFix) && //如果是檔案,就判斷檔案名稱是否以.vcl結尾,如果是,而且可讀,則放入搜尋的list裡面。
file.canRead()){
String fileName = file.getName();
VCLFile vclFile = new VCLFile(
fileName, canonicalPath, file.lastModified());
mAllVclFileList.add(vclFile);

}
}
}

public void onCancel(DialogInterface dialog) {
mCanceled = true;
}

public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
mCanceled = true;
}
}
}

2. 選擇好要匯入的檔案之後,就是解析該檔案,解析完一個BEGIN:VCALL和END:VCALL之後,就存入資料庫(你也可以解析多條之後一次性存入資料庫)

複製代碼 代碼如下:private void parseItemInter(String name, String value) throws Exception{
if ("SLOT".equalsIgnoreCase(name)){
mValues.put("sub_id", value);
}else if ("TYPE".equalsIgnoreCase(name)){
mValues.put("type", value);
}else if ("DATE".equalsIgnoreCase(name)){
mValues.put("date", getGTMDatetime(value));
}else if ("NUMBER".equalsIgnoreCase(name)){
mValues.put("formatted_number", value);
mValues.put("number", value);
}else if ("DURATION".equalsIgnoreCase(name)){
mValues.put("duration", value);
}else{
throw new Exception("Unknown type, name: " + name + " value: " + value);
}
}

//提交一次通話記錄資訊到資料庫
Uri uri = Uri.parse("content://call_log");
mContext.getContentResolver().insert(uri, mValues);

大體就是這個意思了,只是具體細節,還要控制。比如檔案非法啦,不是以BEGIN:VCALL開頭啦,之類的。還需要大家控制。

大體就這麼多了,希望能對大家以後做這塊的時候稍微有所參考。。。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.