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