1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.bluetooth.pbapclient; 17 18import android.content.ContentProviderOperation; 19import android.content.ContentValues; 20import android.content.Context; 21import android.content.OperationApplicationException; 22import android.os.RemoteException; 23import android.provider.CallLog; 24import android.util.Log; 25import android.util.Pair; 26 27import com.android.vcard.VCardEntry; 28import com.android.vcard.VCardEntry.PhoneData; 29 30import java.text.ParseException; 31import java.text.SimpleDateFormat; 32import java.util.ArrayList; 33import java.util.Date; 34import java.util.List; 35 36public class CallLogPullRequest extends PullRequest { 37 private static boolean DBG = true; 38 private static boolean VDBG = false; 39 private static String TAG = "PbapCallLogPullRequest"; 40 private static final String TIMESTAMP_PROPERTY = "X-IRMC-CALL-DATETIME"; 41 private static final String TIMESTAMP_FORMAT = "yyyyMMdd'T'HHmmss"; 42 43 private Context mContext; 44 45 public CallLogPullRequest(Context context, String path) { 46 mContext = context; 47 this.path = path; 48 } 49 50 @Override 51 public void onPullComplete() { 52 if (mEntries == null) { 53 Log.e(TAG, "onPullComplete entries is null."); 54 return; 55 } 56 57 if (DBG) { 58 Log.d(TAG, "onPullComplete"); 59 if (VDBG) { 60 Log.d(TAG, " with " + mEntries.size() + " count."); 61 } 62 } 63 int type; 64 try { 65 if (path.equals(PbapClientConnectionHandler.ICH_PATH)) { 66 type = CallLog.Calls.INCOMING_TYPE; 67 } else if (path.equals(PbapClientConnectionHandler.OCH_PATH)) { 68 type = CallLog.Calls.OUTGOING_TYPE; 69 } else if (path.equals(PbapClientConnectionHandler.MCH_PATH)) { 70 type = CallLog.Calls.MISSED_TYPE; 71 } else { 72 Log.w(TAG, "Unknown path type:" + path); 73 return; 74 } 75 76 ArrayList<ContentProviderOperation> ops = new ArrayList<>(); 77 for (VCardEntry vcard : mEntries) { 78 ContentValues values = new ContentValues(); 79 80 values.put(CallLog.Calls.TYPE, type); 81 82 List<PhoneData> phones = vcard.getPhoneList(); 83 if (phones == null || phones.get(0).getNumber().equals(";")) { 84 values.put(CallLog.Calls.NUMBER, ""); 85 } else { 86 values.put(CallLog.Calls.NUMBER, phones.get(0).getNumber()); 87 } 88 89 List<Pair<String, String>> irmc = vcard.getUnknownXData(); 90 SimpleDateFormat parser = new SimpleDateFormat(TIMESTAMP_FORMAT); 91 if (irmc != null) { 92 for (Pair<String, String> pair : irmc) { 93 if (pair.first.startsWith(TIMESTAMP_PROPERTY)) { 94 try { 95 values.put(CallLog.Calls.DATE, parser.parse(pair.second).getTime()); 96 } catch (ParseException e) { 97 Log.d(TAG, "Failed to parse date "); 98 if (VDBG) { 99 Log.d(TAG, pair.second); 100 } 101 } 102 } 103 } 104 } 105 106 ops.add(ContentProviderOperation.newInsert(CallLog.Calls.CONTENT_URI) 107 .withValues(values).withYieldAllowed(true).build()); 108 } 109 mContext.getContentResolver().applyBatch(CallLog.AUTHORITY, ops); 110 Log.d(TAG, "Updated call logs."); 111 } catch (RemoteException | OperationApplicationException e) { 112 Log.d(TAG, "Failed to update call log for path=" + path, e); 113 } finally { 114 synchronized (this) { 115 this.notify(); 116 } 117 } 118 } 119} 120