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 /** 133 * Here we override to prevent WindowProviderService from invoking 134 * {@link Application.registerComponentCallback}, which will result in callback registered 135 * for process-level Configuration change updates. 136 */ 137 @Override registerComponentCallbacks(@onNull ComponentCallbacks callback)138 public void registerComponentCallbacks(@NonNull ComponentCallbacks callback) { 139 // For broadcasting Configuration Changes. 140 mCallbacksController.registerCallbacks(callback); 141 } 142 143 @SuppressLint("OnNameExpected") 144 @Override unregisterComponentCallbacks(@onNull ComponentCallbacks callback)145 public void unregisterComponentCallbacks(@NonNull ComponentCallbacks callback) { 146 mCallbacksController.unregisterCallbacks(callback); 147 } 148 149 @SuppressLint("OnNameExpected") 150 @Override onConfigurationChanged(@onNull Configuration configuration)151 public void onConfigurationChanged(@NonNull Configuration configuration) { 152 // This is only called from WindowTokenClient. 153 mCallbacksController.dispatchConfigurationChanged(configuration); 154 } 155 156 /** 157 * Override {@link Service}'s empty implementation and listen to {@code ActivityThread} for 158 * low memory and trim memory events. 159 */ 160 @Override onLowMemory()161 public void onLowMemory() { 162 mCallbacksController.dispatchLowMemory(); 163 } 164 165 @Override onTrimMemory(int level)166 public void onTrimMemory(int level) { 167 mCallbacksController.dispatchTrimMemory(level); 168 } 169 170 /** 171 * Returns the display ID to launch this {@link WindowProviderService}. 172 * 173 * @hide 174 */ 175 @TestApi 176 @SuppressLint({"OnNameExpected"}) 177 // Suppress the lint because it is not a callback and users may override this API to provide 178 // display. 179 @NonNull getInitialDisplayId()180 public int getInitialDisplayId() { 181 return DEFAULT_DISPLAY; 182 } 183 184 /** 185 * Attaches this WindowProviderService to the {@code windowToken}. 186 * 187 * @hide 188 */ 189 @TestApi attachToWindowToken(@onNull IBinder windowToken)190 public final void attachToWindowToken(@NonNull IBinder windowToken) { 191 mController.attachToWindowToken(windowToken); 192 } 193 194 /** @hide */ 195 @Override createServiceBaseContext(ActivityThread mainThread, LoadedApk packageInfo)196 public final Context createServiceBaseContext(ActivityThread mainThread, 197 LoadedApk packageInfo) { 198 final Context context = super.createServiceBaseContext(mainThread, packageInfo); 199 final DisplayManager displayManager = context.getSystemService(DisplayManager.class); 200 final int initialDisplayId = getInitialDisplayId(); 201 Display display = displayManager.getDisplay(initialDisplayId); 202 // Fallback to use the default display if the initial display to start WindowProviderService 203 // is detached. 204 if (display == null) { 205 Log.e(TAG, "Display with id " + initialDisplayId + " not found, falling back to " 206 + "DEFAULT_DISPLAY"); 207 display = displayManager.getDisplay(DEFAULT_DISPLAY); 208 } 209 return context.createTokenContext(mWindowToken, display); 210 } 211 212 /** @hide */ 213 @Override attachBaseContext(Context newBase)214 protected void attachBaseContext(Context newBase) { 215 super.attachBaseContext(newBase); 216 if (!mInitialized) { 217 mWindowToken.attachContext(this); 218 mController.attachToDisplayArea(getWindowType(), getDisplayId(), 219 getWindowContextOptions()); 220 mWindowManager = WindowManagerImpl.createWindowContextWindowManager(this); 221 mInitialized = true; 222 } 223 } 224 225 // Suppress the lint because ths is overridden from Context. 226 @SuppressLint("OnNameExpected") 227 @Override 228 @Nullable getSystemService(@onNull String name)229 public Object getSystemService(@NonNull String name) { 230 if (WINDOW_SERVICE.equals(name)) { 231 return mWindowManager; 232 } 233 return super.getSystemService(name); 234 } 235 236 @CallSuper 237 @Override onDestroy()238 public void onDestroy() { 239 super.onDestroy(); 240 mController.detachIfNeeded(); 241 mCallbacksController.clearCallbacks(); 242 } 243 } 244