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