亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android通話記錄備份實現代碼

2020-04-11 12:26:11
字體:
來源:轉載
供稿:網友
(一) 前言

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開頭啦,之類的。還需要大家控制。

大體就這么多了,希望能對大家以后做這塊的時候稍微有所參考。。。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
69精品小视频| 国产婷婷成人久久av免费高清| 精品亚洲国产成av人片传媒| 国产精品日韩欧美综合| 亚洲男人av在线| 日韩美女毛茸茸| 中文字幕欧美日韩在线| 色综合久久88| 国产欧美一区二区白浆黑人| 日韩电影中文 亚洲精品乱码| 日韩成人小视频| 亚洲欧美中文字幕| 日韩av中文字幕在线免费观看| 91精品国产免费久久久久久| 91高潮在线观看| 久久久在线免费观看| 国产精品福利无圣光在线一区| 98精品国产高清在线xxxx天堂| 成人a免费视频| 国产精品高潮在线| 亚洲国产精彩中文乱码av| 国产一区二区三区在线播放免费观看| 亚洲精品自拍第一页| 日韩中文字幕视频| 日韩精品视频在线免费观看| 欧美高跟鞋交xxxxxhd| 亚洲高清在线观看| 自拍偷拍亚洲在线| 亚洲va久久久噜噜噜久久天堂| 欧美综合激情网| 美日韩精品免费视频| 日韩在线观看av| 亚洲国产精品字幕| 中日韩美女免费视频网站在线观看| 自拍视频国产精品| 国产精品爽爽爽爽爽爽在线观看| 欧美一级大片在线观看| 欧美激情视频在线免费观看 欧美视频免费一| 亚洲欧美日韩国产中文| 国产精品丝袜一区二区三区| 欧美日韩午夜视频在线观看| 欧美精品aaa| 日韩成人激情影院| 欧美性少妇18aaaa视频| 热久久这里只有精品| 国产欧美日韩综合精品| 亚洲一区二区三区四区视频| 国内外成人免费激情在线视频| 亚洲视频第一页| 日韩a**站在线观看| 亚洲欧美日韩精品久久亚洲区| 久久久久亚洲精品国产| 91久久久亚洲精品| 欧美在线视频免费播放| 欧美性猛交丰臀xxxxx网站| 欧美精品激情在线观看| 国产在线不卡精品| 亚洲第一偷拍网| 欧美视频裸体精品| 亚洲国产天堂久久综合| 日韩小视频网址| 欧美日韩美女在线| 欧美日韩中文字幕| 在线观看免费高清视频97| 成人网在线免费观看| 国产精品影片在线观看| 国产精品都在这里| 中文字幕国产精品| 国产日韩换脸av一区在线观看| 亚洲免费一级电影| 欧美在线一区二区视频| 亚洲图片在区色| 69视频在线免费观看| 日韩av在线精品| 亚洲精品美女在线| 欧洲日本亚洲国产区| 在线视频日本亚洲性| 日韩欧美成人区| 57pao成人国产永久免费| 中文字幕在线看视频国产欧美在线看完整| 亚洲图片欧美日产| 欧美精品videosex牲欧美| 欧美—级高清免费播放| 国产精品69精品一区二区三区| 一区二区三区国产视频| 国产精品白嫩美女在线观看| 日韩天堂在线视频| 欧美最近摘花xxxx摘花| 久久中文字幕在线视频| 国内精品久久久久久影视8| 亚洲欧美日韩爽爽影院| 欧美性极品xxxx做受| 国产精品久久97| 亚洲一区二区三区xxx视频| 欧美日本亚洲视频| 97在线精品国自产拍中文| 日韩中文有码在线视频| 国产欧美一区二区三区在线看| 亚洲黄在线观看| 日韩成人中文字幕在线观看| 久久久久久久久久亚洲| 国产精品一区专区欧美日韩| 日韩av在线免费观看| 中文字幕精品视频| 亚州国产精品久久久| 中文字幕久热精品在线视频| 成人欧美一区二区三区在线湿哒哒| 久久精品久久精品亚洲人| 国产精品日韩在线观看| 超在线视频97| 国产一区视频在线播放| 岛国视频午夜一区免费在线观看| 久久久精品在线观看| 亚洲精品资源美女情侣酒店| 国产+成+人+亚洲欧洲| 亚洲国产精品网站| 亚洲国产毛片完整版| 欧美色欧美亚洲高清在线视频| 亚洲va久久久噜噜噜久久天堂| 欧美午夜电影在线| 亚洲成在人线av| 亚洲第一av在线| 国内精品久久久久久| 亚洲第一av网站| 国产欧美在线视频| 97在线视频一区| 91夜夜揉人人捏人人添红杏| 欧美中文字幕视频| 中文字幕日韩av电影| 狠狠躁18三区二区一区| 91精品国产高清久久久久久91| 欧美成人久久久| 日韩欧美成人免费视频| 亚洲美女免费精品视频在线观看| 欧美日韩在线观看视频| 中文字幕自拍vr一区二区三区| 中文字幕欧美日韩精品| 欧美特级www| 久久亚洲综合国产精品99麻豆精品福利| 91中文字幕在线观看| 亚洲区bt下载| 亚洲国产成人91精品| 麻豆一区二区在线观看| 91理论片午午论夜理片久久| 国产一区二区三区欧美| 欧美激情性做爰免费视频| 亚洲电影成人av99爱色| 91精品视频一区| 久久久国产影院| www.国产精品一二区| 亚洲电影第1页| 欧美精品18videos性欧美| 国产精品美女午夜av| 久久久精品久久久久| 亚洲精品大尺度| 成人午夜高潮视频| 色爱精品视频一区| 在线观看视频亚洲| 亚洲日韩欧美视频| 7m第一福利500精品视频| 色婷婷久久av| 亚洲一区二区中文| 久久久久久久国产| 欧美精品第一页在线播放|