Merge "Introduce WM#LayoutParams mWindowContextToken"

This commit is contained in:
Charles Chen
2021-01-25 02:10:15 +00:00
committed by Android (Google) Code Review
4 changed files with 87 additions and 31 deletions

View File

@@ -93,6 +93,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -2843,6 +2844,16 @@ public interface WindowManager extends ViewManager {
*/
public IBinder token = null;
/**
* The token of {@link android.app.WindowContext}. It is usually a
* {@link android.app.WindowTokenClient} and is used for updating
* {@link android.content.res.Resources} from {@link Configuration} propagated from the
* server side.
*
* @hide
*/
public IBinder mWindowContextToken = null;
/**
* Name of the package owning this window.
*/
@@ -3552,6 +3563,7 @@ public interface WindowManager extends ViewManager {
out.writeFloat(buttonBrightness);
out.writeInt(rotationAnimation);
out.writeStrongBinder(token);
out.writeStrongBinder(mWindowContextToken);
out.writeString(packageName);
TextUtils.writeToParcel(mTitle, out, parcelableFlags);
out.writeInt(screenOrientation);
@@ -3620,6 +3632,7 @@ public interface WindowManager extends ViewManager {
buttonBrightness = in.readFloat();
rotationAnimation = in.readInt();
token = in.readStrongBinder();
mWindowContextToken = in.readStrongBinder();
packageName = in.readString();
mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
screenOrientation = in.readInt();
@@ -3781,6 +3794,11 @@ public interface WindowManager extends ViewManager {
// already have one.
token = o.token;
}
if (mWindowContextToken == null) {
// NOTE: token only copied if the recipient doesn't
// already have one.
mWindowContextToken = o.mWindowContextToken;
}
if (packageName == null) {
// NOTE: packageName only copied if the recipient doesn't
// already have one.

View File

@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
import android.app.ResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
@@ -74,23 +75,42 @@ public final class WindowManagerImpl implements WindowManager {
public final Context mContext;
private final Window mParentWindow;
/**
* If {@link LayoutParams#token} is {@code null} and no parent window is specified, the value
* of {@link LayoutParams#token} will be overridden to {@code mDefaultToken}.
*/
private IBinder mDefaultToken;
/**
* This token will be set to {@link LayoutParams#mWindowContextToken} and used to receive
* configuration changes from the server side.
*/
@Nullable
private final IBinder mWindowContextToken;
public WindowManagerImpl(Context context) {
this(context, null);
this(context, null /* parentWindow */, null /* clientToken */);
}
private WindowManagerImpl(Context context, Window parentWindow) {
private WindowManagerImpl(Context context, Window parentWindow,
@Nullable IBinder windowContextToken) {
mContext = context;
mParentWindow = parentWindow;
mWindowContextToken = windowContextToken;
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken);
}
public WindowManagerImpl createPresentationWindowManager(Context displayContext) {
return new WindowManagerImpl(displayContext, mParentWindow);
return new WindowManagerImpl(displayContext, mParentWindow, mWindowContextToken);
}
/** Creates a {@link WindowManager} for a {@link android.app.WindowContext}. */
public static WindowManager createWindowContextWindowManager(Context context) {
final IBinder clientToken = context.getWindowContextToken();
return new WindowManagerImpl(context, null /* parentWindow */, clientToken);
}
/**
@@ -105,30 +125,27 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
applyTokens(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
applyTokens(params);
mGlobal.updateViewLayout(view, params);
}
private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) {
// Only use the default token if we don't have a parent window.
if (mDefaultToken != null && mParentWindow == null) {
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
// Only use the default token if we don't already have a token.
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (wparams.token == null) {
wparams.token = mDefaultToken;
}
private void applyTokens(@NonNull ViewGroup.LayoutParams params) {
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
// 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;
}
wparams.mWindowContextToken = mWindowContextToken;
}
@Override

View File

@@ -19,6 +19,7 @@ package android.app;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -28,7 +29,10 @@ import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.IWindowManager;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerImpl;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -50,23 +54,41 @@ import org.junit.runner.RunWith;
@SmallTest
@Presubmit
public class WindowContextTest {
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
private final WindowContext mWindowContext = createWindowContext();
@Test
public void testWindowContextRelease_doRemoveWindowToken() throws Throwable {
final Context instContext = InstrumentationRegistry.getInstrumentation()
.getTargetContext();
final Display display = instContext.getSystemService(DisplayManager.class)
.getDisplay(DEFAULT_DISPLAY);
final Context context = instContext.createDisplayContext(display);
final WindowContext windowContext = new WindowContext(context, TYPE_APPLICATION_OVERLAY,
null /* options */);
final IBinder token = windowContext.getWindowContextToken();
final IBinder token = mWindowContext.getWindowContextToken();
final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
assertTrue("Token must be registered to WMS", wms.isWindowToken(token));
windowContext.release();
mWindowContext.release();
assertFalse("Token must be unregistered to WMS", wms.isWindowToken(token));
}
@Test
public void testCreateWindowContextWindowManagerAttachClientToken() {
final WindowManager windowContextWm = WindowManagerImpl
.createWindowContextWindowManager(mWindowContext);
final WindowManager.LayoutParams params =
new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
mInstrumentation.runOnMainSync(() -> {
final View view = new View(mWindowContext);
windowContextWm.addView(view, params);
});
assertEquals(mWindowContext.getWindowContextToken(), params.mWindowContextToken);
}
private WindowContext createWindowContext() {
final Context instContext = mInstrumentation.getTargetContext();
final Display display = instContext.getSystemService(DisplayManager.class)
.getDisplay(DEFAULT_DISPLAY);
final Context context = instContext.createDisplayContext(display);
return new WindowContext(context, TYPE_APPLICATION_OVERLAY,
null /* options */);
}
}

View File

@@ -29,7 +29,6 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.view.View;
import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -46,7 +45,7 @@ import java.util.Objects;
* {@link WindowManagerService#registerWindowContextListener(IBinder, int, int, Bundle)}
* automatically.</li>
* <li>When the {@link android.app.WindowContext} adds the first window to the screen via
* {@link android.view.WindowManager#addView(View, ViewGroup.LayoutParams)},
* {@link android.view.WindowManager#addView(View, android.view.ViewGroup.LayoutParams)},
* {@link WindowManagerService} then updates the {@link WindowContextListenerImpl} to listen
* to corresponding {@link WindowToken} via this controller.</li>
* <li>When the {@link android.app.WindowContext} is GCed, it unregisters the previously