Merge "Enable to add ComponentCallbacks to Activity"
This commit is contained in:
@@ -47,7 +47,9 @@ import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.EnabledSince;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ComponentCallbacks;
|
||||
import android.content.ComponentCallbacks2;
|
||||
import android.content.ComponentCallbacksController;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -982,6 +984,8 @@ public class Activity extends ContextThemeWrapper
|
||||
@Nullable
|
||||
private DumpableContainerImpl mDumpableContainer;
|
||||
|
||||
private ComponentCallbacksController mCallbacksController;
|
||||
|
||||
private final WindowControllerCallback mWindowControllerCallback =
|
||||
new WindowControllerCallback() {
|
||||
/**
|
||||
@@ -1323,6 +1327,28 @@ public class Activity extends ContextThemeWrapper
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerComponentCallbacks(ComponentCallbacks callback) {
|
||||
if (CompatChanges.isChangeEnabled(OVERRIDABLE_COMPONENT_CALLBACKS)
|
||||
&& mCallbacksController == null) {
|
||||
mCallbacksController = new ComponentCallbacksController();
|
||||
}
|
||||
if (mCallbacksController != null) {
|
||||
mCallbacksController.registerCallbacks(callback);
|
||||
} else {
|
||||
super.registerComponentCallbacks(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterComponentCallbacks(ComponentCallbacks callback) {
|
||||
if (mCallbacksController != null) {
|
||||
mCallbacksController.unregisterCallbacks(callback);
|
||||
} else {
|
||||
super.unregisterComponentCallbacks(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchActivityPreCreated(@Nullable Bundle savedInstanceState) {
|
||||
getApplication().dispatchActivityPreCreated(this, savedInstanceState);
|
||||
Object[] callbacks = collectActivityLifecycleCallbacks();
|
||||
@@ -2668,10 +2694,12 @@ public class Activity extends ContextThemeWrapper
|
||||
if (mUiTranslationController != null) {
|
||||
mUiTranslationController.onActivityDestroyed();
|
||||
}
|
||||
|
||||
if (mDefaultBackCallback != null) {
|
||||
getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback);
|
||||
}
|
||||
if (mCallbacksController != null) {
|
||||
mCallbacksController.clearCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2991,6 +3019,9 @@ public class Activity extends ContextThemeWrapper
|
||||
}
|
||||
|
||||
dispatchActivityConfigurationChanged();
|
||||
if (mCallbacksController != null) {
|
||||
mCallbacksController.dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3162,12 +3193,18 @@ public class Activity extends ContextThemeWrapper
|
||||
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onLowMemory " + this);
|
||||
mCalled = true;
|
||||
mFragments.dispatchLowMemory();
|
||||
if (mCallbacksController != null) {
|
||||
mCallbacksController.dispatchLowMemory();
|
||||
}
|
||||
}
|
||||
|
||||
public void onTrimMemory(int level) {
|
||||
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onTrimMemory " + this + ": " + level);
|
||||
mCalled = true;
|
||||
mFragments.dispatchTrimMemory(level);
|
||||
if (mCallbacksController != null) {
|
||||
mCallbacksController.dispatchTrimMemory(level);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.annotation.SystemApi;
|
||||
import android.annotation.TestApi;
|
||||
import android.annotation.UiContext;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.BroadcastOptions;
|
||||
import android.app.GameManager;
|
||||
@@ -45,6 +46,8 @@ import android.app.VrManager;
|
||||
import android.app.ambientcontext.AmbientContextManager;
|
||||
import android.app.people.PeopleManager;
|
||||
import android.app.time.TimeManager;
|
||||
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;
|
||||
@@ -85,6 +88,7 @@ import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
|
||||
import android.view.textclassifier.TextClassificationManager;
|
||||
import android.window.WindowContext;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.compat.IPlatformCompat;
|
||||
import com.android.internal.compat.IPlatformCompatNative;
|
||||
|
||||
@@ -111,6 +115,19 @@ import java.util.function.Consumer;
|
||||
* broadcasting and receiving intents, etc.
|
||||
*/
|
||||
public abstract class Context {
|
||||
/**
|
||||
* After {@link Build.VERSION_CODES#TIRAMISU},
|
||||
* {@link #registerComponentCallbacks(ComponentCallbacks)} will add a {@link ComponentCallbacks}
|
||||
* to {@link Activity} or {@link ContextWrapper#getBaseContext()} instead of always adding to
|
||||
* {@link #getApplicationContext()}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
|
||||
@VisibleForTesting
|
||||
public static final long OVERRIDABLE_COMPONENT_CALLBACKS = 193247900L;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "MODE_" }, value = {
|
||||
MODE_PRIVATE,
|
||||
|
||||
@@ -25,8 +25,6 @@ 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;
|
||||
@@ -73,16 +71,6 @@ 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
|
||||
@@ -1355,7 +1343,7 @@ public class ContextWrapper extends Context {
|
||||
public void registerComponentCallbacks(ComponentCallbacks callback) {
|
||||
if (mBase != null) {
|
||||
mBase.registerComponentCallbacks(callback);
|
||||
} else if (!CompatChanges.isChangeEnabled(COMPONENT_CALLBACK_ON_WRAPPER)) {
|
||||
} else if (!CompatChanges.isChangeEnabled(OVERRIDABLE_COMPONENT_CALLBACKS)) {
|
||||
super.registerComponentCallbacks(callback);
|
||||
synchronized (mLock) {
|
||||
// Also register ComponentCallbacks to ContextWrapper, so we can find the correct
|
||||
@@ -1397,7 +1385,7 @@ public class ContextWrapper extends Context {
|
||||
mCallbacksRegisteredToSuper.remove(callback);
|
||||
} else if (mBase != null) {
|
||||
mBase.unregisterComponentCallbacks(callback);
|
||||
} else if (CompatChanges.isChangeEnabled(COMPONENT_CALLBACK_ON_WRAPPER)) {
|
||||
} else if (CompatChanges.isChangeEnabled(OVERRIDABLE_COMPONENT_CALLBACKS)) {
|
||||
// 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.");
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.app.activity;
|
||||
|
||||
import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
|
||||
import static android.content.Context.OVERRIDABLE_COMPONENT_CALLBACKS;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.app.activity.ActivityThreadTest.TestActivity;
|
||||
import android.compat.testing.PlatformCompatChangeRule;
|
||||
import android.content.ComponentCallbacks;
|
||||
import android.content.TestComponentCallbacks2;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Test for verifying {@link Activity#registerComponentCallbacks(ComponentCallbacks)} behavior.
|
||||
* Build/Install/Run:
|
||||
* atest FrameworksCoreTests:android.app.activity.RegisterComponentCallbacksTest
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
public class RegisterComponentCallbacksTest {
|
||||
@Rule
|
||||
public ActivityScenarioRule rule = new ActivityScenarioRule<>(TestActivity.class);
|
||||
@Rule
|
||||
public TestRule compatChangeRule = new PlatformCompatChangeRule();
|
||||
|
||||
@Test
|
||||
public void testRegisterComponentCallbacks() {
|
||||
final ActivityScenario scenario = rule.getScenario();
|
||||
final TestComponentCallbacks2 callbacks = new TestComponentCallbacks2();
|
||||
final Configuration config = new Configuration();
|
||||
config.fontScale = 1.2f;
|
||||
config.windowConfiguration.setWindowingMode(
|
||||
WindowConfiguration.WINDOWING_MODE_FREEFORM);
|
||||
config.windowConfiguration.setBounds(new Rect(0, 0, 100, 100));
|
||||
final int trimMemoryLevel = TRIM_MEMORY_RUNNING_LOW;
|
||||
|
||||
scenario.onActivity(activity -> {
|
||||
// It should be no-op to unregister a ComponentCallbacks without registration.
|
||||
activity.unregisterComponentCallbacks(callbacks);
|
||||
|
||||
activity.registerComponentCallbacks(callbacks);
|
||||
// Verify #onConfigurationChanged
|
||||
activity.onConfigurationChanged(config);
|
||||
assertThat(callbacks.mConfiguration).isEqualTo(config);
|
||||
// Verify #onTrimMemory
|
||||
activity.onTrimMemory(trimMemoryLevel);
|
||||
assertThat(callbacks.mLevel).isEqualTo(trimMemoryLevel);
|
||||
// verify #onLowMemory
|
||||
activity.onLowMemory();
|
||||
assertThat(callbacks.mLowMemoryCalled).isTrue();
|
||||
|
||||
activity.unregisterComponentCallbacks(callbacks);
|
||||
});
|
||||
}
|
||||
|
||||
@DisableCompatChanges(OVERRIDABLE_COMPONENT_CALLBACKS)
|
||||
@Test
|
||||
public void testRegisterComponentCallbacksBeforeT() {
|
||||
final ActivityScenario scenario = rule.getScenario();
|
||||
final TestComponentCallbacks2 callbacks = new TestComponentCallbacks2();
|
||||
final Configuration config = new Configuration();
|
||||
config.fontScale = 1.2f;
|
||||
config.windowConfiguration.setWindowingMode(
|
||||
WindowConfiguration.WINDOWING_MODE_FREEFORM);
|
||||
config.windowConfiguration.setBounds(new Rect(0, 0, 100, 100));
|
||||
final int trimMemoryLevel = TRIM_MEMORY_RUNNING_LOW;
|
||||
|
||||
scenario.onActivity(activity -> {
|
||||
// It should be no-op to unregister a ComponentCallbacks without registration.
|
||||
activity.unregisterComponentCallbacks(callbacks);
|
||||
|
||||
activity.registerComponentCallbacks(callbacks);
|
||||
// Verify #onConfigurationChanged
|
||||
activity.onConfigurationChanged(config);
|
||||
assertWithMessage("The ComponentCallbacks must be added to #getApplicationContext "
|
||||
+ "before T.").that(callbacks.mConfiguration).isNull();
|
||||
// Verify #onTrimMemory
|
||||
activity.onTrimMemory(trimMemoryLevel);
|
||||
assertWithMessage("The ComponentCallbacks must be added to #getApplicationContext "
|
||||
+ "before T.").that(callbacks.mLevel).isEqualTo(0);
|
||||
// verify #onLowMemory
|
||||
activity.onLowMemory();
|
||||
assertWithMessage("The ComponentCallbacks must be added to #getApplicationContext "
|
||||
+ "before T.").that(callbacks.mLowMemoryCalled).isFalse();
|
||||
|
||||
activity.unregisterComponentCallbacks(callbacks);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package android.content;
|
||||
|
||||
import static android.content.ContextWrapper.COMPONENT_CALLBACK_ON_WRAPPER;
|
||||
import static android.content.Context.OVERRIDABLE_COMPONENT_CALLBACKS;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
|
||||
@@ -61,7 +61,7 @@ public class ContextWrapperTest {
|
||||
* register {@link ComponentCallbacks} to {@link ContextWrapper#getApplicationContext} before
|
||||
* {@link ContextWrapper#attachBaseContext(Context)}.
|
||||
*/
|
||||
@DisableCompatChanges(COMPONENT_CALLBACK_ON_WRAPPER)
|
||||
@DisableCompatChanges(OVERRIDABLE_COMPONENT_CALLBACKS)
|
||||
@Test
|
||||
public void testRegisterComponentCallbacksWithoutBaseContextBeforeT() {
|
||||
final ContextWrapper wrapper = new TestContextWrapper(null /* base */);
|
||||
|
||||
@@ -20,10 +20,10 @@ import android.content.res.Configuration;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
class TestComponentCallbacks2 implements ComponentCallbacks2 {
|
||||
android.content.res.Configuration mConfiguration;
|
||||
boolean mLowMemoryCalled;
|
||||
int mLevel;
|
||||
public class TestComponentCallbacks2 implements ComponentCallbacks2 {
|
||||
public Configuration mConfiguration = null;
|
||||
public boolean mLowMemoryCalled = false;
|
||||
public int mLevel = 0;
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
|
||||
@@ -62,6 +62,7 @@ public final class FrameworksTestsFilter extends SelectTest {
|
||||
"android.view.PendingInsetsControllerTest",
|
||||
"android.window.", // all tests under the package.
|
||||
"android.app.activity.ActivityThreadTest",
|
||||
"android.app.activity.RegisterComponentCallbacksTest"
|
||||
};
|
||||
|
||||
public FrameworksTestsFilter(Bundle testArgs) {
|
||||
|
||||
Reference in New Issue
Block a user