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