1 /* 2 * Copyright (C) 2018 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.settings.accounts; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.anyString; 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.never; 26 import static org.mockito.Mockito.spy; 27 import static org.mockito.Mockito.verify; 28 29 import android.accounts.Account; 30 import android.content.ContentProvider; 31 import android.content.ContentResolver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.pm.ApplicationInfo; 35 import android.content.pm.PackageInfo; 36 import android.content.pm.ProviderInfo; 37 import android.content.pm.ResolveInfo; 38 import android.graphics.Bitmap; 39 import android.net.Uri; 40 import android.os.Bundle; 41 import android.widget.ImageView; 42 43 import com.android.settings.homepage.SettingsHomepageActivity; 44 import com.android.settings.testutils.shadow.ShadowUserManager; 45 46 import org.junit.Before; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 import org.mockito.MockitoAnnotations; 50 import org.robolectric.Robolectric; 51 import org.robolectric.RobolectricTestRunner; 52 import org.robolectric.RuntimeEnvironment; 53 import org.robolectric.android.controller.ActivityController; 54 import org.robolectric.annotation.Config; 55 import org.robolectric.annotation.Implementation; 56 import org.robolectric.annotation.Implements; 57 import org.robolectric.shadow.api.Shadow; 58 import org.robolectric.shadows.ShadowContentResolver; 59 import org.robolectric.shadows.ShadowPackageManager; 60 61 @RunWith(RobolectricTestRunner.class) 62 @Config(shadows = ShadowUserManager.class) 63 public class AvatarViewMixinTest { 64 private static final String FAKE_ACCOUNT = "test@domain.com"; 65 private static final String FAKE_DOMAIN = "domain.com"; 66 private static final String FAKE_AUTHORITY = "authority.domain.com"; 67 private static final String METHOD_GET_ACCOUNT_AVATAR = "getAccountAvatar"; 68 69 private Context mContext; 70 private ImageView mImageView; 71 private ActivityController mController; 72 private SettingsHomepageActivity mActivity; 73 74 @Before setUp()75 public void setUp() { 76 MockitoAnnotations.initMocks(this); 77 mContext = RuntimeEnvironment.application; 78 mImageView = new ImageView(mContext); 79 mController = Robolectric.buildActivity(SettingsHomepageActivity.class).create(); 80 mActivity = (SettingsHomepageActivity) mController.get(); 81 } 82 83 @Test hasAccount_useDefaultAccountData_returnFalse()84 public void hasAccount_useDefaultAccountData_returnFalse() { 85 final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView); 86 assertThat(avatarViewMixin.hasAccount()).isFalse(); 87 } 88 89 @Test 90 @Config(shadows = ShadowAccountFeatureProviderImpl.class) hasAccount_useShadowAccountData_returnTrue()91 public void hasAccount_useShadowAccountData_returnTrue() { 92 final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView); 93 assertThat(avatarViewMixin.hasAccount()).isTrue(); 94 } 95 96 @Test onStart_useMockAvatarViewMixin_shouldBeExecuted()97 public void onStart_useMockAvatarViewMixin_shouldBeExecuted() { 98 final AvatarViewMixin mockAvatar = spy(new AvatarViewMixin(mActivity, mImageView)); 99 100 mActivity.getLifecycle().addObserver(mockAvatar); 101 mController.start(); 102 103 verify(mockAvatar).hasAccount(); 104 } 105 106 @Test onStart_noAccount_mAccountNameShouldBeNull()107 public void onStart_noAccount_mAccountNameShouldBeNull() { 108 final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView); 109 avatarViewMixin.mAccountName = FAKE_ACCOUNT; 110 111 avatarViewMixin.onStart(); 112 113 assertThat(avatarViewMixin.mAccountName).isNull(); 114 } 115 116 @Test queryProviderAuthority_useShadowPackagteManager_returnNull()117 public void queryProviderAuthority_useShadowPackagteManager_returnNull() { 118 final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView); 119 120 assertThat(avatarViewMixin.queryProviderAuthority()).isNull(); 121 } 122 123 @Test queryProviderAuthority_useNewShadowPackagteManager_returnAuthority()124 public void queryProviderAuthority_useNewShadowPackagteManager_returnAuthority() { 125 final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView); 126 ShadowPackageManager shadowPackageManager = Shadow.extract(mContext.getPackageManager()); 127 final PackageInfo accountProvider = new PackageInfo(); 128 accountProvider.packageName = "test.pkg"; 129 accountProvider.applicationInfo = new ApplicationInfo(); 130 accountProvider.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; 131 accountProvider.applicationInfo.packageName = accountProvider.packageName; 132 accountProvider.providers = new ProviderInfo[1]; 133 accountProvider.providers[0] = new ProviderInfo(); 134 accountProvider.providers[0].authority = FAKE_AUTHORITY; 135 accountProvider.providers[0].packageName = accountProvider.packageName; 136 accountProvider.providers[0].name = "test.class"; 137 accountProvider.providers[0].applicationInfo = accountProvider.applicationInfo; 138 139 final ResolveInfo resolveInfo = new ResolveInfo(); 140 resolveInfo.providerInfo = accountProvider.providers[0]; 141 shadowPackageManager.addResolveInfoForIntent(AvatarViewMixin.INTENT_GET_ACCOUNT_DATA, 142 resolveInfo); 143 assertThat(avatarViewMixin.queryProviderAuthority()).isEqualTo(FAKE_AUTHORITY); 144 } 145 146 @Test callWithGetAccountAvatarMethod_useFakeData_shouldReturnAccountNameAndAvatar()147 public void callWithGetAccountAvatarMethod_useFakeData_shouldReturnAccountNameAndAvatar() { 148 final ContentResolver contentResolver = mContext.getContentResolver(); 149 final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority( 150 FAKE_AUTHORITY).build(); 151 final ContentProvider mockContentProvider = mock(ContentProvider.class); 152 153 ShadowContentResolver.registerProviderInternal(FAKE_AUTHORITY, mockContentProvider); 154 155 final Bundle bundle = new Bundle(); 156 final Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 157 bundle.putParcelable("account_avatar", bitmap); 158 bundle.putString("account_name", FAKE_ACCOUNT); 159 doReturn(bundle).when(mockContentProvider).call(anyString(), anyString(), 160 any(Bundle.class)); 161 162 contentResolver.call(uri, METHOD_GET_ACCOUNT_AVATAR, null /* arg */, null /* extras */); 163 164 final Object object = bundle.getParcelable("account_avatar"); 165 assertThat(object instanceof Bitmap).isTrue(); 166 assertThat(bundle.getString("account_name")).isEqualTo(FAKE_ACCOUNT); 167 } 168 169 @Test onClickAvatar_withEmptyUri_startActivityShouldNotBeExecuted()170 public void onClickAvatar_withEmptyUri_startActivityShouldNotBeExecuted() { 171 final SettingsHomepageActivity activity = spy((SettingsHomepageActivity) mController.get()); 172 final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(activity, mImageView); 173 174 mImageView.performClick(); 175 176 verify(activity, never()).startActivity(any(Intent.class)); 177 } 178 179 @Implements(value = AccountFeatureProviderImpl.class) 180 public static class ShadowAccountFeatureProviderImpl { 181 182 @Implementation getAccounts(Context context)183 protected Account[] getAccounts(Context context) { 184 return new Account[]{new Account(FAKE_ACCOUNT, FAKE_DOMAIN)}; 185 } 186 } 187 } 188