1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16package android.content.res;
17
18import android.annotation.NonNull;
19import android.app.ResourcesManager;
20import android.os.Binder;
21import android.os.LocaleList;
22import android.support.test.filters.SmallTest;
23import android.util.DisplayMetrics;
24import android.util.TypedValue;
25import android.view.Display;
26import android.view.DisplayAdjustments;
27
28import junit.framework.TestCase;
29
30public class ResourcesManagerTest extends TestCase {
31    private static final String APP_ONE_RES_DIR = "app_one.apk";
32    private static final String APP_ONE_RES_SPLIT_DIR = "app_one_split.apk";
33    private static final String APP_TWO_RES_DIR = "app_two.apk";
34    private static final String LIB_RES_DIR = "lib.apk";
35
36    private ResourcesManager mResourcesManager;
37    private DisplayMetrics mDisplayMetrics;
38
39    @Override
40    protected void setUp() throws Exception {
41        super.setUp();
42
43        mDisplayMetrics = new DisplayMetrics();
44        mDisplayMetrics.setToDefaults();
45
46        // Override defaults (which take device specific properties).
47        mDisplayMetrics.density = 1.0f;
48        mDisplayMetrics.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
49        mDisplayMetrics.xdpi = DisplayMetrics.DENSITY_DEFAULT;
50        mDisplayMetrics.ydpi = DisplayMetrics.DENSITY_DEFAULT;
51        mDisplayMetrics.noncompatDensity = mDisplayMetrics.density;
52        mDisplayMetrics.noncompatDensityDpi = mDisplayMetrics.densityDpi;
53        mDisplayMetrics.noncompatXdpi = DisplayMetrics.DENSITY_DEFAULT;
54        mDisplayMetrics.noncompatYdpi = DisplayMetrics.DENSITY_DEFAULT;
55
56        mResourcesManager = new ResourcesManager() {
57            @Override
58            protected AssetManager createAssetManager(@NonNull ResourcesKey key) {
59                return new AssetManager();
60            }
61
62            @Override
63            protected DisplayMetrics getDisplayMetrics(int displayId, DisplayAdjustments daj) {
64                return mDisplayMetrics;
65            }
66        };
67    }
68
69    @SmallTest
70    public void testMultipleCallsWithIdenticalParametersCacheReference() {
71        Resources resources = mResourcesManager.getResources(
72                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
73                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
74        assertNotNull(resources);
75
76        Resources newResources = mResourcesManager.getResources(
77                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
78                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
79        assertNotNull(newResources);
80        assertSame(resources, newResources);
81    }
82
83    @SmallTest
84    public void testMultipleCallsWithDifferentParametersReturnDifferentReferences() {
85        Resources resources = mResourcesManager.getResources(
86                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
87                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
88        assertNotNull(resources);
89
90        Configuration overrideConfig = new Configuration();
91        overrideConfig.smallestScreenWidthDp = 200;
92        Resources newResources = mResourcesManager.getResources(
93                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, overrideConfig,
94                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
95        assertNotNull(newResources);
96        assertNotSame(resources, newResources);
97    }
98
99    @SmallTest
100    public void testAddingASplitCreatesANewImpl() {
101        Resources resources1 = mResourcesManager.getResources(
102                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
103                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
104        assertNotNull(resources1);
105
106        Resources resources2 = mResourcesManager.getResources(
107                null, APP_ONE_RES_DIR, new String[] { APP_ONE_RES_SPLIT_DIR }, null, null,
108                Display.DEFAULT_DISPLAY, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
109        assertNotNull(resources2);
110
111        assertNotSame(resources1, resources2);
112        assertNotSame(resources1.getImpl(), resources2.getImpl());
113    }
114
115    @SmallTest
116    public void testUpdateConfigurationUpdatesAllAssetManagers() {
117        Resources resources1 = mResourcesManager.getResources(
118                null, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
119                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
120        assertNotNull(resources1);
121
122        Resources resources2 = mResourcesManager.getResources(
123                null, APP_TWO_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
124                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
125        assertNotNull(resources2);
126
127        Binder activity = new Binder();
128        final Configuration overrideConfig = new Configuration();
129        overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
130        Resources resources3 = mResourcesManager.getResources(
131                activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
132                overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
133        assertNotNull(resources3);
134
135        // No Resources object should be the same.
136        assertNotSame(resources1, resources2);
137        assertNotSame(resources1, resources3);
138        assertNotSame(resources2, resources3);
139
140        // Each ResourcesImpl should be different.
141        assertNotSame(resources1.getImpl(), resources2.getImpl());
142        assertNotSame(resources1.getImpl(), resources3.getImpl());
143        assertNotSame(resources2.getImpl(), resources3.getImpl());
144
145        Configuration newConfig = new Configuration();
146        newConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
147        mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null);
148
149        final Configuration expectedConfig = new Configuration();
150        expectedConfig.setLocales(LocaleList.getAdjustedDefault());
151        expectedConfig.densityDpi = mDisplayMetrics.densityDpi;
152        expectedConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
153
154        assertEquals(expectedConfig, resources1.getConfiguration());
155        assertEquals(expectedConfig, resources2.getConfiguration());
156        assertEquals(expectedConfig, resources3.getConfiguration());
157    }
158
159    @SmallTest
160    public void testTwoActivitiesWithIdenticalParametersShareImpl() {
161        Binder activity1 = new Binder();
162        Resources resources1 = mResourcesManager.getResources(
163                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
164                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
165        assertNotNull(resources1);
166
167        Binder activity2 = new Binder();
168        Resources resources2 = mResourcesManager.getResources(
169                activity2, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
170                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
171        assertNotNull(resources1);
172
173        // The references themselves should be unique.
174        assertNotSame(resources1, resources2);
175
176        // The implementations should be the same.
177        assertSame(resources1.getImpl(), resources2.getImpl());
178    }
179
180    @SmallTest
181    public void testThemesGetUpdatedWithNewImpl() {
182        Binder activity1 = new Binder();
183        Resources resources1 = mResourcesManager.createBaseActivityResources(
184                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
185                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
186        assertNotNull(resources1);
187
188        Resources.Theme theme = resources1.newTheme();
189        assertSame(resources1, theme.getResources());
190        theme.applyStyle(android.R.style.Theme_NoTitleBar, false);
191
192        TypedValue value = new TypedValue();
193        assertTrue(theme.resolveAttribute(android.R.attr.windowNoTitle, value, true));
194        assertEquals(TypedValue.TYPE_INT_BOOLEAN, value.type);
195        assertTrue(value.data != 0);
196
197        final Configuration overrideConfig = new Configuration();
198        overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
199        mResourcesManager.updateResourcesForActivity(activity1, overrideConfig);
200        assertSame(resources1, theme.getResources());
201
202        // Make sure we can still access the data.
203        assertTrue(theme.resolveAttribute(android.R.attr.windowNoTitle, value, true));
204        assertEquals(TypedValue.TYPE_INT_BOOLEAN, value.type);
205        assertTrue(value.data != 0);
206    }
207
208    @SmallTest
209    public void testMultipleResourcesForOneActivityGetUpdatedWhenActivityBaseUpdates() {
210        Binder activity1 = new Binder();
211
212        // Create a Resources for the Activity.
213        Configuration config1 = new Configuration();
214        config1.densityDpi = 280;
215        Resources resources1 = mResourcesManager.createBaseActivityResources(
216                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config1,
217                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
218        assertNotNull(resources1);
219
220        // Create a Resources based on the Activity.
221        Configuration config2 = new Configuration();
222        config2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
223        Resources resources2 = mResourcesManager.getResources(
224                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config2,
225                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
226        assertNotNull(resources2);
227
228        assertNotSame(resources1, resources2);
229        assertNotSame(resources1.getImpl(), resources2.getImpl());
230
231        final Configuration expectedConfig1 = new Configuration();
232        expectedConfig1.setLocales(LocaleList.getAdjustedDefault());
233        expectedConfig1.densityDpi = 280;
234        assertEquals(expectedConfig1, resources1.getConfiguration());
235
236        // resources2 should be based on the Activity's override config, so the density should
237        // be the same as resources1.
238        final Configuration expectedConfig2 = new Configuration();
239        expectedConfig2.setLocales(LocaleList.getAdjustedDefault());
240        expectedConfig2.densityDpi = 280;
241        expectedConfig2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
242        assertEquals(expectedConfig2, resources2.getConfiguration());
243
244        // Now update the Activity base override, and both resources should update.
245        config1.orientation = Configuration.ORIENTATION_LANDSCAPE;
246        mResourcesManager.updateResourcesForActivity(activity1, config1);
247
248        expectedConfig1.orientation = Configuration.ORIENTATION_LANDSCAPE;
249        assertEquals(expectedConfig1, resources1.getConfiguration());
250
251        expectedConfig2.orientation = Configuration.ORIENTATION_LANDSCAPE;
252        assertEquals(expectedConfig2, resources2.getConfiguration());
253    }
254}
255