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 List<Record> mCallRecords = new ArrayList<>(); 74 75 /** 76 * Creates a {@link PhoneCallLog} from a {@link Cursor}. 77 */ fromCursor(Context context, Cursor cursor)78 public static PhoneCallLog fromCursor(Context context, Cursor cursor) { 79 int idColumn = cursor.getColumnIndex(CallLog.Calls._ID); 80 int numberColumn = cursor.getColumnIndex(CallLog.Calls.NUMBER); 81 int dateColumn = cursor.getColumnIndex(CallLog.Calls.DATE); 82 int callTypeColumn = cursor.getColumnIndex(CallLog.Calls.TYPE); 83 84 PhoneCallLog phoneCallLog = new PhoneCallLog(); 85 phoneCallLog.mId = cursor.getLong(idColumn); 86 phoneCallLog.mPhoneNumberString = cursor.getString(numberColumn); 87 phoneCallLog.mI18nPhoneNumberWrapper = I18nPhoneNumberWrapper.Factory.INSTANCE.get(context, 88 phoneCallLog.mPhoneNumberString); 89 Record record = new Record(cursor.getLong(dateColumn), cursor.getInt(callTypeColumn)); 90 phoneCallLog.mCallRecords.add(record); 91 return phoneCallLog; 92 } 93 94 /** Returns the phone number of this log. */ getPhoneNumberString()95 public String getPhoneNumberString() { 96 return mPhoneNumberString; 97 } 98 99 /** Returns the id of this log. */ getPhoneLogId()100 public long getPhoneLogId() { 101 return mId; 102 } 103 104 /** 105 * Returns the last call end timestamp of this number. Returns -1 if there's no call log 106 * records. 107 */ getLastCallEndTimestamp()108 public long getLastCallEndTimestamp() { 109 if (!mCallRecords.isEmpty()) { 110 return mCallRecords.get(0).getCallEndTimestamp(); 111 } 112 return -1; 113 } 114 115 /** 116 * Returns a copy of records from the phone number. Logs are sorted from most recent to least 117 * recent call end time. 118 */ getAllCallRecords()119 public List<Record> getAllCallRecords() { 120 return new ArrayList<>(mCallRecords); 121 } 122 123 /** 124 * Merges all call records with this call log's call records if they are representing the same 125 * phone number. 126 */ merge(@onNull PhoneCallLog phoneCallLog)127 public boolean merge(@NonNull PhoneCallLog phoneCallLog) { 128 if (equals(phoneCallLog)) { 129 mCallRecords.addAll(phoneCallLog.mCallRecords); 130 Collections.sort(mCallRecords); 131 return true; 132 } 133 return false; 134 } 135 136 @Override equals(Object object)137 public boolean equals(Object object) { 138 if (object instanceof PhoneCallLog) { 139 // We compare the ids when the phone number string is empty. 140 if (TextUtils.isEmpty(mPhoneNumberString)) { 141 return mId == ((PhoneCallLog) object).mId; 142 } else { 143 return mI18nPhoneNumberWrapper.equals( 144 ((PhoneCallLog) object).mI18nPhoneNumberWrapper); 145 } 146 } 147 return false; 148 } 149 150 @Override hashCode()151 public int hashCode() { 152 if (TextUtils.isEmpty(mPhoneNumberString)) { 153 return Long.hashCode(mId); 154 } else { 155 return Objects.hashCode(mI18nPhoneNumberWrapper); 156 } 157 } 158 159 @Override toString()160 public String toString() { 161 StringBuilder sb = new StringBuilder(); 162 sb.append("PhoneNumber: "); 163 sb.append(TelecomUtils.piiLog(mPhoneNumberString)); 164 sb.append(" CallLog: "); 165 sb.append(mCallRecords.size()); 166 return sb.toString(); 167 } 168 } 169