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