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 static androidx.lifecycle.Transformations.map;
19 
20 import android.app.Application;
21 import android.content.Context;
22 import android.telephony.PhoneStateListener;
23 import android.telephony.TelephonyManager;
24 
25 import androidx.lifecycle.AndroidViewModel;
26 import androidx.lifecycle.LiveData;
27 import androidx.lifecycle.MutableLiveData;
28 
29 import com.android.car.telephony.common.Contact;
30 import com.android.car.telephony.common.InMemoryPhoneBook;
31 import com.android.car.telephony.common.TelecomUtils.PhoneNumberInfo;
32 
33 /**
34  * View model for {@link PhoneFragment}
35  */
36 public final class PhoneFragmentViewModel extends AndroidViewModel {
37     private MutableLiveData<Long> mConnectTime = new MutableLiveData<>();
38     private MutableLiveData<Integer> mState = new MutableLiveData<>();
39     private MutableLiveData<String> mNumber = new MutableLiveData<>();
40     private LiveData<String> mBody;
41     private LiveData<ContactInfo> mContactInfo;
42 
43     private PhoneStateCallback mCallback;
44     private ClusterPhoneStateListener mPhoneStateListener = new ClusterPhoneStateListener();
45 
PhoneFragmentViewModel(Application application)46     public PhoneFragmentViewModel(Application application) {
47         super(application);
48 
49         TelephonyManager telephonyManager = (TelephonyManager) application.getSystemService(
50                 Context.TELEPHONY_SERVICE);
51 
52         // We have to keep a reference to the PhoneStateListener around to prevent it from being
53         // garbage-collected.
54         telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
55 
56         LiveData<PhoneNumberInfo> numberInfo = new PhoneNumberInfoLiveData(
57                 getApplication(), mNumber);
58         mBody = new SelfRefreshDescriptionLiveData(
59                 getApplication(), mState, numberInfo, mConnectTime);
60 
61         mContactInfo = map(numberInfo, ContactInfo::new);
62     }
63 
64     public interface PhoneStateCallback {
onCall()65         void onCall();
66 
onDisconnect()67         void onDisconnect();
68     }
69 
getState()70     public LiveData<Integer> getState() {
71         return mState;
72     }
73 
getBody()74     public LiveData<String> getBody() {
75         return mBody;
76     }
77 
getContactInfo()78     public LiveData<ContactInfo> getContactInfo() {
79         return mContactInfo;
80     }
81 
setPhoneStateCallback(PhoneStateCallback callback)82     public void setPhoneStateCallback(PhoneStateCallback callback) {
83         mCallback = callback;
84     }
85 
86     /**
87      * Listens to phone state changes
88      */
89     private class ClusterPhoneStateListener extends PhoneStateListener {
ClusterPhoneStateListener()90         ClusterPhoneStateListener() {
91         }
92 
93         @Override
onCallStateChanged(int state, String incomingNumber)94         public void onCallStateChanged(int state, String incomingNumber) {
95             super.onCallStateChanged(state, incomingNumber);
96 
97             mState.setValue(state);
98             mNumber.setValue(incomingNumber);
99 
100             if (state == TelephonyManager.CALL_STATE_IDLE) {
101                 if (mCallback != null) {
102                     mCallback.onDisconnect();
103                 }
104             } else if (state == TelephonyManager.CALL_STATE_RINGING) {
105                 if (mCallback != null) {
106                     mCallback.onCall();
107                 }
108             } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
109                 mConnectTime.setValue(System.currentTimeMillis());
110                 if (mCallback != null) {
111                     mCallback.onCall();
112                 }
113             }
114         }
115     }
116 
117     public class ContactInfo {
118         private String mNumber;
119         private String mDisplayName;
120         private Contact mContact;
121 
ContactInfo(PhoneNumberInfo info)122         public ContactInfo(PhoneNumberInfo info) {
123             mNumber = info.getPhoneNumber();
124             mDisplayName = info.getDisplayName();
125             mContact = InMemoryPhoneBook.get().lookupContactEntry(info.getPhoneNumber());
126         }
127 
getNumber()128         public String getNumber() {
129             return mNumber;
130         }
131 
getDisplayName()132         public String getDisplayName() {
133             return mDisplayName;
134         }
135 
getContact()136         public Contact getContact() {
137             return mContact;
138         }
139     }
140 }
141