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