• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base;
6 
7 import android.content.Context;
8 import android.content.SharedPreferences;
9 import android.preference.PreferenceManager;
10 
11 import org.chromium.base.annotations.JNINamespace;
12 import org.chromium.base.annotations.MainDex;
13 
14 /**
15  * This class provides Android application context related utility methods.
16  */
17 @JNINamespace("base::android")
18 @MainDex
19 public class ContextUtils {
20     private static final String TAG = "ContextUtils";
21     private static Context sApplicationContext;
22 
23     /**
24      * Initialization-on-demand holder. This exists for thread-safe lazy initialization.
25      */
26     private static class Holder {
27         // Not final for tests.
28         private static SharedPreferences sSharedPreferences = fetchAppSharedPreferences();
29     }
30 
31     /**
32      * Get the Android application context.
33      *
34      * Under normal circumstances there is only one application context in a process, so it's safe
35      * to treat this as a global. In WebView it's possible for more than one app using WebView to be
36      * running in a single process, but this mechanism is rarely used and this is not the only
37      * problem in that scenario, so we don't currently forbid using it as a global.
38      *
39      * Do not downcast the context returned by this method to Application (or any subclass). It may
40      * not be an Application object; it may be wrapped in a ContextWrapper. The only assumption you
41      * may make is that it is a Context whose lifetime is the same as the lifetime of the process.
42      */
getApplicationContext()43     public static Context getApplicationContext() {
44         return sApplicationContext;
45     }
46 
47     /**
48      * Initializes the java application context.
49      *
50      * This should be called exactly once early on during startup, before native is loaded and
51      * before any other clients make use of the application context through this class.
52      *
53      * @param appContext The application context.
54      */
initApplicationContext(Context appContext)55     public static void initApplicationContext(Context appContext) {
56         // Conceding that occasionally in tests, native is loaded before the browser process is
57         // started, in which case the browser process re-sets the application context.
58         if (sApplicationContext != null && sApplicationContext != appContext) {
59             throw new RuntimeException("Attempting to set multiple global application contexts.");
60         }
61         initJavaSideApplicationContext(appContext);
62     }
63 
64     /**
65      * Initialize the native Android application context to be the same as the java counter-part.
66      */
initApplicationContextForNative()67     public static void initApplicationContextForNative() {
68         if (sApplicationContext == null) {
69             throw new RuntimeException("Cannot have native global application context be null.");
70         }
71         nativeInitNativeSideApplicationContext(sApplicationContext);
72     }
73 
74     /**
75      * Only called by the static holder class and tests.
76      *
77      * @return The application-wide shared preferences.
78      */
fetchAppSharedPreferences()79     private static SharedPreferences fetchAppSharedPreferences() {
80         return PreferenceManager.getDefaultSharedPreferences(sApplicationContext);
81     }
82 
83     /**
84      * This is used to ensure that we always use the application context to fetch the default shared
85      * preferences. This avoids needless I/O for android N and above. It also makes it clear that
86      * the app-wide shared preference is desired, rather than the potentially context-specific one.
87      *
88      * @return application-wide shared preferences.
89      */
getAppSharedPreferences()90     public static SharedPreferences getAppSharedPreferences() {
91         return Holder.sSharedPreferences;
92     }
93 
94     /**
95      * Occasionally tests cannot ensure the application context doesn't change between tests (junit)
96      * and sometimes specific tests has its own special needs, initApplicationContext should be used
97      * as much as possible, but this method can be used to override it.
98      *
99      * @param appContext The new application context.
100      */
101     @VisibleForTesting
initApplicationContextForTests(Context appContext)102     public static void initApplicationContextForTests(Context appContext) {
103         initJavaSideApplicationContext(appContext);
104         Holder.sSharedPreferences = fetchAppSharedPreferences();
105     }
106 
initJavaSideApplicationContext(Context appContext)107     private static void initJavaSideApplicationContext(Context appContext) {
108         if (appContext == null) {
109             throw new RuntimeException("Global application context cannot be set to null.");
110         }
111         sApplicationContext = appContext;
112     }
113 
nativeInitNativeSideApplicationContext(Context appContext)114     private static native void nativeInitNativeSideApplicationContext(Context appContext);
115 }
116