Override (un)registerComponentCallbacks for ContextWrapper
Bug: 193247900 Test: WindowContextTest Test: ContextWrapperTest Change-Id: Ia070b12eea5631d70a96d6e41d03ab08f6b44caa
This commit is contained in:
@@ -24,6 +24,9 @@ import android.annotation.TestApi;
|
||||
import android.annotation.UiContext;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.IServiceConnection;
|
||||
import android.app.compat.CompatChanges;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.EnabledSince;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -47,12 +50,16 @@ import android.view.DisplayAdjustments;
|
||||
import android.view.WindowManager.LayoutParams.WindowType;
|
||||
import android.view.autofill.AutofillManager.AutofillClient;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -66,6 +73,31 @@ public class ContextWrapper extends Context {
|
||||
@UnsupportedAppUsage
|
||||
Context mBase;
|
||||
|
||||
/**
|
||||
* After {@link Build.VERSION_CODES#TIRAMISU},
|
||||
* {@link #registerComponentCallbacks(ComponentCallbacks)} will delegate to
|
||||
* {@link #getBaseContext()} instead of {@link #getApplicationContext()}.
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
|
||||
@VisibleForTesting
|
||||
static final long COMPONENT_CALLBACK_ON_WRAPPER = 193247900L;
|
||||
|
||||
/**
|
||||
* A list to store {@link ComponentCallbacks} which
|
||||
* passes to {@link #registerComponentCallbacks(ComponentCallbacks)} before
|
||||
* {@link #attachBaseContext(Context)}.
|
||||
* It is to provide compatibility behavior for Application targeted prior to
|
||||
* {@link Build.VERSION_CODES#TIRAMISU}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
@VisibleForTesting
|
||||
public List<ComponentCallbacks> mCallbacksRegisteredToSuper;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
public ContextWrapper(Context base) {
|
||||
mBase = base;
|
||||
}
|
||||
@@ -1301,4 +1333,77 @@ public class ContextWrapper extends Context {
|
||||
}
|
||||
return mBase.isConfigurationContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new {@link ComponentCallbacks} to the base application of the
|
||||
* Context, which will be called at the same times as the ComponentCallbacks
|
||||
* methods of activities and other components are called. Note that you
|
||||
* <em>must</em> be sure to use {@link #unregisterComponentCallbacks} when
|
||||
* appropriate in the future; this will not be removed for you.
|
||||
* <p>
|
||||
* After {@link Build.VERSION_CODES#TIRAMISU}, the {@link ComponentCallbacks} will be registered
|
||||
* to {@link #getBaseContext() the base Context}, and can be only used after
|
||||
* {@link #attachBaseContext(Context)}. Users can still call to
|
||||
* {@code getApplicationContext().registerComponentCallbacks(ComponentCallbacks)} to add
|
||||
* {@link ComponentCallbacks} to the base application.
|
||||
*
|
||||
* @param callback The interface to call. This can be either a
|
||||
* {@link ComponentCallbacks} or {@link ComponentCallbacks2} interface.
|
||||
* @throws IllegalStateException if this method calls before {@link #attachBaseContext(Context)}
|
||||
*/
|
||||
@Override
|
||||
public void registerComponentCallbacks(ComponentCallbacks callback) {
|
||||
if (mBase != null) {
|
||||
mBase.registerComponentCallbacks(callback);
|
||||
} else if (!CompatChanges.isChangeEnabled(COMPONENT_CALLBACK_ON_WRAPPER)) {
|
||||
super.registerComponentCallbacks(callback);
|
||||
synchronized (mLock) {
|
||||
// Also register ComponentCallbacks to ContextWrapper, so we can find the correct
|
||||
// Context to unregister it for compatibility.
|
||||
if (mCallbacksRegisteredToSuper == null) {
|
||||
mCallbacksRegisteredToSuper = new ArrayList<>();
|
||||
}
|
||||
mCallbacksRegisteredToSuper.add(callback);
|
||||
}
|
||||
} else {
|
||||
// Throw exception for Application targeting T+
|
||||
throw new IllegalStateException("ComponentCallbacks must be registered after "
|
||||
+ "this ContextWrapper is attached to a base Context.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a {@link ComponentCallbacks} object that was previously registered
|
||||
* with {@link #registerComponentCallbacks(ComponentCallbacks)}.
|
||||
* <p>
|
||||
* After {@link Build.VERSION_CODES#TIRAMISU}, the {@link ComponentCallbacks} will be
|
||||
* unregistered to {@link #getBaseContext() the base Context}, and can be only used after
|
||||
* {@link #attachBaseContext(Context)}
|
||||
* </p>
|
||||
*
|
||||
* @param callback The interface to call. This can be either a
|
||||
* {@link ComponentCallbacks} or {@link ComponentCallbacks2} interface.
|
||||
* @throws IllegalStateException if this method calls before {@link #attachBaseContext(Context)}
|
||||
*/
|
||||
@Override
|
||||
public void unregisterComponentCallbacks(ComponentCallbacks callback) {
|
||||
// It usually means the ComponentCallbacks is registered before this ContextWrapper attaches
|
||||
// to a base Context and Application is targeting prior to S-v2. We should unregister the
|
||||
// ComponentCallbacks to the Application Context instead to prevent leak.
|
||||
synchronized (mLock) {
|
||||
if (mCallbacksRegisteredToSuper != null
|
||||
&& mCallbacksRegisteredToSuper.contains(callback)) {
|
||||
super.unregisterComponentCallbacks(callback);
|
||||
mCallbacksRegisteredToSuper.remove(callback);
|
||||
} else if (mBase != null) {
|
||||
mBase.unregisterComponentCallbacks(callback);
|
||||
} else if (CompatChanges.isChangeEnabled(COMPONENT_CALLBACK_ON_WRAPPER)) {
|
||||
// Throw exception for Application that is targeting S-v2+
|
||||
throw new IllegalStateException("ComponentCallbacks must be unregistered after "
|
||||
+ "this ContextWrapper is attached to a base Context.");
|
||||
}
|
||||
}
|
||||
// Do nothing if the callback hasn't been registered to Application Context by
|
||||
// super.unregisterComponentCallbacks() for Application that is targeting prior to T.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
},
|
||||
{
|
||||
"include-filter": "android.content.ComponentCallbacksControllerTest"
|
||||
},
|
||||
{
|
||||
"include-filter": "android.content.ContextWrapperTest"
|
||||
}
|
||||
],
|
||||
"file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java", "(/|^)ComponentCallbacksController.java"]
|
||||
|
||||
@@ -17,6 +17,8 @@ package android.window;
|
||||
|
||||
import static android.view.WindowManagerImpl.createWindowContextWindowManager;
|
||||
|
||||
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UiContext;
|
||||
@@ -135,7 +137,8 @@ public class WindowContext extends ContextWrapper implements WindowProvider {
|
||||
}
|
||||
|
||||
/** Dispatch {@link Configuration} to each {@link ComponentCallbacks}. */
|
||||
void dispatchConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
@VisibleForTesting(visibility = PACKAGE)
|
||||
public void dispatchConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
mCallbacksController.dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,25 +116,4 @@ public class ComponentCallbacksControllerTest {
|
||||
@Override
|
||||
public void onLowMemory() {}
|
||||
}
|
||||
|
||||
private static class TestComponentCallbacks2 implements ComponentCallbacks2 {
|
||||
private Configuration mConfiguration;
|
||||
private boolean mLowMemoryCalled;
|
||||
private int mLevel;
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
mConfiguration = newConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
mLowMemoryCalled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
mLevel = level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
158
core/tests/coretests/src/android/content/ContextWrapperTest.java
Normal file
158
core/tests/coretests/src/android/content/ContextWrapperTest.java
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.content;
|
||||
|
||||
import static android.content.ContextWrapper.COMPONENT_CALLBACK_ON_WRAPPER;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.WindowConfiguration;
|
||||
import android.compat.testing.PlatformCompatChangeRule;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.view.Display;
|
||||
import android.window.WindowContext;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
|
||||
/**
|
||||
* Build/Install/Run:
|
||||
* atest FrameworksCoreTests:ContextWrapperTest
|
||||
*/
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ContextWrapperTest {
|
||||
@Rule
|
||||
public TestRule compatChangeRule = new PlatformCompatChangeRule();
|
||||
|
||||
/**
|
||||
* Before {@link android.os.Build.VERSION_CODES#TIRAMISU}, {@link ContextWrapper} must
|
||||
* register {@link ComponentCallbacks} to {@link ContextWrapper#getApplicationContext} before
|
||||
* {@link ContextWrapper#attachBaseContext(Context)}.
|
||||
*/
|
||||
@DisableCompatChanges(COMPONENT_CALLBACK_ON_WRAPPER)
|
||||
@Test
|
||||
public void testRegisterComponentCallbacksWithoutBaseContextBeforeT() {
|
||||
final ContextWrapper wrapper = new TestContextWrapper(null /* base */);
|
||||
final ComponentCallbacks callbacks = new TestComponentCallbacks2();
|
||||
|
||||
// It should be no-op if unregister a ComponentCallbacks without registration.
|
||||
wrapper.unregisterComponentCallbacks(callbacks);
|
||||
|
||||
wrapper.registerComponentCallbacks(callbacks);
|
||||
|
||||
assertThat(wrapper.mCallbacksRegisteredToSuper.size()).isEqualTo(1);
|
||||
assertThat(wrapper.mCallbacksRegisteredToSuper.get(0)).isEqualTo(callbacks);
|
||||
|
||||
wrapper.unregisterComponentCallbacks(callbacks);
|
||||
|
||||
assertThat(wrapper.mCallbacksRegisteredToSuper.isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* After {@link android.os.Build.VERSION_CODES#TIRAMISU}, {@link ContextWrapper} must
|
||||
* throw {@link IllegalStateException} before {@link ContextWrapper#attachBaseContext(Context)}.
|
||||
*/
|
||||
@Test
|
||||
public void testRegisterComponentCallbacksWithoutBaseContextAfterT() {
|
||||
final ContextWrapper wrapper = new TestContextWrapper(null /* base */);
|
||||
final ComponentCallbacks callbacks = new TestComponentCallbacks2();
|
||||
|
||||
try {
|
||||
wrapper.unregisterComponentCallbacks(callbacks);
|
||||
fail("ContextWrapper#unregisterComponentCallbacks must throw Exception before"
|
||||
+ " ContextWrapper#attachToBaseContext.");
|
||||
} catch (IllegalStateException ignored) {
|
||||
// It is expected to throw IllegalStateException.
|
||||
}
|
||||
|
||||
try {
|
||||
wrapper.registerComponentCallbacks(callbacks);
|
||||
fail("ContextWrapper#registerComponentCallbacks must throw Exception before"
|
||||
+ " ContextWrapper#attachToBaseContext.");
|
||||
} catch (IllegalStateException ignored) {
|
||||
// It is expected to throw IllegalStateException.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ContextWrapper#registerComponentCallbacks(ComponentCallbacks)} must delegate to its
|
||||
* {@link ContextWrapper#getBaseContext()}, so does
|
||||
* {@link ContextWrapper#unregisterComponentCallbacks(ComponentCallbacks)}.
|
||||
*/
|
||||
@Test
|
||||
public void testRegisterComponentCallbacks() {
|
||||
final Context appContext = ApplicationProvider.getApplicationContext();
|
||||
final Display display = appContext.getSystemService(DisplayManager.class)
|
||||
.getDisplay(DEFAULT_DISPLAY);
|
||||
final WindowContext windowContext = (WindowContext) appContext.createWindowContext(display,
|
||||
TYPE_APPLICATION_OVERLAY, null /* options */);
|
||||
final ContextWrapper wrapper = new ContextWrapper(windowContext);
|
||||
final TestComponentCallbacks2 callbacks = new TestComponentCallbacks2();
|
||||
|
||||
wrapper.registerComponentCallbacks(callbacks);
|
||||
|
||||
assertThat(wrapper.mCallbacksRegisteredToSuper).isNull();
|
||||
|
||||
final Configuration dispatchedConfig = new Configuration();
|
||||
dispatchedConfig.fontScale = 1.2f;
|
||||
dispatchedConfig.windowConfiguration.setWindowingMode(
|
||||
WindowConfiguration.WINDOWING_MODE_FREEFORM);
|
||||
dispatchedConfig.windowConfiguration.setBounds(new Rect(0, 0, 100, 100));
|
||||
windowContext.dispatchConfigurationChanged(dispatchedConfig);
|
||||
|
||||
assertThat(callbacks.mConfiguration).isEqualTo(dispatchedConfig);
|
||||
}
|
||||
|
||||
private static class TestContextWrapper extends ContextWrapper {
|
||||
TestContextWrapper(Context base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getApplicationContext() {
|
||||
// The default implementation of ContextWrapper#getApplicationContext is to delegate
|
||||
// to the base Context, and it leads to NPE if #registerComponentCallbacks is called
|
||||
// directly before attach to base Context.
|
||||
// We call to ApplicationProvider#getApplicationContext to prevent NPE because
|
||||
// developers may have its implementation to prevent NPE without attaching base Context.
|
||||
final Context baseContext = getBaseContext();
|
||||
if (baseContext == null) {
|
||||
return ApplicationProvider.getApplicationContext();
|
||||
} else {
|
||||
return super.getApplicationContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.content;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
class TestComponentCallbacks2 implements ComponentCallbacks2 {
|
||||
android.content.res.Configuration mConfiguration;
|
||||
boolean mLowMemoryCalled;
|
||||
int mLevel;
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
mConfiguration = newConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
mLowMemoryCalled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
mLevel = level;
|
||||
}
|
||||
}
|
||||
@@ -21,16 +21,25 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.EmptyActivity;
|
||||
import android.app.Instrumentation;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.ComponentCallbacks;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
@@ -43,6 +52,7 @@ import android.view.WindowManager.LayoutParams.WindowType;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.view.WindowManagerImpl;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
@@ -79,6 +89,8 @@ public class WindowContextTest {
|
||||
private final WindowContext mWindowContext = createWindowContext();
|
||||
private final IWindowManager mWms = WindowManagerGlobal.getWindowManagerService();
|
||||
|
||||
private static final int TIMEOUT_IN_SECONDS = 4;
|
||||
|
||||
@Test
|
||||
public void testCreateWindowContextWindowManagerAttachClientToken() {
|
||||
final WindowManager windowContextWm = WindowManagerImpl
|
||||
@@ -131,7 +143,7 @@ public class WindowContextTest {
|
||||
});
|
||||
|
||||
|
||||
assertTrue(latch.await(4, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS));
|
||||
|
||||
|
||||
// Verify that the window token of the window context is created after first addView().
|
||||
@@ -234,7 +246,7 @@ public class WindowContextTest {
|
||||
// Add the parent window
|
||||
mInstrumentation.runOnMainSync(() -> wm.addView(parentWindow, params));
|
||||
|
||||
assertTrue(listener.mLatch.await(4, TimeUnit.SECONDS));
|
||||
assertTrue(listener.mLatch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS));
|
||||
|
||||
final WindowManager.LayoutParams subWindowAttrs =
|
||||
new WindowManager.LayoutParams(TYPE_APPLICATION_ATTACHED_DIALOG);
|
||||
@@ -251,6 +263,63 @@ public class WindowContextTest {
|
||||
null /* theme */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterComponentCallbacks() {
|
||||
final WindowContext windowContext = createWindowContext();
|
||||
final ConfigurationListener listener = new ConfigurationListener();
|
||||
|
||||
windowContext.registerComponentCallbacks(listener);
|
||||
|
||||
try {
|
||||
final Configuration config = new Configuration();
|
||||
config.windowConfiguration.setWindowingMode(
|
||||
WindowConfiguration.WINDOWING_MODE_FREEFORM);
|
||||
config.windowConfiguration.setBounds(new Rect(0, 0, 100, 100));
|
||||
|
||||
windowContext.dispatchConfigurationChanged(config);
|
||||
|
||||
try {
|
||||
assertWithMessage("Waiting for onConfigurationChanged timeout.")
|
||||
.that(listener.mLatch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)).isTrue();
|
||||
} catch (InterruptedException e) {
|
||||
fail("Waiting for configuration changed failed because of " + e);
|
||||
}
|
||||
|
||||
assertThat(listener.mConfiguration).isEqualTo(config);
|
||||
} finally {
|
||||
windowContext.unregisterComponentCallbacks(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterComponentCallbacksOnWindowContextWrapper() {
|
||||
final WindowContext windowContext = createWindowContext();
|
||||
final Context wrapper = new ContextWrapper(windowContext);
|
||||
final ConfigurationListener listener = new ConfigurationListener();
|
||||
|
||||
wrapper.registerComponentCallbacks(listener);
|
||||
|
||||
try {
|
||||
final Configuration config = new Configuration();
|
||||
config.windowConfiguration.setWindowingMode(
|
||||
WindowConfiguration.WINDOWING_MODE_FREEFORM);
|
||||
config.windowConfiguration.setBounds(new Rect(0, 0, 100, 100));
|
||||
|
||||
windowContext.dispatchConfigurationChanged(config);
|
||||
|
||||
try {
|
||||
assertWithMessage("Waiting for onConfigurationChanged timeout.")
|
||||
.that(listener.mLatch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)).isTrue();
|
||||
} catch (InterruptedException e) {
|
||||
fail("Waiting for configuration changed failed because of " + e);
|
||||
}
|
||||
|
||||
assertThat(listener.mConfiguration).isEqualTo(config);
|
||||
} finally {
|
||||
wrapper.unregisterComponentCallbacks(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private WindowContext createWindowContext() {
|
||||
return createWindowContext(TYPE_APPLICATION_OVERLAY);
|
||||
}
|
||||
@@ -262,6 +331,20 @@ public class WindowContextTest {
|
||||
return (WindowContext) instContext.createWindowContext(display, type, null /* options */);
|
||||
}
|
||||
|
||||
private static class ConfigurationListener implements ComponentCallbacks {
|
||||
private Configuration mConfiguration;
|
||||
private CountDownLatch mLatch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
mConfiguration = newConfig;
|
||||
mLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {}
|
||||
}
|
||||
|
||||
private static class AttachStateListener implements View.OnAttachStateChangeListener {
|
||||
final CountDownLatch mLatch = new CountDownLatch(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user