1 /* 2 * Copyright (C) 2019 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.customization.model.theme; 17 18 import static com.android.customization.model.ResourceConstants.ANDROID_PACKAGE; 19 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_COLOR; 20 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_FONT; 21 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_ANDROID; 22 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_SETTINGS; 23 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_SYSUI; 24 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SHAPE; 25 import static com.android.customization.model.ResourceConstants.SETTINGS_PACKAGE; 26 import static com.android.customization.model.ResourceConstants.SYSUI_PACKAGE; 27 import static com.android.customization.model.ResourceConstants.THEME_SETTING; 28 29 import static junit.framework.Assert.assertFalse; 30 import static junit.framework.Assert.assertTrue; 31 import static junit.framework.TestCase.assertEquals; 32 33 import static org.mockito.Mockito.mock; 34 import static org.mockito.Mockito.spy; 35 import static org.mockito.Mockito.verify; 36 import static org.mockito.Mockito.when; 37 38 import android.provider.Settings; 39 40 import androidx.annotation.Nullable; 41 import androidx.fragment.app.FragmentActivity; 42 43 import com.android.customization.model.CustomizationManager.Callback; 44 import com.android.customization.model.CustomizationManager.OptionsFetchedListener; 45 import com.android.customization.model.theme.custom.CustomTheme; 46 import com.android.customization.module.ThemesUserEventLogger; 47 import com.android.customization.testutils.OverlayManagerMocks; 48 49 import org.json.JSONObject; 50 import org.junit.After; 51 import org.junit.Before; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 import org.mockito.Mock; 55 import org.mockito.MockitoAnnotations; 56 import org.robolectric.Robolectric; 57 import org.robolectric.RobolectricTestRunner; 58 59 @RunWith(RobolectricTestRunner.class) 60 public class ThemeManagerTest { 61 62 @Mock OverlayManagerCompat mMockOm; 63 @Mock ThemesUserEventLogger mThemesUserEventLogger; 64 @Mock ThemeBundleProvider mThemeBundleProvider; 65 private OverlayManagerMocks mMockOmHelper; 66 private ThemeManager mThemeManager; 67 private FragmentActivity mActivity; 68 69 @Before setUp()70 public void setUp() { 71 MockitoAnnotations.initMocks(this); 72 FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).get(); 73 mActivity = spy(activity); 74 mMockOmHelper = new OverlayManagerMocks(); 75 mMockOmHelper.setUpMock(mMockOm); 76 mThemeManager = new ThemeManager(mThemeBundleProvider, activity, 77 mMockOm, mThemesUserEventLogger); 78 } 79 80 @After cleanUp()81 public void cleanUp() { 82 mMockOmHelper.clearOverlays(); 83 } 84 85 @Test apply_WithDefaultTheme_StoresEmptyJsonString()86 public void apply_WithDefaultTheme_StoresEmptyJsonString() { 87 mMockOmHelper.addOverlay("test.package.name_color", ANDROID_PACKAGE, 88 OVERLAY_CATEGORY_COLOR, true, 0); 89 mMockOmHelper.addOverlay("test.package.name_font", ANDROID_PACKAGE, 90 OVERLAY_CATEGORY_FONT, true, 0); 91 mMockOmHelper.addOverlay("test.package.name_shape", ANDROID_PACKAGE, 92 OVERLAY_CATEGORY_SHAPE, true, 0); 93 mMockOmHelper.addOverlay("test.package.name_icon", ANDROID_PACKAGE, 94 OVERLAY_CATEGORY_ICON_ANDROID, true, 0); 95 mMockOmHelper.addOverlay("test.package.name_settings", SETTINGS_PACKAGE, 96 OVERLAY_CATEGORY_ICON_SETTINGS, true, 0); 97 mMockOmHelper.addOverlay("test.package.name_sysui", SYSUI_PACKAGE, 98 OVERLAY_CATEGORY_ICON_SYSUI, true, 0); 99 mMockOmHelper.addOverlay("test.package.name_themepicker", mActivity.getPackageName(), 100 OVERLAY_CATEGORY_ICON_SYSUI, true, 0); 101 102 ThemeBundle defaultTheme = new ThemeBundle.Builder().asDefault().build(mActivity); 103 104 applyTheme(defaultTheme); 105 106 assertEquals("Secure Setting should be empty JSON string after applying default theme", 107 new JSONObject().toString(), 108 Settings.Secure.getString(mActivity.getContentResolver(), THEME_SETTING)); 109 } 110 111 @Test apply_WithOverlayTheme_StoresSerializedPackagesWithTimestamp()112 public void apply_WithOverlayTheme_StoresSerializedPackagesWithTimestamp() { 113 ThemeBundle theme = getOverlayTheme(); 114 final String serializedPackagesWithTimestamp = theme.getSerializedPackagesWithTimestamp(); 115 116 theme = spy(theme); 117 // Makes it return the fixed serializedPackagesWithTimestamp to test. Since we will get 118 // fresh time every time, it's hard to compare for testing. 119 when(theme.getSerializedPackagesWithTimestamp()) 120 .thenReturn(serializedPackagesWithTimestamp); 121 122 applyTheme(theme); 123 124 assertEquals("Secure Setting should be the overlay packages after applying theme", 125 serializedPackagesWithTimestamp, 126 Settings.Secure.getString(mActivity.getContentResolver(), THEME_SETTING)); 127 } 128 129 @Test isAvailable_ThemeBundleProviderAndOverlayManagerAreAvailable_ReturnsTrue()130 public void isAvailable_ThemeBundleProviderAndOverlayManagerAreAvailable_ReturnsTrue() { 131 when(mThemeBundleProvider.isAvailable()).thenReturn(true); 132 when(mMockOm.isAvailable()).thenReturn(true); 133 134 assertTrue(mThemeManager.isAvailable()); 135 } 136 137 @Test isAvailable_ThemeBundleProviderOrOverlayManagerIsAvailable_ReturnsFalse()138 public void isAvailable_ThemeBundleProviderOrOverlayManagerIsAvailable_ReturnsFalse() { 139 when(mThemeBundleProvider.isAvailable()).thenReturn(false); 140 when(mMockOm.isAvailable()).thenReturn(true); 141 assertFalse(mThemeManager.isAvailable()); 142 143 when(mThemeBundleProvider.isAvailable()).thenReturn(true); 144 when(mMockOm.isAvailable()).thenReturn(false); 145 assertFalse(mThemeManager.isAvailable()); 146 } 147 148 @Test fetchOptions_ThemeBundleProviderFetches()149 public void fetchOptions_ThemeBundleProviderFetches() { 150 OptionsFetchedListener listener = mock(OptionsFetchedListener.class); 151 152 mThemeManager.fetchOptions(listener, false); 153 154 verify(mThemeBundleProvider).fetch(listener, false); 155 } 156 157 @Test removeCustomTheme_ThemeBundleProviderRemovesCustomTheme()158 public void removeCustomTheme_ThemeBundleProviderRemovesCustomTheme() { 159 CustomTheme customTheme = mock(CustomTheme.class); 160 mThemeManager.removeCustomTheme(customTheme); 161 162 verify(mThemeBundleProvider).removeCustomTheme(customTheme); 163 } 164 165 @Test findThemeByPackages_ThemeBundleProviderFindsEquivalent()166 public void findThemeByPackages_ThemeBundleProviderFindsEquivalent() { 167 CustomTheme theme = mock(CustomTheme.class); 168 mThemeManager.findThemeByPackages(theme); 169 170 verify(mThemeBundleProvider).findEquivalent(theme); 171 } 172 173 @Test storeEmptyTheme_SettingsSecureStoresEmptyTheme()174 public void storeEmptyTheme_SettingsSecureStoresEmptyTheme() { 175 mThemeManager.storeEmptyTheme(); 176 177 assertEquals( 178 new JSONObject().toString(), 179 Settings.Secure.getString(mActivity.getContentResolver(), THEME_SETTING)); 180 } 181 182 @Test getStoredOverlays_GetsFromSettingsSecureWithExpectedName()183 public void getStoredOverlays_GetsFromSettingsSecureWithExpectedName() { 184 ThemeBundle theme = getOverlayTheme(); 185 186 applyTheme(theme); 187 188 assertEquals( 189 Settings.Secure.getString(mActivity.getContentResolver(), THEME_SETTING), 190 mThemeManager.getStoredOverlays()); 191 } 192 getOverlayTheme()193 private ThemeBundle getOverlayTheme() { 194 final String bundleColorPackage = "test.package.name_color"; 195 final String bundleFontPackage = "test.package.name_font"; 196 final String otherPackage = "other.package.name_font"; 197 198 mMockOmHelper.addOverlay(bundleColorPackage, ANDROID_PACKAGE, 199 OVERLAY_CATEGORY_COLOR, false, 0); 200 mMockOmHelper.addOverlay(bundleFontPackage, ANDROID_PACKAGE, 201 OVERLAY_CATEGORY_FONT, false, 0); 202 mMockOmHelper.addOverlay(otherPackage, ANDROID_PACKAGE, 203 OVERLAY_CATEGORY_FONT, false, 0); 204 205 return new ThemeBundle.Builder() 206 .addOverlayPackage(OVERLAY_CATEGORY_COLOR, bundleColorPackage) 207 .addOverlayPackage(OVERLAY_CATEGORY_FONT, bundleFontPackage) 208 .build(mActivity); 209 } 210 applyTheme(ThemeBundle theme)211 private void applyTheme(ThemeBundle theme) { 212 mThemeManager.apply(theme, new Callback() { 213 @Override 214 public void onSuccess() { 215 } 216 217 @Override 218 public void onError(@Nullable Throwable throwable) { 219 } 220 }); 221 } 222 } 223