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 package android.car.cluster;
17 
18 import android.content.Context;
19 import android.telephony.TelephonyManager;
20 import android.text.TextUtils;
21 import android.text.format.DateUtils;
22 
23 import androidx.lifecycle.LiveData;
24 import androidx.lifecycle.MediatorLiveData;
25 
26 import com.android.car.telephony.common.TelecomUtils.PhoneNumberInfo;
27 
28 /**
29  * Emits the description for the body in {@link PhoneFragmentViewModel}.
30  *
31  * This description may be the current duration of the call, call state, call type,
32  * or a combination of them.
33  *
34  * Possible strings:
35  * "Ringing"
36  * "1:05"
37  * "Mobile · Dialing"
38  * "Mobile · 1:05"
39  */
40 public class SelfRefreshDescriptionLiveData extends MediatorLiveData<String> {
41     private final LiveData<Long> mConnectTimeLiveData;
42     private final LiveData<PhoneNumberInfo> mNumberLiveData;
43     private final LiveData<Integer> mStateLiveData;
44     private final Context mContext;
45 
46     /**
47      * @param stateLiveData       LiveData holding the {@link TelephonyManager} call state
48      * @param numberLiveData      LiveData holding the call number
49      * @param connectTimeLiveData LiveData holding the starting timestamp of the call
50      */
SelfRefreshDescriptionLiveData(Context context, LiveData<Integer> stateLiveData, LiveData<PhoneNumberInfo> numberLiveData, LiveData<Long> connectTimeLiveData)51     public SelfRefreshDescriptionLiveData(Context context,
52             LiveData<Integer> stateLiveData,
53             LiveData<PhoneNumberInfo> numberLiveData,
54             LiveData<Long> connectTimeLiveData) {
55         mContext = context;
56         mNumberLiveData = numberLiveData;
57         mStateLiveData = stateLiveData;
58         mConnectTimeLiveData = connectTimeLiveData;
59 
60         HeartBeatLiveData heartBeatLiveData = new HeartBeatLiveData(DateUtils.SECOND_IN_MILLIS);
61 
62         addSource(stateLiveData, (trigger) -> updateDescription());
63         addSource(heartBeatLiveData, (trigger) -> updateDescription());
64         addSource(mNumberLiveData, (trigger) -> updateDescription());
65         addSource(mConnectTimeLiveData, (trigger) -> updateDescription());
66     }
67 
updateDescription()68     private void updateDescription() {
69         PhoneNumberInfo number = mNumberLiveData.getValue();
70         Integer callState = mStateLiveData.getValue();
71         Long connectTime = mConnectTimeLiveData.getValue();
72         if (callState != null) {
73             String newDescription = getCallInfoText(mContext, callState, number,
74                     connectTime != null ? connectTime : 0);
75 
76             String oldDescription = getValue();
77             if (!newDescription.equals(oldDescription)) {
78                 setValue(newDescription);
79             }
80         } else {
81             setValue("");
82         }
83     }
84 
85     /**
86      * @return A formatted string that has information about the phone call
87      * Possible strings:
88      * "Mobile · Dialing"
89      * "Mobile · 1:05"
90      */
getCallInfoText(Context context, Integer callState, PhoneNumberInfo number, Long connectTime)91     private String getCallInfoText(Context context, Integer callState, PhoneNumberInfo number,
92             Long connectTime) {
93         String label = number != null ? number.getTypeLabel() : null;
94         String text = "";
95         if (callState == TelephonyManager.CALL_STATE_OFFHOOK) {
96             long duration = connectTime > 0 ? System.currentTimeMillis()
97                     - connectTime : 0;
98             String durationString = DateUtils.formatElapsedTime(duration / 1000);
99             if (!TextUtils.isEmpty(durationString) && !TextUtils.isEmpty(label)) {
100                 text = context.getString(R.string.phone_label_with_info, label,
101                         durationString);
102             } else if (!TextUtils.isEmpty(durationString)) {
103                 text = durationString;
104             } else if (!TextUtils.isEmpty(label)) {
105                 text = label;
106             }
107         } else {
108             String state = callStateToUiString(context, callState);
109             if (!TextUtils.isEmpty(label)) {
110                 text = context.getString(R.string.phone_label_with_info, label, state);
111             } else {
112                 text = state;
113             }
114         }
115 
116         return text;
117     }
118 
119     /**
120      * @return A string representation of the call state that can be presented to a user.
121      */
callStateToUiString(Context context, int state)122     private String callStateToUiString(Context context, int state) {
123         switch (state) {
124             case TelephonyManager.CALL_STATE_IDLE:
125                 return context.getString(R.string.call_state_call_ended);
126             case TelephonyManager.CALL_STATE_RINGING:
127                 return context.getString(R.string.call_state_call_ringing);
128             case TelephonyManager.CALL_STATE_OFFHOOK:
129                 return context.getString(R.string.call_state_call_active);
130             default:
131                 return "";
132         }
133     }
134 }
135