1 /*
2  * Copyright (C) 2015 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.server.telecom.tests;
18 
19 import com.android.internal.annotations.VisibleForTesting;
20 import com.android.internal.telecom.IInCallAdapter;
21 import com.android.internal.telecom.IInCallService;
22 
23 import org.mockito.Mockito;
24 
25 import android.os.Bundle;
26 import android.os.IBinder;
27 import android.os.IInterface;
28 import android.os.RemoteException;
29 import android.telecom.CallAudioState;
30 import android.telecom.CallEndpoint;
31 import android.telecom.ParcelableCall;
32 
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.concurrent.CountDownLatch;
37 import java.util.concurrent.TimeUnit;
38 
39 /**
40  * Controls a test {@link IInCallService} as would be provided by an InCall UI on a system.
41  */
42 public class InCallServiceFixture implements TestFixture<IInCallService> {
43     public static boolean sIgnoreOverrideAdapterFlag = false;
44     public String mLatestCallId;
45     public IInCallAdapter mInCallAdapter;
46     public CallAudioState mCallAudioState;
47     public final Map<String, ParcelableCall> mCallById = new HashMap<>();
48     public final Map<String, String> mPostDialById = new HashMap<>();
49     public final Map<String, String> mPostDialWaitById = new HashMap<>();
50     public boolean mBringToForeground;
51     public boolean mShowDialpad;
52     public boolean mCanAddCall;
53     public boolean mSilenceRinger;
54     public CountDownLatch mUpdateCallLock = new CountDownLatch(1);
55     public CountDownLatch mAddCallLock = new CountDownLatch(1);
56 
57     @VisibleForTesting
setIgnoreOverrideAdapterFlag(boolean flag)58     public static void setIgnoreOverrideAdapterFlag(boolean flag) {
59         sIgnoreOverrideAdapterFlag = flag;
60     }
61 
62     public class FakeInCallService extends IInCallService.Stub {
63         @Override
setInCallAdapter(IInCallAdapter inCallAdapter)64         public void setInCallAdapter(IInCallAdapter inCallAdapter) throws RemoteException {
65             // sIgnoreOverrideAdapterFlag is being used to verify a scenario where the InCallAdapter
66             // gets set twice (secondary user places MO/MT call).
67             if (mInCallAdapter != null && inCallAdapter != null && !sIgnoreOverrideAdapterFlag) {
68                 throw new RuntimeException("Adapter is already set");
69             }
70             if (mInCallAdapter == null && inCallAdapter == null) {
71                 throw new RuntimeException("Adapter was never set");
72             }
73             mInCallAdapter = inCallAdapter;
74         }
75 
76         @Override
addCall(ParcelableCall call)77         public void addCall(ParcelableCall call) throws RemoteException {
78             if (mCallById.containsKey(call.getId())) {
79                 throw new RuntimeException("Call " + call.getId() + " already added");
80             }
81             mLatestCallId = call.getId();
82             mCallById.put(call.getId(), call);
83             mAddCallLock.countDown();
84         }
85 
86         @Override
updateCall(ParcelableCall call)87         public void updateCall(ParcelableCall call) throws RemoteException {
88             if (!mCallById.containsKey(call.getId())) {
89                 // This used to throw an exception, however the actual InCallService implementation
90                 // ignores updates for calls which don't yet exist.  This is not a problem as when
91                 // a call is added to an InCallService its entire state is parceled and sent to the
92                 // InCallService.
93                 return;
94             }
95             mLatestCallId = call.getId();
96             mCallById.put(call.getId(), call);
97             mUpdateCallLock.countDown();
98         }
99 
100         @Override
setPostDial(String callId, String remaining)101         public void setPostDial(String callId, String remaining) throws RemoteException {
102             mPostDialWaitById.remove(callId);
103             mPostDialById.put(callId, remaining);
104         }
105 
106         @Override
setPostDialWait(String callId, String remaining)107         public void setPostDialWait(String callId, String remaining) throws RemoteException {
108             mPostDialById.remove(callId);
109             mPostDialWaitById.put(callId, remaining);
110         }
111 
112         @Override
onCallAudioStateChanged(CallAudioState audioState)113         public void onCallAudioStateChanged(CallAudioState audioState) throws RemoteException {
114             mCallAudioState = audioState;
115         }
116 
117         @Override
onCallEndpointChanged(CallEndpoint callEndpoint)118         public void onCallEndpointChanged(CallEndpoint callEndpoint) {}
119 
120         @Override
onAvailableCallEndpointsChanged(List<CallEndpoint> availableCallEndpoints)121         public void onAvailableCallEndpointsChanged(List<CallEndpoint> availableCallEndpoints) {}
122 
123         @Override
onMuteStateChanged(boolean isMuted)124         public void onMuteStateChanged(boolean isMuted) {}
125 
126         @Override
bringToForeground(boolean showDialpad)127         public void bringToForeground(boolean showDialpad) throws RemoteException {
128             mBringToForeground = true;
129             mShowDialpad = showDialpad;
130         }
131 
132         @Override
onCanAddCallChanged(boolean canAddCall)133         public void onCanAddCallChanged(boolean canAddCall) throws RemoteException {
134             mCanAddCall = canAddCall;
135         }
136 
137         @Override
silenceRinger()138         public void silenceRinger() throws RemoteException {
139             mSilenceRinger = true;
140         }
141 
142         @Override
onConnectionEvent(String callId, String event, Bundle extras)143         public void onConnectionEvent(String callId, String event, Bundle extras)
144                 throws RemoteException {
145         }
146 
147         @Override
onRttUpgradeRequest(String callId, int id)148         public void onRttUpgradeRequest(String callId, int id) throws RemoteException {
149         }
150 
151         @Override
onRttInitiationFailure(String callId, int reason)152         public void onRttInitiationFailure(String callId, int reason) throws RemoteException {
153         }
154 
155         @Override
asBinder()156         public IBinder asBinder() {
157             return this;
158         }
159 
160         @Override
queryLocalInterface(String descriptor)161         public IInterface queryLocalInterface(String descriptor) {
162             return this;
163         }
164 
165         @Override
onHandoverFailed(String callId, int error)166         public void onHandoverFailed(String callId, int error) {}
167 
168         @Override
onHandoverComplete(String callId)169         public void onHandoverComplete(String callId) {}
170     }
171 
172     private IInCallService.Stub mInCallServiceFake = new FakeInCallService();
173     private IInCallService.Stub mInCallServiceSpy = Mockito.spy(mInCallServiceFake);
174 
InCallServiceFixture()175     public InCallServiceFixture() throws Exception { }
176 
177     @Override
getTestDouble()178     public IInCallService getTestDouble() {
179         return mInCallServiceSpy;
180     }
181 
getCall(String id)182     public ParcelableCall getCall(String id) {
183         return mCallById.get(id);
184     }
185 
getInCallAdapter()186     public IInCallAdapter getInCallAdapter() {
187         return mInCallAdapter;
188     }
189 
waitForUpdate()190     public void waitForUpdate() {
191         try {
192             mUpdateCallLock.await(5000, TimeUnit.MILLISECONDS);
193         } catch (InterruptedException ie) {
194             return;
195         }
196         mUpdateCallLock = new CountDownLatch(1);
197     }
198 
waitUntilNumCalls(int numCalls)199     public void waitUntilNumCalls(int numCalls) {
200         if (mCallById.size() == numCalls) {
201             return;
202         }
203         mAddCallLock = new CountDownLatch(1);
204 
205         try {
206             mAddCallLock.await(5000, TimeUnit.MILLISECONDS);
207         } catch (InterruptedException ie) {
208             return;
209         }
210     }
211 }
212