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.Context;
31 import android.hardware.display.DisplayManager;
32 import android.os.Bundle;
33 import android.os.IBinder;
34 import android.view.Display;
35 import android.view.WindowManager;
36 import android.view.WindowManager.LayoutParams.WindowType;
37 import android.view.WindowManagerImpl;
38 
39 /**
40  * A {@link Service} responsible for showing a non-activity window, such as software keyboards or
41  * accessibility overlay windows. This {@link Service} has similar behavior to
42  * {@link WindowContext}, but is represented as {@link Service}.
43  *
44  * @see android.inputmethodservice.InputMethodService
45  *
46  * @hide
47  */
48 @TestApi
49 @UiContext
50 public abstract class WindowProviderService extends Service implements WindowProvider {
51 
52     private final Bundle mOptions;
53     private final WindowTokenClient mWindowToken = new WindowTokenClient();
54     private final WindowContextController mController = new WindowContextController(mWindowToken);
55     private WindowManager mWindowManager;
56     private boolean mInitialized;
57 
58     /**
59      * Returns {@code true} if the {@code windowContextOptions} declares that it is a
60      * {@link WindowProviderService}.
61      *
62      * @hide
63      */
isWindowProviderService(@ullable Bundle windowContextOptions)64     public static boolean isWindowProviderService(@Nullable Bundle windowContextOptions) {
65         if (windowContextOptions == null) {
66             return false;
67         }
68         return (windowContextOptions.getBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, false));
69     }
70 
WindowProviderService()71     public WindowProviderService() {
72         mOptions = new Bundle();
73         mOptions.putBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, true);
74     }
75 
76     /**
77      * Returns the window type of this {@link WindowProviderService}.
78      * Each inheriting class must implement this method to provide the type of the window. It is
79      * used similar to {@code type} of {@link Context#createWindowContext(int, Bundle)}
80      *
81      * @see Context#createWindowContext(int, Bundle)
82      *
83      * @hide
84      */
85     @TestApi
86     @SuppressLint("OnNameExpected")
87     // Suppress the lint because it is not a callback and users should provide window type
88     // so we cannot make it final.
89     @WindowType
90     @Override
getWindowType()91     public abstract int getWindowType();
92 
93     /**
94      * Returns the option of this {@link WindowProviderService}.
95      * <p>
96      * The inheriting class can implement this method to provide the customization {@code option} of
97      * the window, but must be based on this method's returned value.
98      * It is used similar to {@code options} of {@link Context#createWindowContext(int, Bundle)}
99      * </p>
100      * <pre class="prettyprint">
101      * public Bundle getWindowContextOptions() {
102      *     final Bundle options = super.getWindowContextOptions();
103      *     options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
104      *     return options;
105      * }
106      * </pre>
107      *
108      * @hide
109      */
110     @TestApi
111     @SuppressLint({"OnNameExpected", "NullableCollection"})
112     // Suppress the lint because it is not a callback and users may override this API to provide
113     // launch option. Also, the return value of this API is null by default.
114     @Nullable
115     @CallSuper
116     @Override
getWindowContextOptions()117     public Bundle getWindowContextOptions() {
118         return mOptions;
119     }
120 
121     /**
122      * Returns the display ID to launch this {@link WindowProviderService}.
123      *
124      * @hide
125      */
126     @TestApi
127     @SuppressLint({"OnNameExpected"})
128     // Suppress the lint because it is not a callback and users may override this API to provide
129     // display.
130     @NonNull
getInitialDisplayId()131     public int getInitialDisplayId() {
132         return DEFAULT_DISPLAY;
133     }
134 
135     /**
136      * Attaches this WindowProviderService to the {@code windowToken}.
137      *
138      * @hide
139      */
140     @TestApi
attachToWindowToken(@onNull IBinder windowToken)141     public final void attachToWindowToken(@NonNull IBinder windowToken) {
142         mController.attachToWindowToken(windowToken);
143     }
144 
145     /** @hide */
146     @Override
createServiceBaseContext(ActivityThread mainThread, LoadedApk packageInfo)147     public final Context createServiceBaseContext(ActivityThread mainThread,
148             LoadedApk packageInfo) {
149         final Context context = super.createServiceBaseContext(mainThread, packageInfo);
150         final Display display = context.getSystemService(DisplayManager.class)
151                 .getDisplay(getInitialDisplayId());
152         return context.createTokenContext(mWindowToken, display);
153     }
154 
155     /** @hide */
156     @Override
attachBaseContext(Context newBase)157     protected void attachBaseContext(Context newBase) {
158         super.attachBaseContext(newBase);
159         if (!mInitialized) {
160             mWindowToken.attachContext(this);
161             mController.attachToDisplayArea(getWindowType(), getDisplayId(),
162                     getWindowContextOptions());
163             mWindowManager = WindowManagerImpl.createWindowContextWindowManager(this);
164             mInitialized = true;
165         }
166     }
167 
168     @SuppressLint("OnNameExpected")
169     @Override
170     // Suppress the lint because ths is overridden from Context.
getSystemService(@onNull String name)171     public @Nullable Object getSystemService(@NonNull String name) {
172         if (WINDOW_SERVICE.equals(name)) {
173             return mWindowManager;
174         }
175         return super.getSystemService(name);
176     }
177 
178     @CallSuper
179     @Override
onDestroy()180     public void onDestroy() {
181         super.onDestroy();
182         mController.detachIfNeeded();
183     }
184 }
185