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(); ctor public WindowProviderService();
method public final void attachToWindowToken(@NonNull android.os.IBinder); method public final void attachToWindowToken(@NonNull android.os.IBinder);
method @NonNull public int getInitialDisplayId(); 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(); method public abstract int getWindowType();
} }

View File

@@ -309,7 +309,7 @@ public abstract class AbstractInputMethodService extends WindowProviderService
@Override @Override
@Nullable @Nullable
public final Bundle getWindowContextOptions() { public final Bundle getWindowContextOptions() {
return null; return super.getWindowContextOptions();
} }
/** @hide */ /** @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_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
import static android.view.View.SYSTEM_UI_FLAG_VISIBLE; 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_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 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.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.window.WindowProvider.KEY_IS_WINDOW_PROVIDER_SERVICE;
import android.annotation.CallbackExecutor; import android.annotation.CallbackExecutor;
import android.annotation.NonNull; import android.annotation.NonNull;
@@ -36,7 +39,9 @@ import android.graphics.Region;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.StrictMode;
import android.window.WindowContext; import android.window.WindowContext;
import android.window.WindowProvider;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver; import com.android.internal.os.IResultReceiver;
@@ -145,6 +150,7 @@ public final class WindowManagerImpl implements WindowManager {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
} }
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; 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. // Only use the default token if we don't have a parent window and a token.
if (mDefaultToken != null && mParentWindow == null && wparams.token == null) { if (mDefaultToken != null && mParentWindow == null && wparams.token == null) {
wparams.token = mDefaultToken; wparams.token = mDefaultToken;
@@ -152,6 +158,35 @@ public final class WindowManagerImpl implements WindowManager {
wparams.mWindowContextToken = mWindowContextToken; 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 @Override
public void removeView(View view) { public void removeView(View view) {
mGlobal.removeView(view, false); mGlobal.removeView(view, false);

View File

@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.ContextWrapper; import android.content.ContextWrapper;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.view.Display;
import android.view.WindowManager; import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
@@ -42,29 +43,33 @@ import java.lang.ref.Reference;
* @hide * @hide
*/ */
@UiContext @UiContext
public class WindowContext extends ContextWrapper { public class WindowContext extends ContextWrapper implements WindowProvider {
private final WindowManager mWindowManager; private final WindowManager mWindowManager;
private final @WindowManager.LayoutParams.WindowType int mType; @WindowManager.LayoutParams.WindowType
private final @Nullable Bundle mOptions; private final int mType;
@Nullable
private final Bundle mOptions;
private final ComponentCallbacksController mCallbacksController = private final ComponentCallbacksController mCallbacksController =
new ComponentCallbacksController(); new ComponentCallbacksController();
private final WindowContextController mController; private final WindowContextController mController;
/** /**
* Default constructor. Will generate a {@link WindowTokenClient} and attach this context to * Default implementation of {@link WindowContext}
* the token. * <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 base Base {@link Context} for this new instance.
* @param type Window type to be used with this context. * @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 * @param options A bundle used to pass window-related options.
* 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);
* @see DisplayAreaInfo#rootDisplayAreaId * @see DisplayAreaInfo#rootDisplayAreaId
* @hide
*/ */
public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) { public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) {
super(base); super(base);
@@ -110,11 +115,14 @@ public class WindowContext extends ContextWrapper {
@Override @Override
public void destroy() { public void destroy() {
try {
mCallbacksController.clearCallbacks(); mCallbacksController.clearCallbacks();
// Called to the base ContextImpl to do final clean-up. // Called to the base ContextImpl to do final clean-up.
getBaseContext().destroy(); getBaseContext().destroy();
} finally {
Reference.reachabilityFence(this); Reference.reachabilityFence(this);
} }
}
@Override @Override
public void registerComponentCallbacks(@NonNull ComponentCallbacks callback) { public void registerComponentCallbacks(@NonNull ComponentCallbacks callback) {
@@ -130,4 +138,15 @@ public class WindowContext extends ContextWrapper {
void dispatchConfigurationChanged(@NonNull Configuration newConfig) { void dispatchConfigurationChanged(@NonNull Configuration newConfig) {
mCallbacksController.dispatchConfigurationChanged(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}. * {@link WindowContext}, but is represented as {@link Service}.
* *
* @see android.inputmethodservice.InputMethodService * @see android.inputmethodservice.InputMethodService
* @see android.accessibilityservice.AccessibilityService
* *
* @hide * @hide
*/ */
@TestApi @TestApi
@UiContext @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 WindowTokenClient mWindowToken = new WindowTokenClient();
private final WindowContextController mController = new WindowContextController(mWindowToken); private final WindowContextController mController = new WindowContextController(mWindowToken);
private WindowManager mWindowManager; private WindowManager mWindowManager;
private boolean mInitialized; 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 * 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)} * used similar to {@code type} of {@link Context#createWindowContext(int, Bundle)}
* *
@@ -68,15 +73,24 @@ public abstract class WindowProviderService extends Service {
@SuppressLint("OnNameExpected") @SuppressLint("OnNameExpected")
// Suppress the lint because it is not a callback and users should provide window type // Suppress the lint because it is not a callback and users should provide window type
// so we cannot make it final. // so we cannot make it final.
public abstract @WindowType int getWindowType(); @WindowType
@Override
public abstract int getWindowType();
/** /**
* Returns the option of this {@link WindowProviderService}. * Returns the option of this {@link WindowProviderService}.
* Default is {@code null}. The inheriting class can implement this method to provide the * <p>
* customization {@code option} of the window. It is used similar to {@code options} of * The inheriting class can implement this method to provide the customization {@code option} of
* {@link Context#createWindowContext(int, Bundle)} * 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)}
* @see 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 * @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 // 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. // launch option. Also, the return value of this API is null by default.
@Nullable @Nullable
@CallSuper
@Override
public Bundle getWindowContextOptions() { public Bundle getWindowContextOptions() {
return null; return mOptions;
} }
/** /**

View File

@@ -94,6 +94,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */); 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. * 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.WindowManagerPolicyConstants.NAV_BAR_INVALID;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; 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.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_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT;
@@ -1730,17 +1731,23 @@ public class WindowManagerService extends IWindowManager.Stub
&& mWindowContextListenerController.hasListener(windowContextToken)) { && mWindowContextListenerController.hasListener(windowContextToken)) {
final int windowContextType = mWindowContextListenerController final int windowContextType = mWindowContextListenerController
.getWindowType(windowContextToken); .getWindowType(windowContextToken);
final Bundle options = mWindowContextListenerController
.getOptions(windowContextToken);
if (type != windowContextType) { if (type != windowContextType) {
ProtoLog.w(WM_ERROR, "Window types in WindowContext and" ProtoLog.w(WM_ERROR, "Window types in WindowContext and"
+ " LayoutParams.type should match! Type from LayoutParams is %d," + " LayoutParams.type should match! Type from LayoutParams is %d,"
+ " but type from WindowContext is %d", type, windowContextType); + " but type from WindowContext is %d", type, windowContextType);
// 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; return WindowManagerGlobal.ADD_INVALID_TYPE;
} }
final Bundle options = mWindowContextListenerController } else {
.getOptions(windowContextToken);
mWindowContextListenerController.registerWindowContainerListener( mWindowContextListenerController.registerWindowContainerListener(
windowContextToken, token, callingUid, type, options); windowContextToken, token, callingUid, type, options);
} }
}
// From now on, no exceptions or errors allowed! // From now on, no exceptions or errors allowed!