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