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