1 /*
2  * Copyright (C) 2024 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 com.android.systemui.car.ndo;
17 
18 import android.telecom.Call;
19 import android.telecom.PhoneAccountHandle;
20 import android.util.Slog;
21 
22 import androidx.annotation.NonNull;
23 import androidx.annotation.Nullable;
24 import androidx.lifecycle.MediatorLiveData;
25 
26 import com.android.car.telephony.calling.InCallServiceManager;
27 import com.android.car.telephony.common.CallDetail;
28 import com.android.systemui.car.telecom.InCallServiceImpl;
29 
30 import java.util.List;
31 
32 /**
33  * Livedata that provides first active call of the currently blocked calling activity.
34  * Returns null if no calls are found for the currently blocked activity.
35  * <p>
36  * Calls must be in an active or holding {@link Call.CallState}. Other states will not emit a value.
37  */
38 public class InCallLiveData extends MediatorLiveData<Call> implements
39         InCallServiceImpl.InCallListener {
40     private static final String TAG = "SysUi.InCallLiveData";
41 
42     private final InCallServiceManager mServiceManager;
43     private final String mBlockedActivity;
44 
InCallLiveData(InCallServiceManager serviceManager, String packageName)45     public InCallLiveData(InCallServiceManager serviceManager, String packageName) {
46         mServiceManager = serviceManager;
47         mBlockedActivity = packageName;
48     }
49 
50     private final Call.Callback mCallStateChangedCallback = new Call.Callback() {
51         @Override
52         public void onStateChanged(Call call, int state) {
53             Slog.d(TAG, "onStateChanged: " + call);
54             update();
55         }
56 
57         @Override
58         public void onParentChanged(Call call, Call parent) {
59             Slog.d(TAG, "onParentChanged: " + call);
60             update();
61         }
62 
63         @Override
64         public void onChildrenChanged(Call call, List<Call> children) {
65             Slog.d(TAG, "onChildrenChanged: " + call);
66             update();
67         }
68     };
69 
70     @Override
onActive()71     protected void onActive() {
72         super.onActive();
73 
74         if (mServiceManager.getInCallService() == null) {
75             setValue(null);
76             return;
77         }
78         update();
79     }
80 
81     @Override
onInactive()82     protected void onInactive() {
83         super.onInactive();
84         setValue(null);
85     }
86 
87     @Override
onCallAdded(Call call)88     public void onCallAdded(Call call) {
89         Slog.d(TAG, "Call added: " + call);
90         call.registerCallback(mCallStateChangedCallback);
91         update();
92     }
93 
94     @Override
onCallRemoved(Call call)95     public void onCallRemoved(Call call) {
96         Slog.d(TAG, "Call removed: " + call);
97         call.unregisterCallback(mCallStateChangedCallback);
98         update();
99     }
100 
update()101     private void update() {
102         setValue(getFirstBlockedActivityCall());
103     }
104 
105     @Nullable
getFirstBlockedActivityCall()106     private Call getFirstBlockedActivityCall() {
107         InCallServiceImpl inCallService = (InCallServiceImpl) mServiceManager.getInCallService();
108 
109         if (inCallService == null) {
110             Slog.i(TAG, "null InCallService");
111             return null;
112         }
113 
114         List<Call> callList = inCallService.getCalls();
115         List<Call> blockedAppCallList = callList.stream()
116                 .filter(call -> contains(mBlockedActivity, getSelfManagedCallAppPackageName(call)))
117                 .toList();
118 
119         return blockedAppCallList.isEmpty() ? null : blockedAppCallList.get(0);
120     }
121 
contains(String a, String b)122     private boolean contains(String a, String b) {
123         if (a == null || b == null) {
124             return false;
125         }
126         return a.contains(b);
127     }
128 
129     @Nullable
getSelfManagedCallAppPackageName(@onNull Call call)130     private String getSelfManagedCallAppPackageName(@NonNull Call call) {
131         int callState = call.getDetails().getState();
132 
133         if (callState != Call.STATE_ACTIVE && callState != Call.STATE_HOLDING) {
134             return null;
135         }
136         CallDetail callDetails = CallDetail.fromTelecomCallDetail(call.getDetails());
137         if (callDetails.isSelfManaged()) {
138             PhoneAccountHandle phoneAccountHandle = callDetails.getPhoneAccountHandle();
139             return phoneAccountHandle == null ? null
140                     : phoneAccountHandle.getComponentName().getPackageName();
141         }
142         return null;
143     }
144 }
145