• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 android.window;
18 
19 import static android.view.Display.DEFAULT_DISPLAY;
20 
21 import android.annotation.CallSuper;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SuppressLint;
25 import android.annotation.TestApi;
26 import android.annotation.UiContext;
27 import android.app.ActivityThread;
28 import android.app.LoadedApk;
29 import android.app.Service;
30 import android.content.ComponentCallbacks;
31 import android.content.ComponentCallbacksController;
32 import android.content.Context;
33 import android.content.res.Configuration;
34 import android.hardware.display.DisplayManager;
35 import android.os.Bundle;
36 import android.os.IBinder;
37 import android.util.Log;
38 import android.view.Display;
39 import android.view.WindowManager;
40 import android.view.WindowManager.LayoutParams.WindowType;
41 import android.view.WindowManagerImpl;
42 
43 /**
44  * A {@link Service} responsible for showing a non-activity window, such as software keyboards or
45  * accessibility overlay windows. This {@link Service} has similar behavior to
46  * {@link WindowContext}, but is represented as {@link Service}.
47  *
48  * @see android.inputmethodservice.InputMethodService
49  *
50  * @hide
51  */
52 @SuppressWarnings("HiddenSuperclass")
53 @TestApi
54 @UiContext
55 public abstract class WindowProviderService extends Service implements WindowProvider,
56         ConfigurationDispatcher {
57 
58     private static final String TAG = WindowProviderService.class.getSimpleName();
59 
60     private final Bundle mOptions;
61     private final WindowTokenClient mWindowToken = new WindowTokenClient();
62     private final WindowContextController mController = new WindowContextController(mWindowToken);
63     private WindowManager mWindowManager;
64     private boolean mInitialized;
65     private final ComponentCallbacksController mCallbacksController =
66             new ComponentCallbacksController();
67 
68     /**
69      * Returns {@code true} if the {@code windowContextOptions} declares that it is a
70      * {@link WindowProviderService}.
71      *
72      * @hide
73      */
isWindowProviderService(@ullable Bundle windowContextOptions)74     public static boolean isWindowProviderService(@Nullable Bundle windowContextOptions) {
75         if (windowContextOptions == null) {
76             return false;
77         }
78         return (windowContextOptions.getBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, false));
79     }
80 
WindowProviderService()81     public WindowProviderService() {
82         mOptions = new Bundle();
83         mOptions.putBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, true);
84     }
85 
86     /**
87      * Returns the window type of this {@link WindowProviderService}.
88      * Each inheriting class must implement this method to provide the type of the window. It is
89      * used similar to {@code type} of {@link Context#createWindowContext(int, Bundle)}
90      *
91      * @see Context#createWindowContext(int, Bundle)
92      *
93      * @hide
94      */
95     @TestApi
96     @SuppressLint("OnNameExpected")
97     // Suppress the lint because it is not a callback and users should provide window type
98     // so we cannot make it final.
99     @WindowType
100     @Override
getWindowType()101     public abstract int getWindowType();
102 
103     /**
104      * Returns the option of this {@link WindowProviderService}.
105      * <p>
106      * The inheriting class can implement this method to provide the customization {@code option} of
107      * the window, but must be based on this method's returned value.
108      * It is used similar to {@code options} of {@link Context#createWindowContext(int, Bundle)}
109      * </p>
110      * <pre class="prettyprint">
111      * public Bundle getWindowContextOptions() {
112      *     final Bundle options = super.getWindowContextOptions();
113      *     options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
114      *     return options;
115      * }
116      * </pre>
117      *
118      * @hide
119      */
120     @TestApi
121     @SuppressLint({"OnNameExpected", "NullableCollection"})
122     // Suppress the lint because it is not a callback and users may override this API to provide
123     // launch option. Also, the return value of this API is null by default.
124     @Nullable
125     @CallSuper
126     @Override
getWindowContextOptions()127     public Bundle getWindowContextOptions() {
128         return mOptions;
129     }
130 
131     @SuppressLint({"OnNameExpected", "ExecutorRegistration"})
132     // Suppress lint because this is a legacy named function and doesn't have an optional param
133     // for executor.
134     /**
135      * Here we override to prevent WindowProviderService from invoking
136      * {@link Application.registerComponentCallback}, which will result in callback registered
137      * for process-level Configuration change updates.
138      */
139     @Override
registerComponentCallbacks(@onNull ComponentCallbacks callback)140     public void registerComponentCallbacks(@NonNull ComponentCallbacks callback) {
141         // For broadcasting Configuration Changes.
142         mCallbacksController.registerCallbacks(callback);
143     }
144 
145     @SuppressLint("OnNameExpected")
146     @Override
unregisterComponentCallbacks(@onNull ComponentCallbacks callback)147     public void unregisterComponentCallbacks(@NonNull ComponentCallbacks callback) {
148         mCallbacksController.unregisterCallbacks(callback);
149     }
150 
151     @SuppressLint("OnNameExpected")
152     @Override
onConfigurationChanged(@onNull Configuration configuration)153     public void onConfigurationChanged(@NonNull Configuration configuration) {
154         // This is only called from WindowTokenClient.
155         mCallbacksController.dispatchConfigurationChanged(configuration);
156     }
157 
158     /**
159      * Override {@link Service}'s empty implementation and listen to {@code ActivityThread} for
160      * low memory and trim memory events.
161      */
162     @Override
onLowMemory()163     public void onLowMemory() {
164         mCallbacksController.dispatchLowMemory();
165     }
166 
167     @Override
onTrimMemory(int level)168     public void onTrimMemory(int level) {
169         mCallbacksController.dispatchTrimMemory(level);
170     }
171 
172     /**
173      * Returns the display ID to launch this {@link WindowProviderService}.
174      *
175      * @hide
176      */
177     @TestApi
178     @SuppressLint({"OnNameExpected"})
179     // Suppress the lint because it is not a callback and users may override this API to provide
180     // display.
181     @NonNull
getInitialDisplayId()182     public int getInitialDisplayId() {
183         return DEFAULT_DISPLAY;
184     }
185 
186     /**
187      * Attaches this WindowProviderService to the {@code windowToken}.
188      *
189      * @hide
190      */
191     @TestApi
attachToWindowToken(@onNull IBinder windowToken)192     public final void attachToWindowToken(@NonNull IBinder windowToken) {
193         mController.attachToWindowToken(windowToken);
194     }
195 
196     /** @hide */
197     @Override
createServiceBaseContext(ActivityThread mainThread, LoadedApk packageInfo)198     public final Context createServiceBaseContext(ActivityThread mainThread,
199             LoadedApk packageInfo) {
200         final Context context = super.createServiceBaseContext(mainThread, packageInfo);
201         final DisplayManager displayManager = context.getSystemService(DisplayManager.class);
202         final int initialDisplayId = getInitialDisplayId();
203         Display display = displayManager.getDisplay(initialDisplayId);
204         // Fallback to use the default display if the initial display to start WindowProviderService
205         // is detached.
206         if (display == null) {
207             Log.e(TAG, "Display with id " + initialDisplayId + " not found, falling back to "
208                     + "DEFAULT_DISPLAY");
209             display = displayManager.getDisplay(DEFAULT_DISPLAY);
210         }
211         return context.createTokenContext(mWindowToken, display);
212     }
213 
214     /** @hide */
215     @Override
attachBaseContext(Context newBase)216     protected void attachBaseContext(Context newBase) {
217         super.attachBaseContext(newBase);
218         if (!mInitialized) {
219             mWindowToken.attachContext(this);
220             mController.attachToDisplayArea(getWindowType(), getDisplayId(),
221                     getWindowContextOptions());
222             mWindowManager = WindowManagerImpl.createWindowContextWindowManager(this);
223             mInitialized = true;
224         }
225     }
226 
227     // Suppress the lint because ths is overridden from Context.
228     @SuppressLint("OnNameExpected")
229     @Override
230     @Nullable
getSystemService(@onNull String name)231     public Object getSystemService(@NonNull String name) {
232         if (WINDOW_SERVICE.equals(name)) {
233             return mWindowManager;
234         }
235         return super.getSystemService(name);
236     }
237 
238     @CallSuper
239     @Override
onDestroy()240     public void onDestroy() {
241         super.onDestroy();
242         mController.detachIfNeeded();
243         mCallbacksController.clearCallbacks();
244     }
245 
246     /**
247      * {@inheritDoc}
248      *
249      * @hide
250      */
251     @Override
dispatchConfigurationChanged(@onNull Configuration configuration)252     public void dispatchConfigurationChanged(@NonNull Configuration configuration) {
253         onConfigurationChanged(configuration);
254     }
255 }
256