1 /*
2  * Copyright (C) 2017 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.managedprovisioning.common;
18 
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.content.res.Resources;
22 
23 import java.util.Locale;
24 
25 /**
26  * Utility class to save and restore the locale of the system.
27  * <p>
28  * Taken from <a href="https://android.googlesource.com/platform/packages/apps/Dialer/+/94b10b530c0fc297e2974e57e094c500d3ee6003/tests/src/com/android/dialer/util/LocaleTestUtils.java">com.android.dialer.util.LocaleTestUtils</a>
29  * <p>
30  * This can be used for tests that assume to be run in a certain locale, e.g., because they
31  * check against strings in a particular language or require an assumption on how the system
32  * will behave in a specific locale.
33  * <p>
34  * In your test, you can change the locale with the following code:
35  * <pre>
36  * public class CanadaFrenchTest extends AndroidTestCase {
37  *     private LocaleTestUtils mLocaleTestUtils;
38  *
39  *     &#64;Override
40  *     public void setUp() throws Exception {
41  *         super.setUp();
42  *         mLocaleTestUtils = new LocaleTestUtils(getContext());
43  *         mLocaleTestUtils.setLocale(Locale.CANADA_FRENCH);
44  *     }
45  *
46  *     &#64;Override
47  *     public void tearDown() throws Exception {
48  *         mLocaleTestUtils.restoreLocale();
49  *         mLocaleTestUtils = null;
50  *         super.tearDown();
51  *     }
52  *
53  *     ...
54  * }
55  * </pre>
56  * Note that one should not call {@link #setLocale(Locale)} more than once without calling
57  * {@link #restoreLocale()} first.
58  * <p>
59  * This class is not thread-safe. Usually its methods should be invoked only from the test thread.
60  */
61 public class LocaleTestUtils {
62     private final Context mContext;
63     private boolean mSaved;
64     private Locale mSavedContextLocale;
65     private Locale mSavedSystemLocale;
66 
67     /**
68      * Create a new instance that can be used to set and reset the locale for the given context.
69      *
70      * @param context the context on which to alter the locale
71      */
LocaleTestUtils(Context context)72     public LocaleTestUtils(Context context) {
73         mContext = context;
74         mSaved = false;
75     }
76 
77     /**
78      * Set the locale to the given value and saves the previous value.
79      *
80      * @param locale the value to which the locale should be set
81      * @throws IllegalStateException if the locale was already set
82      */
setLocale(Locale locale)83     public void setLocale(Locale locale) {
84         if (mSaved) {
85             throw new IllegalStateException(
86                     "call restoreLocale() before calling setLocale() again");
87         }
88         mSavedContextLocale = setResourcesLocale(mContext.getResources(), locale);
89         mSavedSystemLocale = setResourcesLocale(Resources.getSystem(), locale);
90         mSaved = true;
91     }
92 
93     /**
94      * Restores the previously set locale.
95      *
96      * @throws IllegalStateException if the locale was not set using {@link #setLocale(Locale)}
97      */
restoreLocale()98     public void restoreLocale() {
99         if (!mSaved) {
100             throw new IllegalStateException("call setLocale() before calling restoreLocale()");
101         }
102         setResourcesLocale(mContext.getResources(), mSavedContextLocale);
103         setResourcesLocale(Resources.getSystem(), mSavedSystemLocale);
104         mSaved = false;
105     }
106 
107     /**
108      * Sets the locale for the given resources and returns the previous locale.
109      *
110      * @param resources the resources on which to set the locale
111      * @param locale the value to which to set the locale
112      * @return the previous value of the locale for the resources
113      */
setResourcesLocale(Resources resources, Locale locale)114     private Locale setResourcesLocale(Resources resources, Locale locale) {
115         Configuration contextConfiguration = new Configuration(resources.getConfiguration());
116         Locale savedLocale = contextConfiguration.locale;
117         contextConfiguration.locale = locale;
118         resources.updateConfiguration(contextConfiguration, null);
119         return savedLocale;
120     }
121 }