1 /* 2 * Copyright (C) 2019 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 */ 16 17 package com.android.car.telephony.common; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.provider.CallLog; 22 import android.text.TextUtils; 23 24 import androidx.annotation.NonNull; 25 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.List; 29 import java.util.Objects; 30 31 /** 32 * Entity class for call logs of a phone number. This call log may contains multiple call 33 * records. 34 */ 35 public class PhoneCallLog { 36 private static final String TAG = "CD.PhoneCallLog"; 37 38 /** Call log record. */ 39 public static class Record implements Comparable<Record> { 40 private final long mCallEndTimestamp; 41 private final int mCallType; 42 Record(long callEndTimestamp, int callType)43 public Record(long callEndTimestamp, int callType) { 44 mCallEndTimestamp = callEndTimestamp; 45 mCallType = callType; 46 } 47 48 /** Returns the timestamp on when the call occured, in milliseconds since the epoch */ getCallEndTimestamp()49 public long getCallEndTimestamp() { 50 return mCallEndTimestamp; 51 } 52 53 /** 54 * Returns the type of this record. For example, missed call, outbound call. Allowed values 55 * are defined in {@link CallLog.Calls#TYPE}. 56 * 57 * @see CallLog.Calls#TYPE 58 */ getCallType()59 public int getCallType() { 60 return mCallType; 61 } 62 63 /** Phone call records are sort in reverse chronological order. */ 64 @Override compareTo(Record otherRecord)65 public int compareTo(Record otherRecord) { 66 return (int) (otherRecord.mCallEndTimestamp - mCallEndTimestamp); 67 } 68 } 69 70 private long mId; 71 private String mPhoneNumberString; 72 private I18nPhoneNumberWrapper mI18nPhoneNumberWrapper; 73 private String mAccountName; 74 private List<Record> mCallRecords = new ArrayList<>(); 75 76 /** 77 * Creates a {@link PhoneCallLog} from a {@link Cursor}. 78 */ fromCursor(Context context, Cursor cursor)79 public static PhoneCallLog fromCursor(Context context, Cursor cursor) { 80 int idColumn = cursor.getColumnIndex(CallLog.Calls._ID); 81 int numberColumn = cursor.getColumnIndex(CallLog.Calls.NUMBER); 82 int dateColumn = cursor.getColumnIndex(CallLog.Calls.DATE); 83 int callTypeColumn = cursor.getColumnIndex(CallLog.Calls.TYPE); 84 int accountNameColumn = cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID); 85 86 PhoneCallLog phoneCallLog = new PhoneCallLog(); 87 phoneCallLog.mId = cursor.getLong(idColumn); 88 phoneCallLog.mPhoneNumberString = cursor.getString(numberColumn); 89 phoneCallLog.mI18nPhoneNumberWrapper = I18nPhoneNumberWrapper.Factory.INSTANCE.get(context, 90 phoneCallLog.mPhoneNumberString); 91 Record record = new Record(cursor.getLong(dateColumn), cursor.getInt(callTypeColumn)); 92 phoneCallLog.mCallRecords.add(record); 93 phoneCallLog.mAccountName = cursor.getString(accountNameColumn); 94 return phoneCallLog; 95 } 96 97 /** Returns the phone number of this log. */ getPhoneNumberString()98 public String getPhoneNumberString() { 99 return mPhoneNumberString; 100 } 101 102 /** 103 * Returns the account name that this call log belongs to. For call logs from Bluetooth device, 104 * account name is the same as Bluetooth address. 105 */ getAccountName()106 public String getAccountName() { 107 return mAccountName; 108 } 109 110 /** Returns the id of this log. */ getPhoneLogId()111 public long getPhoneLogId() { 112 return mId; 113 } 114 115 /** 116 * Returns the last call end timestamp of this number. Returns -1 if there's no call log 117 * records. 118 */ getLastCallEndTimestamp()119 public long getLastCallEndTimestamp() { 120 if (!mCallRecords.isEmpty()) { 121 return mCallRecords.get(0).getCallEndTimestamp(); 122 } 123 return -1; 124 } 125 126 /** 127 * Returns a copy of records from the phone number. Logs are sorted from most recent to least 128 * recent call end time. 129 */ getAllCallRecords()130 public List<Record> getAllCallRecords() { 131 return new ArrayList<>(mCallRecords); 132 } 133 134 /** 135 * Merges all call records with this call log's call records if they are representing the same 136 * phone number. 137 */ merge(@onNull PhoneCallLog phoneCallLog)138 public boolean merge(@NonNull PhoneCallLog phoneCallLog) { 139 if (equals(phoneCallLog)) { 140 mCallRecords.addAll(phoneCallLog.mCallRecords); 141 Collections.sort(mCallRecords); 142 return true; 143 } 144 return false; 145 } 146 147 @Override equals(Object object)148 public boolean equals(Object object) { 149 if (object instanceof PhoneCallLog) { 150 // We compare the ids when the phone number string is empty. 151 if (TextUtils.isEmpty(mPhoneNumberString)) { 152 return mId == ((PhoneCallLog) object).mId; 153 } else { 154 return mI18nPhoneNumberWrapper.equals( 155 ((PhoneCallLog) object).mI18nPhoneNumberWrapper); 156 } 157 } 158 return false; 159 } 160 161 @Override hashCode()162 public int hashCode() { 163 if (TextUtils.isEmpty(mPhoneNumberString)) { 164 return Long.hashCode(mId); 165 } else { 166 return Objects.hashCode(mI18nPhoneNumberWrapper); 167 } 168 } 169 170 @Override toString()171 public String toString() { 172 StringBuilder sb = new StringBuilder(); 173 sb.append("PhoneNumber: "); 174 sb.append(TelecomUtils.piiLog(mPhoneNumberString)); 175 sb.append(" CallLog: "); 176 sb.append(mCallRecords.size()); 177 sb.append(" Account: "); 178 sb.append(mAccountName); 179 return sb.toString(); 180 } 181 } 182