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