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 package com.android.settings.location; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static org.mockito.Matchers.any; 20 import static org.mockito.Matchers.anyInt; 21 import static org.mockito.Mockito.doNothing; 22 import static org.mockito.Mockito.never; 23 import static org.mockito.Mockito.spy; 24 import static org.mockito.Mockito.times; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.arch.lifecycle.LifecycleOwner; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.pm.ActivityInfo; 33 import android.content.pm.ApplicationInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.PackageManager.NameNotFoundException; 36 import android.content.pm.ResolveInfo; 37 import android.content.res.Resources; 38 import android.location.LocationManager; 39 import android.os.Bundle; 40 import android.support.v7.preference.Preference; 41 import android.support.v7.preference.PreferenceCategory; 42 43 import com.android.settings.testutils.SettingsRobolectricTestRunner; 44 import com.android.settingslib.core.lifecycle.Lifecycle; 45 46 import org.junit.Before; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 import org.mockito.ArgumentCaptor; 50 import org.mockito.Mock; 51 import org.mockito.MockitoAnnotations; 52 import org.robolectric.RuntimeEnvironment; 53 54 import java.util.ArrayList; 55 import java.util.List; 56 57 @RunWith(SettingsRobolectricTestRunner.class) 58 public class LocationFooterPreferenceControllerTest { 59 60 @Mock 61 private PreferenceCategory mPreferenceCategory; 62 @Mock 63 private PackageManager mPackageManager; 64 @Mock 65 private Resources mResources; 66 private Context mContext; 67 private LocationFooterPreferenceController mController; 68 private LifecycleOwner mLifecycleOwner; 69 private Lifecycle mLifecycle; 70 private static final int TEST_RES_ID = 1234; 71 private static final String TEST_TEXT = "text"; 72 73 @Before setUp()74 public void setUp() throws NameNotFoundException { 75 MockitoAnnotations.initMocks(this); 76 mContext = spy(RuntimeEnvironment.application); 77 when(mContext.getPackageManager()).thenReturn(mPackageManager); 78 mLifecycleOwner = () -> mLifecycle; 79 mLifecycle = new Lifecycle(mLifecycleOwner); 80 when(mPreferenceCategory.getContext()).thenReturn(mContext); 81 mController = spy(new LocationFooterPreferenceController(mContext, mLifecycle)); 82 when(mPackageManager.getResourcesForApplication(any(ApplicationInfo.class))) 83 .thenReturn(mResources); 84 when(mResources.getString(TEST_RES_ID)).thenReturn(TEST_TEXT); 85 doNothing().when(mPreferenceCategory).removeAll(); 86 } 87 88 @Test isAvailable_hasValidFooter_returnsTrue()89 public void isAvailable_hasValidFooter_returnsTrue() throws NameNotFoundException { 90 final List<ResolveInfo> testResolveInfos = new ArrayList<>(); 91 testResolveInfos.add( 92 getTestResolveInfo(/*isSystemApp*/ true, /*hasRequiredMetadata*/ true)); 93 when(mPackageManager.queryBroadcastReceivers(any(Intent.class), anyInt())) 94 .thenReturn(testResolveInfos); 95 96 assertThat(mController.isAvailable()).isTrue(); 97 } 98 99 @Test isAvailable_noSystemApp_returnsFalse()100 public void isAvailable_noSystemApp_returnsFalse() throws NameNotFoundException { 101 final List<ResolveInfo> testResolveInfos = new ArrayList<>(); 102 testResolveInfos.add( 103 getTestResolveInfo(/*isSystemApp*/ false, /*hasRequiredMetadata*/ true)); 104 when(mPackageManager.queryBroadcastReceivers(any(Intent.class), anyInt())) 105 .thenReturn(testResolveInfos); 106 assertThat(mController.isAvailable()).isFalse(); 107 } 108 109 @Test isAvailable_noRequiredMetadata_returnsFalse()110 public void isAvailable_noRequiredMetadata_returnsFalse() throws NameNotFoundException { 111 final List<ResolveInfo> testResolveInfos = new ArrayList<>(); 112 testResolveInfos.add( 113 getTestResolveInfo(/*isSystemApp*/ true, /*hasRequiredMetadata*/ false)); 114 when(mPackageManager.queryBroadcastReceivers(any(Intent.class), anyInt())) 115 .thenReturn(testResolveInfos); 116 assertThat(mController.isAvailable()).isFalse(); 117 } 118 119 @Test sendBroadcastFooterInject()120 public void sendBroadcastFooterInject() { 121 ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); 122 final ActivityInfo activityInfo = 123 getTestResolveInfo(/*isSystemApp*/ true, /*hasRequiredMetadata*/ true).activityInfo; 124 mController.sendBroadcastFooterDisplayed( 125 new ComponentName(activityInfo.packageName, activityInfo.name)); 126 verify(mContext).sendBroadcast(intent.capture()); 127 assertThat(intent.getValue().getAction()) 128 .isEqualTo(LocationManager.SETTINGS_FOOTER_DISPLAYED_ACTION); 129 } 130 131 @Test updateState_sendBroadcast()132 public void updateState_sendBroadcast() throws NameNotFoundException { 133 final List<ResolveInfo> testResolveInfos = new ArrayList<>(); 134 testResolveInfos.add( 135 getTestResolveInfo(/*isSystemApp*/ true, /*hasRequiredMetadata*/ true)); 136 when(mPackageManager.queryBroadcastReceivers(any(), anyInt())) 137 .thenReturn(testResolveInfos); 138 mController.updateState(mPreferenceCategory); 139 ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); 140 verify(mContext).sendBroadcast(intent.capture()); 141 assertThat(intent.getValue().getAction()) 142 .isEqualTo(LocationManager.SETTINGS_FOOTER_DISPLAYED_ACTION); 143 } 144 145 @Test updateState_addPreferences()146 public void updateState_addPreferences() throws NameNotFoundException { 147 final List<ResolveInfo> testResolveInfos = new ArrayList<>(); 148 testResolveInfos.add( 149 getTestResolveInfo(/*isSystemApp*/ true, /*hasRequiredMetadata*/ true)); 150 when(mPackageManager.queryBroadcastReceivers(any(Intent.class), anyInt())) 151 .thenReturn(testResolveInfos); 152 mController.updateState(mPreferenceCategory); 153 ArgumentCaptor<Preference> pref = ArgumentCaptor.forClass(Preference.class); 154 verify(mPreferenceCategory).addPreference(pref.capture()); 155 assertThat(pref.getValue().getTitle()).isEqualTo(TEST_TEXT); 156 } 157 158 @Test updateState_notSystemApp_ignore()159 public void updateState_notSystemApp_ignore() throws NameNotFoundException { 160 final List<ResolveInfo> testResolveInfos = new ArrayList<>(); 161 testResolveInfos.add( 162 getTestResolveInfo(/*isSystemApp*/ false, /*hasRequiredMetadata*/ true)); 163 when(mPackageManager.queryBroadcastReceivers(any(Intent.class), anyInt())) 164 .thenReturn(testResolveInfos); 165 mController.updateState(mPreferenceCategory); 166 verify(mPreferenceCategory, never()).addPreference(any(Preference.class)); 167 verify(mContext, never()).sendBroadcast(any(Intent.class)); 168 } 169 170 @Test updateState_thenOnPause_sendBroadcasts()171 public void updateState_thenOnPause_sendBroadcasts() throws NameNotFoundException { 172 final List<ResolveInfo> testResolveInfos = new ArrayList<>(); 173 testResolveInfos.add( 174 getTestResolveInfo(/*isSystemApp*/ true, /*hasRequiredMetadata*/ true)); 175 when(mPackageManager.queryBroadcastReceivers(any(Intent.class), anyInt())) 176 .thenReturn(testResolveInfos); 177 mController.updateState(mPreferenceCategory); 178 ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); 179 verify(mContext).sendBroadcast(intent.capture()); 180 assertThat(intent.getValue().getAction()) 181 .isEqualTo(LocationManager.SETTINGS_FOOTER_DISPLAYED_ACTION); 182 183 mController.onPause(); 184 verify(mContext, times(2)).sendBroadcast(intent.capture()); 185 assertThat(intent.getValue().getAction()) 186 .isEqualTo(LocationManager.SETTINGS_FOOTER_REMOVED_ACTION); 187 } 188 189 @Test onPause_doNotSendBroadcast()190 public void onPause_doNotSendBroadcast() { 191 mController.onPause(); 192 verify(mContext, never()).sendBroadcast(any(Intent.class)); 193 } 194 195 /** 196 * Returns a ResolveInfo object for testing 197 * @param isSystemApp If true, the application is a system app. 198 * @param hasRequiredMetaData If true, the broadcast receiver has a valid value for 199 * {@link LocationManager#METADATA_SETTINGS_FOOTER_STRING} 200 */ getTestResolveInfo(boolean isSystemApp, boolean hasRequiredMetaData)201 private ResolveInfo getTestResolveInfo(boolean isSystemApp, boolean hasRequiredMetaData) { 202 ResolveInfo testResolveInfo = new ResolveInfo(); 203 ApplicationInfo testAppInfo = new ApplicationInfo(); 204 if (isSystemApp) { 205 testAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM; 206 } 207 ActivityInfo testActivityInfo = new ActivityInfo(); 208 testActivityInfo.name = "TestActivityName"; 209 testActivityInfo.packageName = "TestPackageName"; 210 testActivityInfo.applicationInfo = testAppInfo; 211 if (hasRequiredMetaData) { 212 testActivityInfo.metaData = new Bundle(); 213 testActivityInfo.metaData.putInt( 214 LocationManager.METADATA_SETTINGS_FOOTER_STRING, TEST_RES_ID); 215 } 216 testResolveInfo.activityInfo = testActivityInfo; 217 return testResolveInfo; 218 } 219 } 220