• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.Manifest.permission.CALL_PHONE;
20 import static android.Manifest.permission.MODIFY_PHONE_STATE;
21 import static android.Manifest.permission.READ_PHONE_STATE;
22 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
23 
24 import android.app.AppOpsManager;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.ApplicationInfo;
29 import android.content.pm.PackageManager;
30 import android.net.Uri;
31 import android.os.Binder;
32 import android.os.Bundle;
33 import android.os.RemoteException;
34 import android.os.UserHandle;
35 import android.os.UserManager;
36 import android.telecom.PhoneAccount;
37 import android.telecom.PhoneAccountHandle;
38 import android.telecom.TelecomManager;
39 import android.telecom.VideoProfile;
40 import android.telephony.TelephonyManager;
41 import android.test.suitebuilder.annotation.SmallTest;
42 
43 import com.android.internal.telecom.ITelecomService;
44 import com.android.server.telecom.Call;
45 import com.android.server.telecom.CallIntentProcessor;
46 import com.android.server.telecom.CallState;
47 import com.android.server.telecom.CallsManager;
48 import com.android.server.telecom.PhoneAccountRegistrar;
49 import com.android.server.telecom.TelecomServiceImpl;
50 import com.android.server.telecom.TelecomSystem;
51 import com.android.server.telecom.components.UserCallIntentProcessor;
52 import com.android.server.telecom.components.UserCallIntentProcessorFactory;
53 
54 import org.mockito.ArgumentCaptor;
55 import org.mockito.ArgumentMatcher;
56 import org.mockito.Mock;
57 
58 import java.util.ArrayList;
59 import java.util.Collection;
60 import java.util.List;
61 
62 import static android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION;
63 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
64 import static org.mockito.Matchers.any;
65 import static org.mockito.Matchers.anyBoolean;
66 import static org.mockito.Matchers.anyInt;
67 import static org.mockito.Matchers.anyString;
68 import static org.mockito.Matchers.argThat;
69 import static org.mockito.Matchers.eq;
70 import static org.mockito.Matchers.isNull;
71 import static org.mockito.Mockito.doNothing;
72 import static org.mockito.Mockito.doReturn;
73 import static org.mockito.Mockito.doThrow;
74 import static org.mockito.Mockito.mock;
75 import static org.mockito.Mockito.never;
76 import static org.mockito.Mockito.spy;
77 import static org.mockito.Mockito.verify;
78 import static org.mockito.Mockito.when;
79 
80 public class TelecomServiceImplTest extends TelecomTestCase {
81     public static class CallIntentProcessAdapterFake implements CallIntentProcessor.Adapter {
82         @Override
processOutgoingCallIntent(Context context, CallsManager callsManager, Intent intent)83         public void processOutgoingCallIntent(Context context, CallsManager callsManager,
84                 Intent intent) {
85 
86         }
87 
88         @Override
processIncomingCallIntent(CallsManager callsManager, Intent intent)89         public void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
90 
91         }
92 
93         @Override
processUnknownCallIntent(CallsManager callsManager, Intent intent)94         public void processUnknownCallIntent(CallsManager callsManager, Intent intent) {
95 
96         }
97     }
98 
99     public static class DefaultDialerManagerAdapterFake
100             implements TelecomServiceImpl.DefaultDialerManagerAdapter {
101         @Override
getDefaultDialerApplication(Context context)102         public String getDefaultDialerApplication(Context context) {
103             return null;
104         }
105 
106         @Override
getDefaultDialerApplication(Context context, int userId)107         public String getDefaultDialerApplication(Context context, int userId) {
108             return null;
109         }
110 
111         @Override
setDefaultDialerApplication(Context context, String packageName)112         public boolean setDefaultDialerApplication(Context context, String packageName) {
113             return false;
114         }
115 
116         @Override
isDefaultOrSystemDialer(Context context, String packageName)117         public boolean isDefaultOrSystemDialer(Context context, String packageName) {
118             return false;
119         }
120     }
121 
122     public static class SubscriptionManagerAdapterFake
123             implements TelecomServiceImpl.SubscriptionManagerAdapter {
124         @Override
getDefaultVoiceSubId()125         public int getDefaultVoiceSubId() {
126             return 0;
127         }
128     }
129 
130     private static class AnyStringIn extends ArgumentMatcher<String> {
131         private Collection<String> mStrings;
AnyStringIn(Collection<String> strings)132         public AnyStringIn(Collection<String> strings) {
133             this.mStrings = strings;
134         }
135 
136         @Override
matches(Object string)137         public boolean matches(Object string) {
138             return mStrings.contains(string);
139         }
140     }
141 
142     private ITelecomService.Stub mTSIBinder;
143     private AppOpsManager mAppOpsManager;
144     private UserManager mUserManager;
145 
146     @Mock private CallsManager mFakeCallsManager;
147     @Mock private PhoneAccountRegistrar mFakePhoneAccountRegistrar;
148     @Mock private TelecomManager mTelecomManager;
149     private CallIntentProcessor.Adapter mCallIntentProcessorAdapter =
150             spy(new CallIntentProcessAdapterFake());
151     private TelecomServiceImpl.DefaultDialerManagerAdapter mDefaultDialerManagerAdapter =
152             spy(new DefaultDialerManagerAdapterFake());
153     private TelecomServiceImpl.SubscriptionManagerAdapter mSubscriptionManagerAdapter =
154             spy(new SubscriptionManagerAdapterFake());
155     @Mock private UserCallIntentProcessor mUserCallIntentProcessor;
156 
157     private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
158 
159     private static final String DEFAULT_DIALER_PACKAGE = "com.google.android.dialer";
160     private static final UserHandle USER_HANDLE_16 = new UserHandle(16);
161     private static final UserHandle USER_HANDLE_17 = new UserHandle(17);
162     private static final PhoneAccountHandle TEL_PA_HANDLE_16 = new PhoneAccountHandle(
163             new ComponentName("test", "telComponentName"), "0", USER_HANDLE_16);
164     private static final PhoneAccountHandle SIP_PA_HANDLE_17 = new PhoneAccountHandle(
165             new ComponentName("test", "sipComponentName"), "1", USER_HANDLE_17);
166     private static final PhoneAccountHandle TEL_PA_HANDLE_CURRENT = new PhoneAccountHandle(
167             new ComponentName("test", "telComponentName"), "2", Binder.getCallingUserHandle());
168     private static final PhoneAccountHandle SIP_PA_HANDLE_CURRENT = new PhoneAccountHandle(
169             new ComponentName("test", "sipComponentName"), "3", Binder.getCallingUserHandle());
170 
171     @Override
setUp()172     public void setUp() throws Exception {
173         super.setUp();
174         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
175         mComponentContextFixture.putBooleanResource(
176                 com.android.internal.R.bool.config_voice_capable, true);
177 
178         doReturn(mContext).when(mContext).getApplicationContext();
179         doNothing().when(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class),
180                 anyString());
181         TelecomServiceImpl telecomServiceImpl = new TelecomServiceImpl(
182                 mContext,
183                 mFakeCallsManager,
184                 mFakePhoneAccountRegistrar,
185                 mCallIntentProcessorAdapter,
186                 new UserCallIntentProcessorFactory() {
187                     @Override
188                     public UserCallIntentProcessor create(Context context, UserHandle userHandle) {
189                         return mUserCallIntentProcessor;
190                     }
191                 },
192                 mDefaultDialerManagerAdapter,
193                 mSubscriptionManagerAdapter,
194                 mLock);
195         mTSIBinder = telecomServiceImpl.getBinder();
196         mComponentContextFixture.setTelecomManager(mTelecomManager);
197         when(mTelecomManager.getDefaultDialerPackage()).thenReturn(DEFAULT_DIALER_PACKAGE);
198         when(mTelecomManager.getSystemDialerPackage()).thenReturn(DEFAULT_DIALER_PACKAGE);
199 
200         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
201         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
202 
203         doReturn(DEFAULT_DIALER_PACKAGE)
204                 .when(mDefaultDialerManagerAdapter)
205                 .getDefaultDialerApplication(any(Context.class));
206 
207         doReturn(true)
208                 .when(mDefaultDialerManagerAdapter)
209                 .isDefaultOrSystemDialer(any(Context.class), eq(DEFAULT_DIALER_PACKAGE));
210     }
211 
212     @SmallTest
testGetDefaultOutgoingPhoneAccount()213     public void testGetDefaultOutgoingPhoneAccount() throws RemoteException {
214         when(mFakePhoneAccountRegistrar
215                 .getOutgoingPhoneAccountForScheme(eq("tel"), any(UserHandle.class)))
216                 .thenReturn(TEL_PA_HANDLE_16);
217         when(mFakePhoneAccountRegistrar
218                 .getOutgoingPhoneAccountForScheme(eq("sip"), any(UserHandle.class)))
219                 .thenReturn(SIP_PA_HANDLE_17);
220         makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
221 
222         PhoneAccountHandle returnedHandleTel
223                 = mTSIBinder.getDefaultOutgoingPhoneAccount("tel", DEFAULT_DIALER_PACKAGE);
224         assertEquals(TEL_PA_HANDLE_16, returnedHandleTel);
225 
226         PhoneAccountHandle returnedHandleSip
227                 = mTSIBinder.getDefaultOutgoingPhoneAccount("sip", DEFAULT_DIALER_PACKAGE);
228         assertEquals(SIP_PA_HANDLE_17, returnedHandleSip);
229     }
230 
231     @SmallTest
testGetDefaultOutgoingPhoneAccountFailure()232     public void testGetDefaultOutgoingPhoneAccountFailure() throws RemoteException {
233         // make sure that the list of user profiles doesn't include anything the PhoneAccountHandles
234         // are associated with
235 
236         when(mFakePhoneAccountRegistrar
237                 .getOutgoingPhoneAccountForScheme(eq("tel"), any(UserHandle.class)))
238                 .thenReturn(TEL_PA_HANDLE_16);
239         when(mFakePhoneAccountRegistrar.getPhoneAccountUnchecked(TEL_PA_HANDLE_16)).thenReturn(
240                 makePhoneAccount(TEL_PA_HANDLE_16).build());
241         when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_READ_PHONE_STATE), anyInt(), anyString()))
242                 .thenReturn(AppOpsManager.MODE_IGNORED);
243         doThrow(new SecurityException()).when(mContext)
244                 .enforceCallingOrSelfPermission(eq(READ_PRIVILEGED_PHONE_STATE), anyString());
245 
246         PhoneAccountHandle returnedHandleTel
247                 = mTSIBinder.getDefaultOutgoingPhoneAccount("tel", "");
248         assertNull(returnedHandleTel);
249     }
250 
251     @SmallTest
testGetUserSelectedOutgoingPhoneAccount()252     public void testGetUserSelectedOutgoingPhoneAccount() throws RemoteException {
253         when(mFakePhoneAccountRegistrar.getUserSelectedOutgoingPhoneAccount(any(UserHandle.class)))
254                 .thenReturn(TEL_PA_HANDLE_16);
255         when(mFakePhoneAccountRegistrar.getPhoneAccountUnchecked(TEL_PA_HANDLE_16)).thenReturn(
256                 makeMultiUserPhoneAccount(TEL_PA_HANDLE_16).build());
257 
258         PhoneAccountHandle returnedHandle
259                 = mTSIBinder.getUserSelectedOutgoingPhoneAccount();
260         assertEquals(TEL_PA_HANDLE_16, returnedHandle);
261     }
262 
263     @SmallTest
testSetUserSelectedOutgoingPhoneAccount()264     public void testSetUserSelectedOutgoingPhoneAccount() throws RemoteException {
265         mTSIBinder.setUserSelectedOutgoingPhoneAccount(TEL_PA_HANDLE_16);
266         verify(mFakePhoneAccountRegistrar)
267                 .setUserSelectedOutgoingPhoneAccount(eq(TEL_PA_HANDLE_16), any(UserHandle.class));
268     }
269 
270     @SmallTest
testSetUserSelectedOutgoingPhoneAccountFailure()271     public void testSetUserSelectedOutgoingPhoneAccountFailure() throws RemoteException {
272         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
273                 anyString(), anyString());
274         try {
275             mTSIBinder.setUserSelectedOutgoingPhoneAccount(TEL_PA_HANDLE_16);
276         } catch (SecurityException e) {
277             // desired result
278         }
279         verify(mFakePhoneAccountRegistrar, never())
280                 .setUserSelectedOutgoingPhoneAccount(
281                         any(PhoneAccountHandle.class), any(UserHandle.class));
282     }
283 
284     @SmallTest
testGetCallCapablePhoneAccounts()285     public void testGetCallCapablePhoneAccounts() throws RemoteException {
286         List<PhoneAccountHandle> fullPHList = new ArrayList<PhoneAccountHandle>() {{
287             add(TEL_PA_HANDLE_16);
288             add(SIP_PA_HANDLE_17);
289         }};
290 
291         List<PhoneAccountHandle> smallPHList = new ArrayList<PhoneAccountHandle>() {{
292             add(SIP_PA_HANDLE_17);
293         }};
294         // Returns all phone accounts when getCallCapablePhoneAccounts is called.
295         when(mFakePhoneAccountRegistrar
296                 .getCallCapablePhoneAccounts(anyString(), eq(true), any(UserHandle.class)))
297                 .thenReturn(fullPHList);
298         // Returns only enabled phone accounts when getCallCapablePhoneAccounts is called.
299         when(mFakePhoneAccountRegistrar
300                 .getCallCapablePhoneAccounts(anyString(), eq(false), any(UserHandle.class)))
301                 .thenReturn(smallPHList);
302         makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
303 
304         assertEquals(fullPHList,
305                 mTSIBinder.getCallCapablePhoneAccounts(true, DEFAULT_DIALER_PACKAGE));
306         assertEquals(smallPHList,
307                 mTSIBinder.getCallCapablePhoneAccounts(false, DEFAULT_DIALER_PACKAGE));
308     }
309 
310     @SmallTest
testGetCallCapablePhoneAccountsFailure()311     public void testGetCallCapablePhoneAccountsFailure() throws RemoteException {
312         List<String> enforcedPermissions = new ArrayList<String>() {{
313             add(READ_PHONE_STATE);
314             add(READ_PRIVILEGED_PHONE_STATE);
315         }};
316         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
317                 argThat(new AnyStringIn(enforcedPermissions)), anyString());
318 
319         List<PhoneAccountHandle> result = null;
320         try {
321             result = mTSIBinder.getCallCapablePhoneAccounts(true, "");
322         } catch (SecurityException e) {
323             // intended behavior
324         }
325         assertNull(result);
326         verify(mFakePhoneAccountRegistrar, never())
327                 .getCallCapablePhoneAccounts(anyString(), anyBoolean(), any(UserHandle.class));
328     }
329 
330     @SmallTest
testGetPhoneAccountsSupportingScheme()331     public void testGetPhoneAccountsSupportingScheme() throws RemoteException {
332         List<PhoneAccountHandle> sipPHList = new ArrayList<PhoneAccountHandle>() {{
333             add(SIP_PA_HANDLE_17);
334         }};
335 
336         List<PhoneAccountHandle> telPHList = new ArrayList<PhoneAccountHandle>() {{
337             add(TEL_PA_HANDLE_16);
338         }};
339         when(mFakePhoneAccountRegistrar
340                 .getCallCapablePhoneAccounts(eq("tel"), anyBoolean(), any(UserHandle.class)))
341                 .thenReturn(telPHList);
342         when(mFakePhoneAccountRegistrar
343                 .getCallCapablePhoneAccounts(eq("sip"), anyBoolean(), any(UserHandle.class)))
344                 .thenReturn(sipPHList);
345         makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
346 
347         assertEquals(telPHList,
348                 mTSIBinder.getPhoneAccountsSupportingScheme("tel", DEFAULT_DIALER_PACKAGE));
349         assertEquals(sipPHList,
350                 mTSIBinder.getPhoneAccountsSupportingScheme("sip", DEFAULT_DIALER_PACKAGE));
351     }
352 
353     @SmallTest
testGetPhoneAccountsForPackage()354     public void testGetPhoneAccountsForPackage() throws RemoteException {
355         List<PhoneAccountHandle> phoneAccountHandleList = new ArrayList<PhoneAccountHandle>() {{
356             add(TEL_PA_HANDLE_16);
357             add(SIP_PA_HANDLE_17);
358         }};
359         when(mFakePhoneAccountRegistrar
360                 .getPhoneAccountsForPackage(anyString(), any(UserHandle.class)))
361                 .thenReturn(phoneAccountHandleList);
362         makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
363         assertEquals(phoneAccountHandleList,
364                 mTSIBinder.getPhoneAccountsForPackage(
365                         TEL_PA_HANDLE_16.getComponentName().getPackageName()));
366     }
367 
368     @SmallTest
testGetPhoneAccount()369     public void testGetPhoneAccount() throws RemoteException {
370         makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
371         assertEquals(TEL_PA_HANDLE_16, mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16)
372                 .getAccountHandle());
373         assertEquals(SIP_PA_HANDLE_17, mTSIBinder.getPhoneAccount(SIP_PA_HANDLE_17)
374                 .getAccountHandle());
375     }
376 
377     @SmallTest
testGetAllPhoneAccounts()378     public void testGetAllPhoneAccounts() throws RemoteException {
379         List<PhoneAccount> phoneAccountList = new ArrayList<PhoneAccount>() {{
380             add(makePhoneAccount(TEL_PA_HANDLE_16).build());
381             add(makePhoneAccount(SIP_PA_HANDLE_17).build());
382         }};
383         when(mFakePhoneAccountRegistrar.getAllPhoneAccounts(any(UserHandle.class)))
384                 .thenReturn(phoneAccountList);
385 
386         assertEquals(2, mTSIBinder.getAllPhoneAccounts().size());
387     }
388 
389     @SmallTest
testRegisterPhoneAccount()390     public void testRegisterPhoneAccount() throws RemoteException {
391         String packageNameToUse = "com.android.officialpackage";
392         PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName(
393                 packageNameToUse, "cs"), "test", Binder.getCallingUserHandle());
394         PhoneAccount phoneAccount = makePhoneAccount(phHandle).build();
395         doReturn(PackageManager.PERMISSION_GRANTED)
396                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
397 
398         registerPhoneAccountTestHelper(phoneAccount, true);
399     }
400 
401     @SmallTest
testRegisterPhoneAccountWithoutModifyPermission()402     public void testRegisterPhoneAccountWithoutModifyPermission() throws RemoteException {
403         // tests the case where the package does not have MODIFY_PHONE_STATE but is
404         // registering its own phone account as a third-party connection service
405         String packageNameToUse = "com.thirdparty.connectionservice";
406         PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName(
407                 packageNameToUse, "cs"), "asdf", Binder.getCallingUserHandle());
408         PhoneAccount phoneAccount = makePhoneAccount(phHandle).build();
409 
410         doReturn(PackageManager.PERMISSION_DENIED)
411                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
412         PackageManager pm = mContext.getPackageManager();
413         when(pm.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)).thenReturn(true);
414 
415         registerPhoneAccountTestHelper(phoneAccount, true);
416     }
417 
418     @SmallTest
testRegisterPhoneAccountWithoutModifyPermissionFailure()419     public void testRegisterPhoneAccountWithoutModifyPermissionFailure() throws RemoteException {
420         // tests the case where the third party package should not be allowed to register a phone
421         // account due to the lack of modify permission.
422         String packageNameToUse = "com.thirdparty.connectionservice";
423         PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName(
424                 packageNameToUse, "cs"), "asdf", Binder.getCallingUserHandle());
425         PhoneAccount phoneAccount = makePhoneAccount(phHandle).build();
426 
427         doReturn(PackageManager.PERMISSION_DENIED)
428                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
429         PackageManager pm = mContext.getPackageManager();
430         when(pm.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)).thenReturn(false);
431 
432         registerPhoneAccountTestHelper(phoneAccount, false);
433     }
434 
435     @SmallTest
testRegisterPhoneAccountWithoutSimSubscriptionPermissionFailure()436     public void testRegisterPhoneAccountWithoutSimSubscriptionPermissionFailure()
437             throws RemoteException {
438         String packageNameToUse = "com.thirdparty.connectionservice";
439         PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName(
440                 packageNameToUse, "cs"), "asdf", Binder.getCallingUserHandle());
441         PhoneAccount phoneAccount = makePhoneAccount(phHandle)
442                 .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION).build();
443 
444         doReturn(PackageManager.PERMISSION_GRANTED)
445                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
446         doThrow(new SecurityException())
447                 .when(mContext)
448                 .enforceCallingOrSelfPermission(eq(REGISTER_SIM_SUBSCRIPTION), anyString());
449 
450         registerPhoneAccountTestHelper(phoneAccount, false);
451     }
452 
453     @SmallTest
testRegisterPhoneAccountWithoutMultiUserPermissionFailure()454     public void testRegisterPhoneAccountWithoutMultiUserPermissionFailure()
455             throws Exception {
456         String packageNameToUse = "com.thirdparty.connectionservice";
457         PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName(
458                 packageNameToUse, "cs"), "asdf", Binder.getCallingUserHandle());
459         PhoneAccount phoneAccount = makeMultiUserPhoneAccount(phHandle).build();
460 
461         doReturn(PackageManager.PERMISSION_GRANTED)
462                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
463 
464         PackageManager packageManager = mContext.getPackageManager();
465         when(packageManager.getApplicationInfo(packageNameToUse, PackageManager.GET_META_DATA))
466                 .thenReturn(new ApplicationInfo());
467 
468         registerPhoneAccountTestHelper(phoneAccount, false);
469     }
470 
registerPhoneAccountTestHelper(PhoneAccount testPhoneAccount, boolean shouldSucceed)471     private void registerPhoneAccountTestHelper(PhoneAccount testPhoneAccount,
472             boolean shouldSucceed) throws RemoteException {
473         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
474         boolean didExceptionOccur = false;
475         try {
476             mTSIBinder.registerPhoneAccount(testPhoneAccount);
477         } catch (Exception e) {
478             didExceptionOccur = true;
479         }
480 
481         if (shouldSucceed) {
482             assertFalse(didExceptionOccur);
483             verify(mFakePhoneAccountRegistrar).registerPhoneAccount(testPhoneAccount);
484             verify(mContext).sendBroadcastAsUser(intentCaptor.capture(), eq(UserHandle.ALL),
485                     anyString());
486 
487             Intent capturedIntent = intentCaptor.getValue();
488             assertEquals(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED,
489                     capturedIntent.getAction());
490             Bundle intentExtras = capturedIntent.getExtras();
491             assertEquals(1, intentExtras.size());
492             assertEquals(testPhoneAccount.getAccountHandle(),
493                     intentExtras.get(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE));
494         } else {
495             assertTrue(didExceptionOccur);
496             verify(mFakePhoneAccountRegistrar, never())
497                     .registerPhoneAccount(any(PhoneAccount.class));
498             verify(mContext, never())
499                     .sendBroadcastAsUser(any(Intent.class), any(UserHandle.class), anyString());
500         }
501     }
502 
503     @SmallTest
testUnregisterPhoneAccount()504     public void testUnregisterPhoneAccount() throws RemoteException {
505         String packageNameToUse = "com.android.officialpackage";
506         PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName(
507                 packageNameToUse, "cs"), "test", Binder.getCallingUserHandle());
508 
509         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
510         doReturn(PackageManager.PERMISSION_GRANTED)
511                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
512 
513         mTSIBinder.unregisterPhoneAccount(phHandle);
514         verify(mFakePhoneAccountRegistrar).unregisterPhoneAccount(phHandle);
515         verify(mContext).sendBroadcastAsUser(intentCaptor.capture(), eq(UserHandle.ALL),
516                 anyString());
517         Intent capturedIntent = intentCaptor.getValue();
518         assertEquals(TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED,
519                 capturedIntent.getAction());
520         Bundle intentExtras = capturedIntent.getExtras();
521         assertEquals(1, intentExtras.size());
522         assertEquals(phHandle, intentExtras.get(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE));
523     }
524 
525     @SmallTest
testUnregisterPhoneAccountFailure()526     public void testUnregisterPhoneAccountFailure() throws RemoteException {
527         String packageNameToUse = "com.thirdparty.connectionservice";
528         PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName(
529                 packageNameToUse, "cs"), "asdf", Binder.getCallingUserHandle());
530 
531         doReturn(PackageManager.PERMISSION_DENIED)
532                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
533         PackageManager pm = mContext.getPackageManager();
534         when(pm.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)).thenReturn(false);
535 
536         try {
537             mTSIBinder.unregisterPhoneAccount(phHandle);
538         } catch (UnsupportedOperationException e) {
539             // expected behavior
540         }
541         verify(mFakePhoneAccountRegistrar, never())
542                 .unregisterPhoneAccount(any(PhoneAccountHandle.class));
543         verify(mContext, never())
544                 .sendBroadcastAsUser(any(Intent.class), any(UserHandle.class), anyString());
545     }
546 
547     @SmallTest
testAddNewIncomingCall()548     public void testAddNewIncomingCall() throws Exception {
549         PhoneAccount phoneAccount = makePhoneAccount(TEL_PA_HANDLE_CURRENT).build();
550         phoneAccount.setIsEnabled(true);
551         doReturn(phoneAccount).when(mFakePhoneAccountRegistrar).getPhoneAccount(
552                 eq(TEL_PA_HANDLE_CURRENT), any(UserHandle.class));
553         doNothing().when(mAppOpsManager).checkPackage(anyInt(), anyString());
554         Bundle extras = createSampleExtras();
555 
556         mTSIBinder.addNewIncomingCall(TEL_PA_HANDLE_CURRENT, extras);
557 
558         addCallTestHelper(TelecomManager.ACTION_INCOMING_CALL,
559                 CallIntentProcessor.KEY_IS_INCOMING_CALL, extras, false);
560     }
561 
562     @SmallTest
testAddNewIncomingCallFailure()563     public void testAddNewIncomingCallFailure() throws Exception {
564         try {
565             mTSIBinder.addNewIncomingCall(TEL_PA_HANDLE_16, null);
566         } catch (SecurityException e) {
567             // expected
568         }
569 
570         doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), anyString());
571 
572         try {
573             mTSIBinder.addNewIncomingCall(TEL_PA_HANDLE_CURRENT, null);
574         } catch (SecurityException e) {
575             // expected
576         }
577 
578         // Verify that neither of these attempts got through
579         verify(mCallIntentProcessorAdapter, never())
580                 .processIncomingCallIntent(any(CallsManager.class), any(Intent.class));
581     }
582 
583     @SmallTest
testAddNewUnknownCall()584     public void testAddNewUnknownCall() throws Exception {
585         PhoneAccount phoneAccount = makePhoneAccount(TEL_PA_HANDLE_CURRENT).build();
586         phoneAccount.setIsEnabled(true);
587         doReturn(phoneAccount).when(mFakePhoneAccountRegistrar).getPhoneAccount(
588                 eq(TEL_PA_HANDLE_CURRENT), any(UserHandle.class));
589         doNothing().when(mAppOpsManager).checkPackage(anyInt(), anyString());
590         Bundle extras = createSampleExtras();
591 
592         mTSIBinder.addNewUnknownCall(TEL_PA_HANDLE_CURRENT, extras);
593 
594         addCallTestHelper(TelecomManager.ACTION_NEW_UNKNOWN_CALL,
595                 CallIntentProcessor.KEY_IS_UNKNOWN_CALL, extras, true);
596     }
597 
598     @SmallTest
testAddNewUnknownCallFailure()599     public void testAddNewUnknownCallFailure() throws Exception {
600         try {
601             mTSIBinder.addNewUnknownCall(TEL_PA_HANDLE_16, null);
602         } catch (SecurityException e) {
603             // expected
604         }
605 
606         doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), anyString());
607 
608         try {
609             mTSIBinder.addNewUnknownCall(TEL_PA_HANDLE_CURRENT, null);
610         } catch (SecurityException e) {
611             // expected
612         }
613 
614         // Verify that neither of these attempts got through
615         verify(mCallIntentProcessorAdapter, never())
616                 .processIncomingCallIntent(any(CallsManager.class), any(Intent.class));
617     }
618 
addCallTestHelper(String expectedAction, String extraCallKey, Bundle expectedExtras, boolean isUnknown)619     private void addCallTestHelper(String expectedAction, String extraCallKey,
620             Bundle expectedExtras, boolean isUnknown) {
621         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
622         if (isUnknown) {
623             verify(mCallIntentProcessorAdapter).processUnknownCallIntent(any(CallsManager.class),
624                     intentCaptor.capture());
625         } else {
626             verify(mCallIntentProcessorAdapter).processIncomingCallIntent(any(CallsManager.class),
627                     intentCaptor.capture());
628         }
629         Intent capturedIntent = intentCaptor.getValue();
630         assertEquals(expectedAction, capturedIntent.getAction());
631         Bundle intentExtras = capturedIntent.getExtras();
632         assertEquals(TEL_PA_HANDLE_CURRENT,
633                 intentExtras.get(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE));
634         assertTrue(intentExtras.getBoolean(extraCallKey));
635 
636         if (isUnknown) {
637             for (String expectedKey : expectedExtras.keySet()) {
638                 assertTrue(intentExtras.containsKey(expectedKey));
639                 assertEquals(expectedExtras.get(expectedKey), intentExtras.get(expectedKey));
640             }
641         }
642         else {
643             assertTrue(areBundlesEqual(expectedExtras,
644                     (Bundle) intentExtras.get(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)));
645         }
646     }
647 
648     @SmallTest
testPlaceCallWithNonEmergencyPermission()649     public void testPlaceCallWithNonEmergencyPermission() throws Exception {
650         Uri handle = Uri.parse("tel:6505551234");
651         Bundle extras = createSampleExtras();
652 
653         when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString()))
654                 .thenReturn(AppOpsManager.MODE_ALLOWED);
655         doReturn(PackageManager.PERMISSION_GRANTED)
656                 .when(mContext).checkCallingPermission(CALL_PHONE);
657 
658         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
659         placeCallTestHelper(handle, extras, true);
660     }
661 
662     @SmallTest
testPlaceCallWithAppOpsOff()663     public void testPlaceCallWithAppOpsOff() throws Exception {
664         Uri handle = Uri.parse("tel:6505551234");
665         Bundle extras = createSampleExtras();
666 
667         when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString()))
668                 .thenReturn(AppOpsManager.MODE_IGNORED);
669         doReturn(PackageManager.PERMISSION_GRANTED)
670                 .when(mContext).checkCallingPermission(CALL_PHONE);
671 
672         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
673         placeCallTestHelper(handle, extras, false);
674     }
675 
676     @SmallTest
testPlaceCallWithNoCallingPermission()677     public void testPlaceCallWithNoCallingPermission() throws Exception {
678         Uri handle = Uri.parse("tel:6505551234");
679         Bundle extras = createSampleExtras();
680 
681         when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString()))
682                 .thenReturn(AppOpsManager.MODE_ALLOWED);
683         doReturn(PackageManager.PERMISSION_DENIED)
684                 .when(mContext).checkCallingPermission(CALL_PHONE);
685 
686         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
687         placeCallTestHelper(handle, extras, false);
688     }
689 
placeCallTestHelper(Uri expectedHandle, Bundle expectedExtras, boolean shouldNonEmergencyBeAllowed)690     private void placeCallTestHelper(Uri expectedHandle, Bundle expectedExtras,
691             boolean shouldNonEmergencyBeAllowed) {
692         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
693         verify(mUserCallIntentProcessor).processIntent(intentCaptor.capture(), anyString(),
694                 eq(shouldNonEmergencyBeAllowed));
695         Intent capturedIntent = intentCaptor.getValue();
696         assertEquals(Intent.ACTION_CALL, capturedIntent.getAction());
697         assertEquals(expectedHandle, capturedIntent.getData());
698         assertTrue(areBundlesEqual(expectedExtras, capturedIntent.getExtras()));
699     }
700 
701     @SmallTest
testPlaceCallFailure()702     public void testPlaceCallFailure() throws Exception {
703         Uri handle = Uri.parse("tel:6505551234");
704         Bundle extras = createSampleExtras();
705 
706         doThrow(new SecurityException())
707                 .when(mContext).enforceCallingOrSelfPermission(eq(CALL_PHONE), anyString());
708 
709         try {
710             mTSIBinder.placeCall(handle, extras, "arbitrary_package_name");
711         } catch (SecurityException e) {
712             // expected
713         }
714 
715         verify(mUserCallIntentProcessor, never())
716                 .processIntent(any(Intent.class), anyString(), anyBoolean());
717     }
718 
719     @SmallTest
testSetDefaultDialer()720     public void testSetDefaultDialer() throws Exception {
721         String packageName = "sample.package";
722 
723         doReturn(true)
724                 .when(mDefaultDialerManagerAdapter)
725                 .setDefaultDialerApplication(any(Context.class), eq(packageName));
726 
727         mTSIBinder.setDefaultDialer(packageName);
728 
729         verify(mDefaultDialerManagerAdapter).setDefaultDialerApplication(any(Context.class),
730                 eq(packageName));
731         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
732         verify(mContext).sendBroadcastAsUser(intentCaptor.capture(), any(UserHandle.class));
733         Intent capturedIntent = intentCaptor.getValue();
734         assertEquals(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED, capturedIntent.getAction());
735         String packageNameExtra = capturedIntent.getStringExtra(
736                 TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME);
737         assertEquals(packageName, packageNameExtra);
738     }
739 
740     @SmallTest
testSetDefaultDialerNoModifyPhoneStatePermission()741     public void testSetDefaultDialerNoModifyPhoneStatePermission() throws Exception {
742         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
743                 eq(MODIFY_PHONE_STATE), anyString());
744         setDefaultDialerFailureTestHelper();
745     }
746 
747     @SmallTest
testSetDefaultDialerNoWriteSecureSettingsPermission()748     public void testSetDefaultDialerNoWriteSecureSettingsPermission() throws Exception {
749         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
750                 eq(WRITE_SECURE_SETTINGS), anyString());
751         setDefaultDialerFailureTestHelper();
752     }
753 
setDefaultDialerFailureTestHelper()754     private void setDefaultDialerFailureTestHelper() throws Exception {
755         boolean exceptionThrown = false;
756         try {
757             mTSIBinder.setDefaultDialer(DEFAULT_DIALER_PACKAGE);
758         } catch (SecurityException e) {
759             exceptionThrown = true;
760         }
761         assertTrue(exceptionThrown);
762         verify(mDefaultDialerManagerAdapter, never()).setDefaultDialerApplication(
763                 any(Context.class), anyString());
764         verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class));
765     }
766 
767     @SmallTest
testIsVoicemailNumber()768     public void testIsVoicemailNumber() throws Exception {
769         String vmNumber = "010";
770         makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_CURRENT);
771 
772         doReturn(true).when(mFakePhoneAccountRegistrar).isVoiceMailNumber(TEL_PA_HANDLE_CURRENT,
773                 vmNumber);
774         assertTrue(mTSIBinder.isVoiceMailNumber(TEL_PA_HANDLE_CURRENT,
775                 vmNumber, DEFAULT_DIALER_PACKAGE));
776     }
777 
778     @SmallTest
testIsVoicemailNumberAccountNotVisibleFailure()779     public void testIsVoicemailNumberAccountNotVisibleFailure() throws Exception {
780         String vmNumber = "010";
781 
782         doReturn(true).when(mFakePhoneAccountRegistrar).isVoiceMailNumber(TEL_PA_HANDLE_CURRENT,
783                 vmNumber);
784 
785         when(mFakePhoneAccountRegistrar.getPhoneAccount(TEL_PA_HANDLE_CURRENT,
786                 Binder.getCallingUserHandle())).thenReturn(null);
787         assertFalse(mTSIBinder
788                 .isVoiceMailNumber(TEL_PA_HANDLE_CURRENT, vmNumber, DEFAULT_DIALER_PACKAGE));
789     }
790 
791     @SmallTest
testGetVoicemailNumberWithNullAccountHandle()792     public void testGetVoicemailNumberWithNullAccountHandle() throws Exception {
793         when(mFakePhoneAccountRegistrar.getPhoneAccount(isNull(PhoneAccountHandle.class),
794                 eq(Binder.getCallingUserHandle())))
795                 .thenReturn(makePhoneAccount(TEL_PA_HANDLE_CURRENT).build());
796         int subId = 58374;
797         String vmNumber = "543";
798         doReturn(subId).when(mSubscriptionManagerAdapter).getDefaultVoiceSubId();
799 
800         TelephonyManager mockTelephonyManager =
801                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
802         when(mockTelephonyManager.getVoiceMailNumber(subId)).thenReturn(vmNumber);
803 
804         assertEquals(vmNumber, mTSIBinder.getVoiceMailNumber(null, DEFAULT_DIALER_PACKAGE));
805     }
806 
807     @SmallTest
testGetVoicemailNumberWithNonNullAccountHandle()808     public void testGetVoicemailNumberWithNonNullAccountHandle() throws Exception {
809         when(mFakePhoneAccountRegistrar.getPhoneAccount(eq(TEL_PA_HANDLE_CURRENT),
810                 eq(Binder.getCallingUserHandle())))
811                 .thenReturn(makePhoneAccount(TEL_PA_HANDLE_CURRENT).build());
812         int subId = 58374;
813         String vmNumber = "543";
814 
815         TelephonyManager mockTelephonyManager =
816                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
817         when(mockTelephonyManager.getVoiceMailNumber(subId)).thenReturn(vmNumber);
818         when(mFakePhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(TEL_PA_HANDLE_CURRENT))
819                 .thenReturn(subId);
820 
821         assertEquals(vmNumber,
822                 mTSIBinder.getVoiceMailNumber(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE));
823     }
824 
825     @SmallTest
testGetLine1Number()826     public void testGetLine1Number() throws Exception {
827         int subId = 58374;
828         String line1Number = "9482752023479";
829         makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_CURRENT);
830         when(mFakePhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(TEL_PA_HANDLE_CURRENT))
831                 .thenReturn(subId);
832         TelephonyManager mockTelephonyManager =
833                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
834         when(mockTelephonyManager.getLine1Number(subId)).thenReturn(line1Number);
835 
836         assertEquals(line1Number,
837                 mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE));
838     }
839 
840     @SmallTest
testEndCallWithRingingForegroundCall()841     public void testEndCallWithRingingForegroundCall() throws Exception {
842         Call call = mock(Call.class);
843         when(call.getState()).thenReturn(CallState.RINGING);
844         when(mFakeCallsManager.getForegroundCall()).thenReturn(call);
845         assertTrue(mTSIBinder.endCall());
846         verify(call).reject(false, null);
847     }
848 
849     @SmallTest
testEndCallWithNonRingingForegroundCall()850     public void testEndCallWithNonRingingForegroundCall() throws Exception {
851         Call call = mock(Call.class);
852         when(call.getState()).thenReturn(CallState.ACTIVE);
853         when(mFakeCallsManager.getForegroundCall()).thenReturn(call);
854         assertTrue(mTSIBinder.endCall());
855         verify(call).disconnect();
856     }
857 
858     @SmallTest
testEndCallWithNoForegroundCall()859     public void testEndCallWithNoForegroundCall() throws Exception {
860         Call call = mock(Call.class);
861         when(call.getState()).thenReturn(CallState.ACTIVE);
862         when(mFakeCallsManager.getFirstCallWithState(anyInt(), anyInt(), anyInt(), anyInt()))
863                 .thenReturn(call);
864         assertTrue(mTSIBinder.endCall());
865         verify(call).disconnect();
866     }
867 
868     @SmallTest
testEndCallWithNoCalls()869     public void testEndCallWithNoCalls() throws Exception {
870         assertFalse(mTSIBinder.endCall());
871     }
872 
873     @SmallTest
testAcceptRingingCall()874     public void testAcceptRingingCall() throws Exception {
875         Call call = mock(Call.class);
876         when(mFakeCallsManager.getFirstCallWithState(any(int[].class)))
877                 .thenReturn(call);
878         // Not intended to be a real video state. Here to ensure that the call will be answered
879         // with whatever video state it's currently in.
880         int fakeVideoState = 29578215;
881         when(call.getVideoState()).thenReturn(fakeVideoState);
882         mTSIBinder.acceptRingingCall();
883         verify(call).answer(fakeVideoState);
884     }
885 
886     @SmallTest
testAcceptRingingCallWithValidVideoState()887     public void testAcceptRingingCallWithValidVideoState() throws Exception {
888         Call call = mock(Call.class);
889         when(mFakeCallsManager.getFirstCallWithState(any(int[].class)))
890                 .thenReturn(call);
891         // Not intended to be a real video state. Here to ensure that the call will be answered
892         // with the video state passed in to acceptRingingCallWithVideoState
893         int fakeVideoState = 29578215;
894         int realVideoState = VideoProfile.STATE_RX_ENABLED | VideoProfile.STATE_TX_ENABLED;
895         when(call.getVideoState()).thenReturn(fakeVideoState);
896         mTSIBinder.acceptRingingCallWithVideoState(realVideoState);
897         verify(call).answer(realVideoState);
898     }
899 
900     /**
901      * Register phone accounts for the supplied PhoneAccountHandles to make them
902      * visible to all users (via the isVisibleToCaller method in TelecomServiceImpl.
903      * @param handles the handles for which phone accounts should be created for.
904      */
makeAccountsVisibleToAllUsers(PhoneAccountHandle... handles)905     private void makeAccountsVisibleToAllUsers(PhoneAccountHandle... handles) {
906         for (PhoneAccountHandle ph : handles) {
907             when(mFakePhoneAccountRegistrar.getPhoneAccountUnchecked(eq(ph))).thenReturn(
908                     makeMultiUserPhoneAccount(ph).build());
909             when(mFakePhoneAccountRegistrar
910                     .getPhoneAccount(eq(ph), any(UserHandle.class), anyBoolean()))
911                     .thenReturn(makeMultiUserPhoneAccount(ph).build());
912             when(mFakePhoneAccountRegistrar
913                     .getPhoneAccount(eq(ph), any(UserHandle.class)))
914                     .thenReturn(makeMultiUserPhoneAccount(ph).build());
915         }
916     }
917 
makeMultiUserPhoneAccount(PhoneAccountHandle paHandle)918     private PhoneAccount.Builder makeMultiUserPhoneAccount(PhoneAccountHandle paHandle) {
919         PhoneAccount.Builder paBuilder = makePhoneAccount(paHandle);
920         paBuilder.setCapabilities(PhoneAccount.CAPABILITY_MULTI_USER);
921         return paBuilder;
922     }
923 
makePhoneAccount(PhoneAccountHandle paHandle)924     private PhoneAccount.Builder makePhoneAccount(PhoneAccountHandle paHandle) {
925         return new PhoneAccount.Builder(paHandle, "testLabel");
926     }
927 
createSampleExtras()928     private Bundle createSampleExtras() {
929         Bundle extras = new Bundle();
930         extras.putString("test_key", "test_value");
931         return extras;
932     }
933 
areBundlesEqual(Bundle b1, Bundle b2)934     private static boolean areBundlesEqual(Bundle b1, Bundle b2) {
935         for (String key1 : b1.keySet()) {
936             if (!b1.get(key1).equals(b2.get(key1))) {
937                 return false;
938             }
939         }
940 
941         for (String key2 : b2.keySet()) {
942             if (!b2.get(key2).equals(b1.get(key2))) {
943                 return false;
944             }
945         }
946         return true;
947     }
948 }
949