Merge "Allow WPS to create windows with multiple type" into sc-v2-dev

This commit is contained in:
Charles Chen
2021-08-13 06:24:45 +00:00
committed by Android (Google) Code Review
8 changed files with 154 additions and 36 deletions

View File

@@ -3323,7 +3323,7 @@ package android.window {
ctor public WindowProviderService();
method public final void attachToWindowToken(@NonNull android.os.IBinder);
method @NonNull public int getInitialDisplayId();
method @Nullable public android.os.Bundle getWindowContextOptions();
method @CallSuper @Nullable public android.os.Bundle getWindowContextOptions();
method public abstract int getWindowType();
}

View File

@@ -309,7 +309,7 @@ public abstract class AbstractInputMethodService extends WindowProviderService
@Override
@Nullable
public final Bundle getWindowContextOptions() {
return null;
return super.getWindowContextOptions();
}
/** @hide */

View File

@@ -19,9 +19,12 @@ package android.view;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.window.WindowProvider.KEY_IS_WINDOW_PROVIDER_SERVICE;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
@@ -36,7 +39,9 @@ import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.StrictMode;
import android.window.WindowContext;
import android.window.WindowProvider;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
@@ -145,6 +150,7 @@ public final class WindowManagerImpl implements WindowManager {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
assertWindowContextTypeMatches(wparams.type);
// Only use the default token if we don't have a parent window and a token.
if (mDefaultToken != null && mParentWindow == null && wparams.token == null) {
wparams.token = mDefaultToken;
@@ -152,6 +158,35 @@ public final class WindowManagerImpl implements WindowManager {
wparams.mWindowContextToken = mWindowContextToken;
}
private void assertWindowContextTypeMatches(@LayoutParams.WindowType int windowType) {
if (!(mContext instanceof WindowProvider)) {
return;
}
// Don't need to check sub-window type because sub window should be allowed to be attached
// to the parent window.
if (windowType >= FIRST_SUB_WINDOW && windowType <= LAST_SUB_WINDOW) {
return;
}
final WindowProvider windowProvider = (WindowProvider) mContext;
if (windowProvider.getWindowType() == windowType) {
return;
}
IllegalArgumentException exception = new IllegalArgumentException("Window type mismatch."
+ " Window Context's window type is " + windowProvider.getWindowType()
+ ", while LayoutParams' type is set to " + windowType + "."
+ " Please create another Window Context via"
+ " createWindowContext(getDisplay(), " + windowType + ", null)"
+ " to add window with type:" + windowType);
if (!windowProvider.getWindowContextOptions().getBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE,
false)) {
throw exception;
}
// Throw IncorrectCorrectViolation if the Window Context is allowed to provide multiple
// window types. Usually it's because the Window Context is a WindowProviderService.
StrictMode.onIncorrectContextUsed("WindowContext's window type must"
+ " match type in WindowManager.LayoutParams", exception);
}
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);

View File

@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.Display;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
@@ -42,29 +43,33 @@ import java.lang.ref.Reference;
* @hide
*/
@UiContext
public class WindowContext extends ContextWrapper {
public class WindowContext extends ContextWrapper implements WindowProvider {
private final WindowManager mWindowManager;
private final @WindowManager.LayoutParams.WindowType int mType;
private final @Nullable Bundle mOptions;
@WindowManager.LayoutParams.WindowType
private final int mType;
@Nullable
private final Bundle mOptions;
private final ComponentCallbacksController mCallbacksController =
new ComponentCallbacksController();
private final WindowContextController mController;
/**
* Default constructor. Will generate a {@link WindowTokenClient} and attach this context to
* the token.
* Default implementation of {@link WindowContext}
* <p>
* Note that the users should call {@link Context#createWindowContext(Display, int, Bundle)}
* to create a {@link WindowContext} instead of using this constructor
* </p><p>
* Example usage:
* <pre class="prettyprint">
* Bundle options = new Bundle();
* options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
* Context windowContext = context.createWindowContext(display, windowType, options);
* </pre></p>
*
* @param base Base {@link Context} for this new instance.
* @param type Window type to be used with this context.
* @param options A bundle used to pass window-related options. For example, on device with
* multiple DisplayAreaGroups, one may specify the RootDisplayArea for the window
* using {@link DisplayAreaOrganizer#KEY_ROOT_DISPLAY_AREA_ID} in the options.
* Example usage:
* Bundle options = new Bundle();
* options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
* Context windowContext = context.createWindowContext(display, type, options);
* @param base Base {@link Context} for this new instance.
* @param type Window type to be used with this context.
* @param options A bundle used to pass window-related options.
* @see DisplayAreaInfo#rootDisplayAreaId
* @hide
*/
public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) {
super(base);
@@ -110,10 +115,13 @@ public class WindowContext extends ContextWrapper {
@Override
public void destroy() {
mCallbacksController.clearCallbacks();
// Called to the base ContextImpl to do final clean-up.
getBaseContext().destroy();
Reference.reachabilityFence(this);
try {
mCallbacksController.clearCallbacks();
// Called to the base ContextImpl to do final clean-up.
getBaseContext().destroy();
} finally {
Reference.reachabilityFence(this);
}
}
@Override
@@ -130,4 +138,15 @@ public class WindowContext extends ContextWrapper {
void dispatchConfigurationChanged(@NonNull Configuration newConfig) {
mCallbacksController.dispatchConfigurationChanged(newConfig);
}
@Override
public int getWindowType() {
return mType;
}
@Nullable
@Override
public Bundle getWindowContextOptions() {
return mOptions;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2020 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 android.annotation.Nullable;
import android.os.Bundle;
import android.view.WindowManager.LayoutParams.WindowType;
/**
* An interface to provide a non-activity window.
* Examples are {@link WindowContext} and {@link WindowProviderService}.
*
* @hide
*/
public interface WindowProvider {
/** @hide */
String KEY_IS_WINDOW_PROVIDER_SERVICE = "android.windowContext.isWindowProviderService";
/** Gets the window type of this provider */
@WindowType
int getWindowType();
/** Gets the launch options of this provider */
@Nullable
Bundle getWindowContextOptions();
}

View File

@@ -42,21 +42,26 @@ import android.view.WindowManagerImpl;
* {@link WindowContext}, but is represented as {@link Service}.
*
* @see android.inputmethodservice.InputMethodService
* @see android.accessibilityservice.AccessibilityService
*
* @hide
*/
@TestApi
@UiContext
public abstract class WindowProviderService extends Service {
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;
public WindowProviderService() {
mOptions = new Bundle();
mOptions.putBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, true);
}
/**
* Returns the type of this {@link WindowProviderService}.
* 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)}
*
@@ -68,15 +73,24 @@ public abstract class WindowProviderService extends Service {
@SuppressLint("OnNameExpected")
// Suppress the lint because it is not a callback and users should provide window type
// so we cannot make it final.
public abstract @WindowType int getWindowType();
@WindowType
@Override
public abstract int getWindowType();
/**
* Returns the option of this {@link WindowProviderService}.
* Default is {@code null}. The inheriting class can implement this method to provide the
* customization {@code option} of the window. It is used similar to {@code options} of
* {@link Context#createWindowContext(int, Bundle)}
*
* @see Context#createWindowContext(int, Bundle)
* <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
*/
@@ -85,8 +99,10 @@ public abstract class WindowProviderService extends Service {
// 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 null;
return mOptions;
}
/**

View File

@@ -94,6 +94,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
}
// TODO(b/192048581): rewrite this method based on WindowContext and WindowProviderService
// are inherited from WindowProvider.
/**
* Called when {@link Configuration} updates from the server side receive.
*

View File

@@ -87,6 +87,7 @@ import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN;
import static android.window.WindowContext.KEY_IS_WINDOW_PROVIDER_SERVICE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT;
@@ -1730,16 +1731,22 @@ public class WindowManagerService extends IWindowManager.Stub
&& mWindowContextListenerController.hasListener(windowContextToken)) {
final int windowContextType = mWindowContextListenerController
.getWindowType(windowContextToken);
final Bundle options = mWindowContextListenerController
.getOptions(windowContextToken);
if (type != windowContextType) {
ProtoLog.w(WM_ERROR, "Window types in WindowContext and"
+ " LayoutParams.type should match! Type from LayoutParams is %d,"
+ " but type from WindowContext is %d", type, windowContextType);
return WindowManagerGlobal.ADD_INVALID_TYPE;
// We allow WindowProviderService to add window other than windowContextType,
// but the WindowProviderService won't be associated with the window's
// WindowToken.
if (!options.getBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, false)) {
return WindowManagerGlobal.ADD_INVALID_TYPE;
}
} else {
mWindowContextListenerController.registerWindowContainerListener(
windowContextToken, token, callingUid, type, options);
}
final Bundle options = mWindowContextListenerController
.getOptions(windowContextToken);
mWindowContextListenerController.registerWindowContainerListener(
windowContextToken, token, callingUid, type, options);
}
// From now on, no exceptions or errors allowed!