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