Merge "Send DA's config directly when attaching to DA" into sc-v2-dev am: 427a66fa71
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15047821 Change-Id: I19901472ca16fbe33cf1c4f1abaa7ab2dab2922e
This commit is contained in:
@@ -2721,10 +2721,13 @@ class ContextImpl extends Context {
|
|||||||
// need to override their display in ResourcesManager.
|
// need to override their display in ResourcesManager.
|
||||||
baseContext.mForceDisplayOverrideInResources = false;
|
baseContext.mForceDisplayOverrideInResources = false;
|
||||||
baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
|
baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
|
||||||
baseContext.mDisplay = display;
|
|
||||||
|
|
||||||
final Resources windowContextResources = createWindowContextResources(baseContext);
|
final Resources windowContextResources = createWindowContextResources(baseContext);
|
||||||
baseContext.setResources(windowContextResources);
|
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);
|
||||||
|
|
||||||
return baseContext;
|
return baseContext;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -814,9 +814,10 @@ interface IWindowManager
|
|||||||
* @param displayId The display associated with the window context
|
* @param displayId The display associated with the window context
|
||||||
* @param options A bundle used to pass window-related options and choose the right DisplayArea
|
* @param options A bundle used to pass window-related options and choose the right DisplayArea
|
||||||
*
|
*
|
||||||
* @return {@code true} if the WindowContext is attached to the DisplayArea successfully.
|
* @return the DisplayArea's {@link android.app.res.Configuration} if the WindowContext is
|
||||||
|
* attached to the DisplayArea successfully. {@code null}, otherwise.
|
||||||
*/
|
*/
|
||||||
boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
|
Configuration attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
|
||||||
in Bundle options);
|
in Bundle options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ 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.os.IBinder;
|
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -73,7 +72,7 @@ public class WindowContext extends ContextWrapper {
|
|||||||
mType = type;
|
mType = type;
|
||||||
mOptions = options;
|
mOptions = options;
|
||||||
mWindowManager = createWindowContextWindowManager(this);
|
mWindowManager = createWindowContextWindowManager(this);
|
||||||
IBinder token = getWindowContextToken();
|
WindowTokenClient token = (WindowTokenClient) getWindowContextToken();
|
||||||
mController = new WindowContextController(token);
|
mController = new WindowContextController(token);
|
||||||
|
|
||||||
Reference.reachabilityFence(this);
|
Reference.reachabilityFence(this);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package android.window;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -46,7 +47,7 @@ public class WindowContextController {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public boolean mAttachedToDisplayArea;
|
public boolean mAttachedToDisplayArea;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final IBinder mToken;
|
private final WindowTokenClient mToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Window Context Controller constructor
|
* Window Context Controller constructor
|
||||||
@@ -54,14 +55,13 @@ public class WindowContextController {
|
|||||||
* @param token The token used to attach to a window manager node. It is usually from
|
* @param token The token used to attach to a window manager node. It is usually from
|
||||||
* {@link Context#getWindowContextToken()}.
|
* {@link Context#getWindowContextToken()}.
|
||||||
*/
|
*/
|
||||||
public WindowContextController(@NonNull IBinder token) {
|
public WindowContextController(@NonNull WindowTokenClient token) {
|
||||||
mToken = token;
|
this(token, WindowManagerGlobal.getWindowManagerService());
|
||||||
mWms = WindowManagerGlobal.getWindowManagerService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used for test only. DO NOT USE it in production code. */
|
/** Used for test only. DO NOT USE it in production code. */
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) {
|
public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) {
|
||||||
mToken = token;
|
mToken = token;
|
||||||
mWms = mockWms;
|
mWms = mockWms;
|
||||||
}
|
}
|
||||||
@@ -81,8 +81,15 @@ public class WindowContextController {
|
|||||||
+ "a DisplayArea once.");
|
+ "a DisplayArea once.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
mAttachedToDisplayArea = mWms.attachWindowContextToDisplayArea(mToken, type, displayId,
|
final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type,
|
||||||
options);
|
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) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,12 @@ import android.content.res.Configuration;
|
|||||||
import android.inputmethodservice.AbstractInputMethodService;
|
import android.inputmethodservice.AbstractInputMethodService;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Debug;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,7 +68,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
|||||||
* can only attach one {@link Context}.
|
* can only attach one {@link Context}.
|
||||||
* <p>This method must be called before invoking
|
* <p>This method must be called before invoking
|
||||||
* {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int,
|
* {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int,
|
||||||
* Bundle, boolean)}.<p/>
|
* Bundle)}.<p/>
|
||||||
*
|
*
|
||||||
* @param context context to be attached
|
* @param context context to be attached
|
||||||
* @throws IllegalStateException if attached context has already existed.
|
* @throws IllegalStateException if attached context has already existed.
|
||||||
@@ -80,8 +83,26 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
|||||||
&& context instanceof AbstractInputMethodService;
|
&& context instanceof AbstractInputMethodService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when {@link Configuration} updates from the server side receive.
|
||||||
|
*
|
||||||
|
* @param newConfig the updated {@link Configuration}
|
||||||
|
* @param newDisplayId the updated {@link android.view.Display} ID
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
|
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
|
||||||
|
onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when {@link Configuration} updates from the server side receive.
|
||||||
|
*
|
||||||
|
* Similar to {@link #onConfigurationChanged(Configuration, int)}, but adds a flag to control
|
||||||
|
* whether to dispatch configuration update or not.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
||||||
|
public void onConfigurationChanged(Configuration newConfig, int newDisplayId,
|
||||||
|
boolean shouldReportConfigChange) {
|
||||||
final Context context = mContextRef.get();
|
final Context context = mContextRef.get();
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
return;
|
return;
|
||||||
@@ -102,9 +123,10 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
|||||||
// TODO(ag/9789103): update resource manager logic to track non-activity tokens
|
// TODO(ag/9789103): update resource manager logic to track non-activity tokens
|
||||||
mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId);
|
mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId);
|
||||||
|
|
||||||
if (context instanceof WindowContext) {
|
if (shouldReportConfigChange && context instanceof WindowContext) {
|
||||||
|
final WindowContext windowContext = (WindowContext) context;
|
||||||
ActivityThread.currentActivityThread().getHandler().post(
|
ActivityThread.currentActivityThread().getHandler().post(
|
||||||
() -> ((WindowContext) context).dispatchConfigurationChanged(newConfig));
|
() -> windowContext.dispatchConfigurationChanged(newConfig));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch onConfigurationChanged only if there's a significant public change to
|
// Dispatch onConfigurationChanged only if there's a significant public change to
|
||||||
@@ -115,17 +137,24 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
|||||||
? new SizeConfigurationBuckets(sizeConfigurations) : null;
|
? new SizeConfigurationBuckets(sizeConfigurations) : null;
|
||||||
final int diff = diffPublicWithSizeBuckets(mConfiguration, newConfig, buckets);
|
final int diff = diffPublicWithSizeBuckets(mConfiguration, newConfig, buckets);
|
||||||
|
|
||||||
if (context instanceof WindowProviderService && diff != 0) {
|
if (shouldReportConfigChange && diff != 0
|
||||||
ActivityThread.currentActivityThread().getHandler().post(() ->
|
&& context instanceof WindowProviderService) {
|
||||||
((WindowProviderService) context).onConfigurationChanged(newConfig));
|
final WindowProviderService windowProviderService = (WindowProviderService) context;
|
||||||
|
ActivityThread.currentActivityThread().getHandler().post(
|
||||||
|
() -> windowProviderService.onConfigurationChanged(newConfig));
|
||||||
}
|
}
|
||||||
freeTextLayoutCachesIfNeeded(diff);
|
freeTextLayoutCachesIfNeeded(diff);
|
||||||
if (diff == 0 && mShouldDumpConfigForIme) {
|
if (mShouldDumpConfigForIme) {
|
||||||
Log.d(TAG, "Configuration not dispatch to IME because configuration has no "
|
if (!shouldReportConfigChange) {
|
||||||
+ " public difference with updated config. "
|
Log.d(TAG, "Only apply configuration update to Resources because "
|
||||||
+ " Current config=" + context.getResources().getConfiguration()
|
+ "shouldReportConfigChange is false.\n" + Debug.getCallers(5));
|
||||||
+ ", reported config=" + mConfiguration
|
} else if (diff == 0) {
|
||||||
+ ", updated config=" + newConfig);
|
Log.d(TAG, "Configuration not dispatch to IME because configuration has no "
|
||||||
|
+ " public difference with updated config. "
|
||||||
|
+ " Current config=" + context.getResources().getConfiguration()
|
||||||
|
+ ", reported config=" + mConfiguration
|
||||||
|
+ ", updated config=" + newConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mConfiguration.setTo(newConfig);
|
mConfiguration.setTo(newConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,15 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
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.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.content.res.Configuration;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.view.IWindowManager;
|
import android.view.IWindowManager;
|
||||||
@@ -38,6 +41,8 @@ import androidx.test.runner.AndroidJUnit4;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link WindowContextController}
|
* Tests for {@link WindowContextController}
|
||||||
@@ -53,15 +58,18 @@ import org.junit.runner.RunWith;
|
|||||||
@Presubmit
|
@Presubmit
|
||||||
public class WindowContextControllerTest {
|
public class WindowContextControllerTest {
|
||||||
private WindowContextController mController;
|
private WindowContextController mController;
|
||||||
|
@Mock
|
||||||
private IWindowManager mMockWms;
|
private IWindowManager mMockWms;
|
||||||
|
@Mock
|
||||||
|
private WindowTokenClient mMockToken;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mMockWms = mock(IWindowManager.class);
|
MockitoAnnotations.initMocks(this);
|
||||||
mController = new WindowContextController(new Binder(), mMockWms);
|
mController = new WindowContextController(mMockToken, mMockWms);
|
||||||
|
doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt(), anyBoolean());
|
||||||
doReturn(true).when(mMockWms).attachWindowContextToDisplayArea(any(), anyInt(),
|
doReturn(new Configuration()).when(mMockWms).attachWindowContextToDisplayArea(any(),
|
||||||
anyInt(), any());
|
anyInt(), anyInt(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
@@ -85,6 +93,8 @@ public class WindowContextControllerTest {
|
|||||||
null /* options */);
|
null /* options */);
|
||||||
|
|
||||||
assertThat(mController.mAttachedToDisplayArea).isTrue();
|
assertThat(mController.mAttachedToDisplayArea).isTrue();
|
||||||
|
verify(mMockToken).onConfigurationChanged(any(), eq(DEFAULT_DISPLAY),
|
||||||
|
eq(false) /* shouldReportConfigChange */);
|
||||||
|
|
||||||
mController.detachIfNeeded();
|
mController.detachIfNeeded();
|
||||||
|
|
||||||
|
|||||||
@@ -2720,8 +2720,8 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
|
public Configuration attachWindowContextToDisplayArea(IBinder clientToken, int
|
||||||
Bundle options) {
|
type, int displayId, Bundle options) {
|
||||||
final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS,
|
final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS,
|
||||||
"attachWindowContextToDisplayArea", false /* printLog */);
|
"attachWindowContextToDisplayArea", false /* printLog */);
|
||||||
final int callingUid = Binder.getCallingUid();
|
final int callingUid = Binder.getCallingUid();
|
||||||
@@ -2732,15 +2732,17 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
if (dc == null) {
|
if (dc == null) {
|
||||||
ProtoLog.w(WM_ERROR, "attachWindowContextToDisplayArea: trying to attach"
|
ProtoLog.w(WM_ERROR, "attachWindowContextToDisplayArea: trying to attach"
|
||||||
+ " to a non-existing display:%d", displayId);
|
+ " to a non-existing display:%d", displayId);
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
// TODO(b/155340867): Investigate if we still need roundedCornerOverlay after
|
// TODO(b/155340867): Investigate if we still need roundedCornerOverlay after
|
||||||
// the feature b/155340867 is completed.
|
// the feature b/155340867 is completed.
|
||||||
final DisplayArea da = dc.findAreaForWindowType(type, options,
|
final DisplayArea da = dc.findAreaForWindowType(type, options,
|
||||||
callerCanManageAppTokens, false /* roundedCornerOverlay */);
|
callerCanManageAppTokens, false /* roundedCornerOverlay */);
|
||||||
|
// TODO(b/190019118): Avoid to send onConfigurationChanged because it has been done
|
||||||
|
// in return value of attachWindowContextToDisplayArea.
|
||||||
mWindowContextListenerController.registerWindowContainerListener(clientToken, da,
|
mWindowContextListenerController.registerWindowContainerListener(clientToken, da,
|
||||||
callingUid, type, options);
|
callingUid, type, options);
|
||||||
return true;
|
return da.getConfiguration();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(origId);
|
Binder.restoreCallingIdentity(origId);
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public class InputMethodMenuControllerTest extends WindowTestsBase {
|
|||||||
mWm.mWindowContextListenerController.registerWindowContainerListener(clientToken,
|
mWm.mWindowContextListenerController.registerWindowContainerListener(clientToken,
|
||||||
dc.getImeContainer(), 1000 /* ownerUid */, TYPE_INPUT_METHOD_DIALOG,
|
dc.getImeContainer(), 1000 /* ownerUid */, TYPE_INPUT_METHOD_DIALOG,
|
||||||
null /* options */);
|
null /* options */);
|
||||||
return true;
|
return dc.getImeContainer().getConfiguration();
|
||||||
}).when(wms).attachWindowContextToDisplayArea(any(), eq(TYPE_INPUT_METHOD_DIALOG),
|
}).when(wms).attachWindowContextToDisplayArea(any(), eq(TYPE_INPUT_METHOD_DIALOG),
|
||||||
anyInt(), any());
|
anyInt(), any());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user