Merge "Associate SystemUiContext with DisplayContent"
This commit is contained in:
@@ -29,6 +29,7 @@ import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
|
||||
import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
|
||||
import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS;
|
||||
import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.window.ConfigurationHelper.diffPublicWithSizeBuckets;
|
||||
import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
|
||||
@@ -322,7 +323,7 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
|
||||
@UnsupportedAppUsage
|
||||
private ContextImpl mSystemContext;
|
||||
private ContextImpl mSystemUiContext;
|
||||
private final SparseArray<ContextImpl> mDisplaySystemUiContexts = new SparseArray<>();
|
||||
|
||||
@UnsupportedAppUsage
|
||||
static volatile IPackageManager sPackageManager;
|
||||
@@ -2641,22 +2642,26 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public ContextImpl getSystemUiContext() {
|
||||
synchronized (this) {
|
||||
if (mSystemUiContext == null) {
|
||||
mSystemUiContext = ContextImpl.createSystemUiContext(getSystemContext());
|
||||
}
|
||||
return mSystemUiContext;
|
||||
}
|
||||
return getSystemUiContext(DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the context instance base on system resources & display information which used for UI.
|
||||
* Gets the context instance base on system resources & display information which used for UI.
|
||||
* @param displayId The ID of the display where the UI is shown.
|
||||
* @see ContextImpl#createSystemUiContext(ContextImpl, int)
|
||||
*/
|
||||
public ContextImpl createSystemUiContext(int displayId) {
|
||||
return ContextImpl.createSystemUiContext(getSystemUiContext(), displayId);
|
||||
@NonNull
|
||||
public ContextImpl getSystemUiContext(int displayId) {
|
||||
synchronized (this) {
|
||||
ContextImpl systemUiContext = mDisplaySystemUiContexts.get(displayId);
|
||||
if (systemUiContext == null) {
|
||||
systemUiContext = ContextImpl.createSystemUiContext(getSystemContext(), displayId);
|
||||
mDisplaySystemUiContexts.put(displayId, systemUiContext);
|
||||
}
|
||||
return systemUiContext;
|
||||
}
|
||||
}
|
||||
|
||||
public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
|
||||
@@ -3775,7 +3780,7 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
if (pkgName != null && !pkgName.isEmpty()
|
||||
&& r.packageInfo.mPackageName.contains(pkgName)) {
|
||||
for (int id : dm.getDisplayIds()) {
|
||||
if (id != Display.DEFAULT_DISPLAY) {
|
||||
if (id != DEFAULT_DISPLAY) {
|
||||
Display display =
|
||||
dm.getCompatibleDisplay(id, appContext.getResources());
|
||||
appContext = (ContextImpl) appContext.createDisplayContext(display);
|
||||
|
||||
@@ -2638,7 +2638,10 @@ class ContextImpl extends Context {
|
||||
overrideConfig, display.getDisplayAdjustments().getCompatibilityInfo(),
|
||||
mResources.getLoaders()));
|
||||
context.mDisplay = display;
|
||||
context.mContextType = CONTEXT_TYPE_DISPLAY_CONTEXT;
|
||||
// Inherit context type if the container is from System or System UI context to bypass
|
||||
// UI context check.
|
||||
context.mContextType = mContextType == CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
|
||||
? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI : CONTEXT_TYPE_DISPLAY_CONTEXT;
|
||||
// Display contexts and any context derived from a display context should always override
|
||||
// the display that would otherwise be inherited from mToken (or the global configuration if
|
||||
// mToken is null).
|
||||
@@ -2691,7 +2694,8 @@ class ContextImpl extends Context {
|
||||
|
||||
// Step 2. Create the base context of the window context, it will also create a Resources
|
||||
// associated with the WindowTokenClient and set the token to the base context.
|
||||
final ContextImpl windowContextBase = createWindowContextBase(windowTokenClient, display);
|
||||
final ContextImpl windowContextBase = createWindowContextBase(windowTokenClient,
|
||||
display.getDisplayId());
|
||||
|
||||
// Step 3. Create a WindowContext instance and set it as the outer context of the base
|
||||
// context to make the service obtained by #getSystemService(String) able to query
|
||||
@@ -2716,9 +2720,7 @@ class ContextImpl extends Context {
|
||||
if (display == null) {
|
||||
throw new IllegalArgumentException("Display must not be null");
|
||||
}
|
||||
final ContextImpl tokenContext = createWindowContextBase(token, display);
|
||||
tokenContext.setResources(createWindowContextResources(tokenContext));
|
||||
return tokenContext;
|
||||
return createWindowContextBase(token, display.getDisplayId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2726,13 +2728,13 @@ class ContextImpl extends Context {
|
||||
* window.
|
||||
*
|
||||
* @param token The token to associate with {@link Resources}
|
||||
* @param display The {@link Display} to associate with.
|
||||
* @param displayId The ID of {@link Display} to associate with.
|
||||
*
|
||||
* @see #createWindowContext(Display, int, Bundle)
|
||||
* @see #createTokenContext(IBinder, Display)
|
||||
*/
|
||||
@UiContext
|
||||
ContextImpl createWindowContextBase(@NonNull IBinder token, @NonNull Display display) {
|
||||
ContextImpl createWindowContextBase(@NonNull IBinder token, int displayId) {
|
||||
ContextImpl baseContext = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
|
||||
mAttributionSource.getAttributionTag(),
|
||||
mAttributionSource.getNext(),
|
||||
@@ -2746,8 +2748,8 @@ class ContextImpl extends Context {
|
||||
baseContext.setResources(windowContextResources);
|
||||
// Associate the display with window context resources so that configuration update from
|
||||
// the server side will also apply to the display's metrics.
|
||||
baseContext.mDisplay = ResourcesManager.getInstance()
|
||||
.getAdjustedDisplay(display.getDisplayId(), windowContextResources);
|
||||
baseContext.mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId,
|
||||
windowContextResources);
|
||||
|
||||
return baseContext;
|
||||
}
|
||||
@@ -2983,6 +2985,18 @@ class ContextImpl extends Context {
|
||||
mContentCaptureOptions = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
// If mToken is a WindowTokenClient, the Context is usually associated with a
|
||||
// WindowContainer. We should detach from WindowContainer when the Context is finalized
|
||||
// if this Context is not a WindowContext. WindowContext finalization is handled in
|
||||
// WindowContext class.
|
||||
if (mToken instanceof WindowTokenClient && mContextType != CONTEXT_TYPE_WINDOW_CONTEXT) {
|
||||
((WindowTokenClient) mToken).detachFromWindowContainerIfNeeded();
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
static ContextImpl createSystemContext(ActivityThread mainThread) {
|
||||
LoadedApk packageInfo = new LoadedApk(mainThread);
|
||||
@@ -3003,22 +3017,13 @@ class ContextImpl extends Context {
|
||||
* @param displayId The ID of the display where the UI is shown.
|
||||
*/
|
||||
static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) {
|
||||
final LoadedApk packageInfo = systemContext.mPackageInfo;
|
||||
ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo,
|
||||
ContextParams.EMPTY, null, null, null, null, null, 0, null, null);
|
||||
context.setResources(createResources(null, packageInfo, null, displayId, null,
|
||||
packageInfo.getCompatibilityInfo(), null));
|
||||
context.updateDisplay(displayId);
|
||||
final WindowTokenClient token = new WindowTokenClient();
|
||||
final ContextImpl context = systemContext.createWindowContextBase(token, displayId);
|
||||
token.attachContext(context);
|
||||
token.attachToDisplayContent(displayId);
|
||||
context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* The overloaded method of {@link #createSystemUiContext(ContextImpl, int)}.
|
||||
* Uses {@Code Display.DEFAULT_DISPLAY} as the target display.
|
||||
*/
|
||||
static ContextImpl createSystemUiContext(ContextImpl systemContext) {
|
||||
return createSystemUiContext(systemContext, Display.DEFAULT_DISPLAY);
|
||||
return context;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
@@ -3227,7 +3232,13 @@ class ContextImpl extends Context {
|
||||
|
||||
@Override
|
||||
public IBinder getWindowContextToken() {
|
||||
return mContextType == CONTEXT_TYPE_WINDOW_CONTEXT ? mToken : null;
|
||||
switch (mContextType) {
|
||||
case CONTEXT_TYPE_WINDOW_CONTEXT:
|
||||
case CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI:
|
||||
return mToken;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMode(int mode) {
|
||||
|
||||
@@ -854,6 +854,23 @@ interface IWindowManager
|
||||
*/
|
||||
void attachWindowContextToWindowToken(IBinder clientToken, IBinder token);
|
||||
|
||||
/**
|
||||
* Attaches a {@code clientToken} to associate with DisplayContent.
|
||||
* <p>
|
||||
* Note that this API should be invoked after calling
|
||||
* {@link android.window.WindowTokenClient#attachContext(Context)}
|
||||
* </p>
|
||||
*
|
||||
* @param clientToken {@link android.window.WindowContext#getWindowContextToken()
|
||||
* the WindowContext's token}
|
||||
* @param displayId The display associated with the window context
|
||||
*
|
||||
* @return the DisplayContent's {@link android.app.res.Configuration} if the Context is
|
||||
* attached to the DisplayContent successfully. {@code null}, otherwise.
|
||||
* @throws android.view.WindowManager.InvalidDisplayException if the display ID is invalid
|
||||
*/
|
||||
Configuration attachToDisplayContent(IBinder clientToken, int displayId);
|
||||
|
||||
/**
|
||||
* Detaches {@link android.window.WindowContext} from the window manager node it's currently
|
||||
* attached to. It is no-op if the WindowContext is not attached to a window manager node.
|
||||
|
||||
@@ -19,13 +19,10 @@ package android.window;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.WindowManager.LayoutParams.WindowType;
|
||||
import android.view.WindowManagerGlobal;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
@@ -38,7 +35,6 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
* @hide
|
||||
*/
|
||||
public class WindowContextController {
|
||||
private final IWindowManager mWms;
|
||||
/**
|
||||
* {@code true} to indicate that the {@code mToken} is associated with a
|
||||
* {@link com.android.server.wm.DisplayArea}. Note that {@code mToken} is able to attach a
|
||||
@@ -56,14 +52,7 @@ public class WindowContextController {
|
||||
* {@link Context#getWindowContextToken()}.
|
||||
*/
|
||||
public WindowContextController(@NonNull WindowTokenClient token) {
|
||||
this(token, WindowManagerGlobal.getWindowManagerService());
|
||||
}
|
||||
|
||||
/** Used for test only. DO NOT USE it in production code. */
|
||||
@VisibleForTesting
|
||||
public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) {
|
||||
mToken = token;
|
||||
mWms = mockWms;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,19 +69,7 @@ public class WindowContextController {
|
||||
throw new IllegalStateException("A Window Context can be only attached to "
|
||||
+ "a DisplayArea once.");
|
||||
}
|
||||
try {
|
||||
final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type,
|
||||
displayId, options);
|
||||
if (configuration != null) {
|
||||
mAttachedToDisplayArea = true;
|
||||
// Send the DisplayArea's configuration to WindowContext directly instead of
|
||||
// waiting for dispatching from WMS.
|
||||
mToken.onConfigurationChanged(configuration, displayId,
|
||||
false /* shouldReportConfigChange */);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
mAttachedToDisplayArea = mToken.attachToDisplayArea(type, displayId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,22 +97,14 @@ public class WindowContextController {
|
||||
throw new IllegalStateException("The Window Context should have been attached"
|
||||
+ " to a DisplayArea.");
|
||||
}
|
||||
try {
|
||||
mWms.attachWindowContextToWindowToken(mToken, windowToken);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
mToken.attachToWindowToken(windowToken);
|
||||
}
|
||||
|
||||
/** Detaches the window context from the node it's currently associated with. */
|
||||
public void detachIfNeeded() {
|
||||
if (mAttachedToDisplayArea) {
|
||||
try {
|
||||
mWms.detachWindowContextFromWindowContainer(mToken);
|
||||
mAttachedToDisplayArea = false;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
mToken.detachFromWindowContainerIfNeeded();
|
||||
mAttachedToDisplayArea = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import static android.window.ConfigurationHelper.isDifferentDisplay;
|
||||
import static android.window.ConfigurationHelper.shouldUpdateResources;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.IWindowToken;
|
||||
import android.app.ResourcesManager;
|
||||
@@ -31,7 +32,11 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Debug;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.WindowManager.LayoutParams.WindowType;
|
||||
import android.view.WindowManagerGlobal;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
@@ -59,10 +64,14 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
|
||||
private final ResourcesManager mResourcesManager = ResourcesManager.getInstance();
|
||||
|
||||
private IWindowManager mWms;
|
||||
|
||||
private final Configuration mConfiguration = new Configuration();
|
||||
|
||||
private boolean mShouldDumpConfigForIme;
|
||||
|
||||
private boolean mAttachToWindowContainer;
|
||||
|
||||
/**
|
||||
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
|
||||
* can only attach one {@link Context}.
|
||||
@@ -83,6 +92,88 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
&& context instanceof AbstractInputMethodService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches this {@link WindowTokenClient} to a {@link com.android.server.wm.DisplayArea}.
|
||||
*
|
||||
* @param type The window type of the {@link WindowContext}
|
||||
* @param displayId The {@link Context#getDisplayId() ID of display} to associate with
|
||||
* @param options The window context launched option
|
||||
* @return {@code true} if attaching successfully.
|
||||
*/
|
||||
public boolean attachToDisplayArea(@WindowType int type, int displayId,
|
||||
@Nullable Bundle options) {
|
||||
try {
|
||||
final Configuration configuration = getWindowManagerService()
|
||||
.attachWindowContextToDisplayArea(this, type, displayId, options);
|
||||
if (configuration == null) {
|
||||
return false;
|
||||
}
|
||||
onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */);
|
||||
mAttachToWindowContainer = true;
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches this {@link WindowTokenClient} to a {@code DisplayContent}.
|
||||
*
|
||||
* @param displayId The {@link Context#getDisplayId() ID of display} to associate with
|
||||
* @return {@code true} if attaching successfully.
|
||||
*/
|
||||
public boolean attachToDisplayContent(int displayId) {
|
||||
final IWindowManager wms = getWindowManagerService();
|
||||
// #createSystemUiContext may call this method before WindowManagerService is initialized.
|
||||
if (wms == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
final Configuration configuration = wms.attachToDisplayContent(this, displayId);
|
||||
if (configuration == null) {
|
||||
return false;
|
||||
}
|
||||
onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */);
|
||||
mAttachToWindowContainer = true;
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches this {@link WindowTokenClient} to a {@code windowToken}.
|
||||
*
|
||||
* @param windowToken the window token to associated with
|
||||
*/
|
||||
public void attachToWindowToken(IBinder windowToken) {
|
||||
try {
|
||||
getWindowManagerService().attachWindowContextToWindowToken(this, windowToken);
|
||||
mAttachToWindowContainer = true;
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/** Detaches this {@link WindowTokenClient} from associated WindowContainer if there's one. */
|
||||
public void detachFromWindowContainerIfNeeded() {
|
||||
if (!mAttachToWindowContainer) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
getWindowManagerService().detachWindowContextFromWindowContainer(this);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private IWindowManager getWindowManagerService() {
|
||||
if (mWms == null) {
|
||||
mWms = WindowManagerGlobal.getWindowManagerService();
|
||||
}
|
||||
return mWms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when {@link Configuration} updates from the server side receive.
|
||||
*
|
||||
|
||||
@@ -24,16 +24,13 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Binder;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.view.IWindowManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
@@ -59,17 +56,14 @@ import org.mockito.MockitoAnnotations;
|
||||
public class WindowContextControllerTest {
|
||||
private WindowContextController mController;
|
||||
@Mock
|
||||
private IWindowManager mMockWms;
|
||||
@Mock
|
||||
private WindowTokenClient mMockToken;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mController = new WindowContextController(mMockToken, mMockWms);
|
||||
mController = new WindowContextController(mMockToken);
|
||||
doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt(), anyBoolean());
|
||||
doReturn(new Configuration()).when(mMockWms).attachWindowContextToDisplayArea(any(),
|
||||
anyInt(), anyInt(), any());
|
||||
doReturn(true).when(mMockToken).attachToDisplayArea(anyInt(), anyInt(), any());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@@ -81,10 +75,10 @@ public class WindowContextControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetachIfNeeded_NotAttachedYet_DoNothing() throws Exception {
|
||||
public void testDetachIfNeeded_NotAttachedYet_DoNothing() {
|
||||
mController.detachIfNeeded();
|
||||
|
||||
verify(mMockWms, never()).detachWindowContextFromWindowContainer(any());
|
||||
verify(mMockToken, never()).detachFromWindowContainerIfNeeded();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,8 +87,6 @@ public class WindowContextControllerTest {
|
||||
null /* options */);
|
||||
|
||||
assertThat(mController.mAttachedToDisplayArea).isTrue();
|
||||
verify(mMockToken).onConfigurationChanged(any(), eq(DEFAULT_DISPLAY),
|
||||
eq(false) /* shouldReportConfigChange */);
|
||||
|
||||
mController.detachIfNeeded();
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ public class InputMethodMenuController {
|
||||
public Context getSettingsContext(int displayId) {
|
||||
if (mSettingsContext == null || mSettingsContext.getDisplayId() != displayId) {
|
||||
final Context systemUiContext = ActivityThread.currentActivityThread()
|
||||
.createSystemUiContext(displayId);
|
||||
.getSystemUiContext(displayId);
|
||||
final Context windowContext = systemUiContext.createWindowContext(
|
||||
WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */);
|
||||
mSettingsContext = new ContextThemeWrapper(
|
||||
|
||||
@@ -34,6 +34,7 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
|
||||
import static android.os.Build.VERSION_CODES.N;
|
||||
import static android.os.Process.SYSTEM_UID;
|
||||
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
|
||||
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
|
||||
import static android.util.RotationUtils.deltaRotation;
|
||||
@@ -61,6 +62,7 @@ import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
||||
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
|
||||
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
|
||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
|
||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
|
||||
@@ -4940,6 +4942,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
reconfigureDisplayLocked();
|
||||
onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
|
||||
mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
|
||||
// Attach the SystemUiContext to this DisplayContent the get latest configuration.
|
||||
// Note that the SystemUiContext will be removed automatically if this DisplayContent
|
||||
// is detached.
|
||||
mWmService.mWindowContextListenerController.registerWindowContainerListener(
|
||||
getDisplayUiContext().getWindowContextToken(), this, SYSTEM_UID,
|
||||
INVALID_WINDOW_TYPE, null /* options */);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -426,7 +426,7 @@ public class DisplayPolicy {
|
||||
: service.mContext.createDisplayContext(displayContent.getDisplay());
|
||||
mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
|
||||
: service.mAtmService.mSystemThread
|
||||
.createSystemUiContext(displayContent.getDisplayId());
|
||||
.getSystemUiContext(displayContent.getDisplayId());
|
||||
mDisplayContent = displayContent;
|
||||
mLock = service.getWindowManagerLock();
|
||||
|
||||
@@ -1887,7 +1887,8 @@ public class DisplayPolicy {
|
||||
// user's package info (see ContextImpl.createDisplayContext)
|
||||
final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
|
||||
uiContext.getPackageName(), null, 0, userId);
|
||||
mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
|
||||
mCurrentUserResources = ResourcesManager.getInstance().getResources(
|
||||
uiContext.getWindowContextToken(),
|
||||
pi.getResDir(),
|
||||
null /* splitResDirs */,
|
||||
pi.getOverlayDirs(),
|
||||
|
||||
@@ -2496,7 +2496,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
// starts. Instead, we expect home activities to be launched when the system is ready
|
||||
// (ActivityManagerService#systemReady).
|
||||
if (mService.isBooted() || mService.isBooting()) {
|
||||
startSystemDecorations(display.mDisplayContent);
|
||||
startSystemDecorations(display);
|
||||
}
|
||||
// Drop any cached DisplayInfos associated with this display id - the values are now
|
||||
// out of date given this display added event.
|
||||
|
||||
@@ -45,7 +45,7 @@ import java.util.Objects;
|
||||
*
|
||||
* <ul>
|
||||
* <li>When a {@link WindowContext} is created, it registers the listener via
|
||||
* {@link WindowManagerService#registerWindowContextListener(IBinder, int, int, Bundle)}
|
||||
* {@link WindowManagerService#attachWindowContextToDisplayArea(IBinder, int, int, Bundle)}
|
||||
* automatically.</li>
|
||||
* <li>When the {@link WindowContext} adds the first window to the screen via
|
||||
* {@link android.view.WindowManager#addView(View, android.view.ViewGroup.LayoutParams)},
|
||||
@@ -53,7 +53,7 @@ import java.util.Objects;
|
||||
* to corresponding {@link WindowToken} via this controller.</li>
|
||||
* <li>When the {@link WindowContext} is GCed, it unregisters the previously
|
||||
* registered listener via
|
||||
* {@link WindowManagerService#unregisterWindowContextListener(IBinder)}.
|
||||
* {@link WindowManagerService#detachWindowContextFromWindowContainer(IBinder)}.
|
||||
* {@link WindowManagerService} is also responsible for removing the
|
||||
* {@link WindowContext} created {@link WindowToken}.</li>
|
||||
* </ul>
|
||||
@@ -68,7 +68,7 @@ class WindowContextListenerController {
|
||||
|
||||
/**
|
||||
* Registers the listener to a {@code container} which is associated with
|
||||
* a {@code clientToken}, which is a {@link android.app.WindowContext} representation. If the
|
||||
* a {@code clientToken}, which is a {@link android.window.WindowContext} representation. If the
|
||||
* listener associated with {@code clientToken} hasn't been initialized yet, create one
|
||||
* {@link WindowContextListenerImpl}. Otherwise, the listener associated with
|
||||
* {@code clientToken} switches to listen to the {@code container}.
|
||||
|
||||
@@ -2700,6 +2700,9 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
@Override
|
||||
public Configuration attachWindowContextToDisplayArea(IBinder clientToken, int
|
||||
type, int displayId, Bundle options) {
|
||||
if (clientToken == null) {
|
||||
throw new IllegalArgumentException("clientToken must not be null!");
|
||||
}
|
||||
final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS,
|
||||
"attachWindowContextToDisplayArea", false /* printLog */);
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
@@ -2790,6 +2793,39 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration attachToDisplayContent(IBinder clientToken, int displayId) {
|
||||
if (clientToken == null) {
|
||||
throw new IllegalArgumentException("clientToken must not be null!");
|
||||
}
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mGlobalLock) {
|
||||
// We use "getDisplayContent" instead of "getDisplayContentOrCreate" because
|
||||
// this method may be called in DisplayPolicy's constructor and may cause
|
||||
// infinite loop. In this scenario, we early return here and switch to do the
|
||||
// registration in DisplayContent#onParentChanged at DisplayContent initialization.
|
||||
final DisplayContent dc = mRoot.getDisplayContent(displayId);
|
||||
if (dc == null) {
|
||||
if (Binder.getCallingPid() != myPid()) {
|
||||
throw new WindowManager.InvalidDisplayException("attachToDisplayContent: "
|
||||
+ "trying to attach to a non-existing display:" + displayId);
|
||||
}
|
||||
// Early return if this method is invoked from system process.
|
||||
// See above comments for more detail.
|
||||
return null;
|
||||
}
|
||||
|
||||
mWindowContextListenerController.registerWindowContainerListener(clientToken, dc,
|
||||
callingUid, INVALID_WINDOW_TYPE, null /* options */);
|
||||
return dc.getConfiguration();
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns {@code true} if this binder is a registered window token. */
|
||||
@Override
|
||||
public boolean isWindowToken(IBinder binder) {
|
||||
|
||||
@@ -29,7 +29,9 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
@@ -44,6 +46,7 @@ import android.view.WindowManagerGlobal;
|
||||
import com.android.server.inputmethod.InputMethodManagerService;
|
||||
import com.android.server.inputmethod.InputMethodMenuController;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -62,6 +65,9 @@ public class InputMethodMenuControllerTest extends WindowTestsBase {
|
||||
private InputMethodMenuController mController;
|
||||
private DualDisplayAreaGroupPolicyTest.DualDisplayContent mSecondaryDisplay;
|
||||
|
||||
private IWindowManager mIWindowManager;
|
||||
private DisplayManagerGlobal mDisplayManagerGlobal;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// Let the Display to be created with the DualDisplay policy.
|
||||
@@ -70,10 +76,12 @@ public class InputMethodMenuControllerTest extends WindowTestsBase {
|
||||
Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
|
||||
|
||||
mController = new InputMethodMenuController(mock(InputMethodManagerService.class));
|
||||
mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent
|
||||
.Builder(mAtm, 1000, 1000).build();
|
||||
|
||||
// Mock addWindowTokenWithOptions to create a test window token.
|
||||
IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
|
||||
spyOn(wms);
|
||||
mIWindowManager = WindowManagerGlobal.getWindowManagerService();
|
||||
spyOn(mIWindowManager);
|
||||
doAnswer(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
IBinder clientToken = (IBinder) args[0];
|
||||
@@ -83,19 +91,24 @@ public class InputMethodMenuControllerTest extends WindowTestsBase {
|
||||
dc.getImeContainer(), 1000 /* ownerUid */, TYPE_INPUT_METHOD_DIALOG,
|
||||
null /* options */);
|
||||
return dc.getImeContainer().getConfiguration();
|
||||
}).when(wms).attachWindowContextToDisplayArea(any(), eq(TYPE_INPUT_METHOD_DIALOG),
|
||||
anyInt(), any());
|
||||
|
||||
mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent
|
||||
.Builder(mAtm, 1000, 1000).build();
|
||||
|
||||
// Mock DisplayManagerGlobal to return test display when obtaining Display instance.
|
||||
}).when(mIWindowManager).attachWindowContextToDisplayArea(any(),
|
||||
eq(TYPE_INPUT_METHOD_DIALOG), anyInt(), any());
|
||||
mDisplayManagerGlobal = DisplayManagerGlobal.getInstance();
|
||||
spyOn(mDisplayManagerGlobal);
|
||||
final int displayId = mSecondaryDisplay.getDisplayId();
|
||||
final Display display = mSecondaryDisplay.getDisplay();
|
||||
DisplayManagerGlobal displayManagerGlobal = DisplayManagerGlobal.getInstance();
|
||||
spyOn(displayManagerGlobal);
|
||||
doReturn(display).when(displayManagerGlobal).getCompatibleDisplay(eq(displayId),
|
||||
doReturn(display).when(mDisplayManagerGlobal).getCompatibleDisplay(eq(displayId),
|
||||
(Resources) any());
|
||||
Context systemUiContext = ActivityThread.currentActivityThread()
|
||||
.getSystemUiContext(displayId);
|
||||
spyOn(systemUiContext);
|
||||
doReturn(display).when(systemUiContext).getDisplay();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
reset(mIWindowManager);
|
||||
reset(mDisplayManagerGlobal);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user