1 /*
2  * Copyright (C) 2015 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.internal.policy;
18 
19 import android.content.AutofillOptions;
20 import android.content.ContentCaptureOptions;
21 import android.content.Context;
22 import android.content.res.AssetManager;
23 import android.content.res.Configuration;
24 import android.content.res.Resources;
25 import android.view.ContextThemeWrapper;
26 import android.view.Display;
27 import android.view.contentcapture.ContentCaptureManager;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 
31 import java.lang.ref.WeakReference;
32 
33 /**
34  * Context for decor views which can be seeded with display context and not depend on the activity,
35  * but still provide some of the facilities that Activity has,
36  * e.g. themes, activity-based resources, etc.
37  *
38  * @hide
39  */
40 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
41 public class DecorContext extends ContextThemeWrapper {
42     private PhoneWindow mPhoneWindow;
43     private Resources mResources;
44     private ContentCaptureManager mContentCaptureManager;
45 
46     private WeakReference<Context> mContext;
47 
48     @VisibleForTesting
DecorContext(Context baseContext, PhoneWindow phoneWindow)49     public DecorContext(Context baseContext, PhoneWindow phoneWindow) {
50         super(null /* base */, null);
51         setPhoneWindow(phoneWindow);
52         // TODO(b/149790106): Non-activity context can be passed.
53         final Display display = phoneWindow.getContext().getDisplayNoVerify();
54         final Context displayContext;
55         if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
56             // TODO(b/166174272): Creating a display context for the default display will result
57             // in additional resource creation.
58             displayContext = baseContext.createConfigurationContext(Configuration.EMPTY);
59             displayContext.updateDisplay(Display.DEFAULT_DISPLAY);
60         } else {
61             displayContext = baseContext.createDisplayContext(display);
62         }
63         attachBaseContext(displayContext);
64     }
65 
setPhoneWindow(PhoneWindow phoneWindow)66     void setPhoneWindow(PhoneWindow phoneWindow) {
67         mPhoneWindow = phoneWindow;
68         final Context context = phoneWindow.getContext();
69         mContext = new WeakReference<>(context);
70         mResources = context.getResources();
71     }
72 
73     @Override
getSystemService(String name)74     public Object getSystemService(String name) {
75         if (Context.WINDOW_SERVICE.equals(name)) {
76             return mPhoneWindow.getWindowManager();
77         }
78         final Context context = mContext.get();
79         if (Context.CONTENT_CAPTURE_MANAGER_SERVICE.equals(name)) {
80             if (context != null && mContentCaptureManager == null) {
81                 mContentCaptureManager = (ContentCaptureManager) context.getSystemService(name);
82             }
83             return mContentCaptureManager;
84         }
85         // LayoutInflater and WallpaperManagerService should also be obtained from visual context
86         // instead of base context.
87         return (context != null) ? context.getSystemService(name) : super.getSystemService(name);
88     }
89 
90     @Override
getResources()91     public Resources getResources() {
92         Context context = mContext.get();
93         // Attempt to update the local cached Resources from the activity context. If the activity
94         // is no longer around, return the old cached values.
95         if (context != null) {
96             mResources = context.getResources();
97         }
98 
99         return mResources;
100     }
101 
102     @Override
getAssets()103     public AssetManager getAssets() {
104         return mResources.getAssets();
105     }
106 
107     @Override
getAutofillOptions()108     public AutofillOptions getAutofillOptions() {
109         Context context = mContext.get();
110         if (context != null) {
111             return context.getAutofillOptions();
112         }
113         return null;
114     }
115 
116     @Override
getContentCaptureOptions()117     public ContentCaptureOptions getContentCaptureOptions() {
118         Context context = mContext.get();
119         if (context != null) {
120             return context.getContentCaptureOptions();
121         }
122         return null;
123     }
124 
125     @Override
isUiContext()126     public boolean isUiContext() {
127         Context context = mContext.get();
128         if (context != null) {
129             return context.isUiContext();
130         }
131         return false;
132     }
133 
134     @Override
isConfigurationContext()135     public boolean isConfigurationContext() {
136         Context context = mContext.get();
137         if (context != null) {
138             return context.isConfigurationContext();
139         }
140         return false;
141     }
142 }
143