Merge "Add a hook that fires before the Activity's super.onCreate()" into androidx-master-dev
diff --git a/activity/activity/api/1.2.0-alpha07.txt b/activity/activity/api/1.2.0-alpha07.txt
index e2b5aed..6883231 100644
--- a/activity/activity/api/1.2.0-alpha07.txt
+++ b/activity/activity/api/1.2.0-alpha07.txt
@@ -1,9 +1,10 @@
// Signature format: 3.0
package androidx.activity {
- public class ComponentActivity extends android.app.Activity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ public class ComponentActivity extends android.app.Activity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
ctor public ComponentActivity();
ctor @ContentView public ComponentActivity(@LayoutRes int);
+ method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
method @Deprecated public Object? getLastCustomNonConfigurationInstance();
@@ -17,6 +18,7 @@
method public final Object? onRetainNonConfigurationInstance();
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method @Deprecated public void startActivityForResult(android.content.Intent!, int);
method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -46,6 +48,26 @@
}
+package androidx.activity.contextaware {
+
+ public interface ContextAware {
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public final class ContextAwareHelper {
+ ctor public ContextAwareHelper(androidx.activity.contextaware.ContextAware);
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void dispatchOnContextAvailable(android.content.Context, android.os.Bundle?);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public interface OnContextAvailableListener {
+ method public void onContextAvailable(androidx.activity.contextaware.ContextAware, android.content.Context, android.os.Bundle?);
+ }
+
+}
+
package androidx.activity.result {
public final class ActivityResult implements android.os.Parcelable {
diff --git a/activity/activity/api/current.txt b/activity/activity/api/current.txt
index e2b5aed..6883231 100644
--- a/activity/activity/api/current.txt
+++ b/activity/activity/api/current.txt
@@ -1,9 +1,10 @@
// Signature format: 3.0
package androidx.activity {
- public class ComponentActivity extends android.app.Activity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ public class ComponentActivity extends android.app.Activity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
ctor public ComponentActivity();
ctor @ContentView public ComponentActivity(@LayoutRes int);
+ method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
method @Deprecated public Object? getLastCustomNonConfigurationInstance();
@@ -17,6 +18,7 @@
method public final Object? onRetainNonConfigurationInstance();
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method @Deprecated public void startActivityForResult(android.content.Intent!, int);
method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -46,6 +48,26 @@
}
+package androidx.activity.contextaware {
+
+ public interface ContextAware {
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public final class ContextAwareHelper {
+ ctor public ContextAwareHelper(androidx.activity.contextaware.ContextAware);
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void dispatchOnContextAvailable(android.content.Context, android.os.Bundle?);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public interface OnContextAvailableListener {
+ method public void onContextAvailable(androidx.activity.contextaware.ContextAware, android.content.Context, android.os.Bundle?);
+ }
+
+}
+
package androidx.activity.result {
public final class ActivityResult implements android.os.Parcelable {
diff --git a/activity/activity/api/public_plus_experimental_1.2.0-alpha07.txt b/activity/activity/api/public_plus_experimental_1.2.0-alpha07.txt
index 1daf641..c40287f 100644
--- a/activity/activity/api/public_plus_experimental_1.2.0-alpha07.txt
+++ b/activity/activity/api/public_plus_experimental_1.2.0-alpha07.txt
@@ -1,9 +1,10 @@
// Signature format: 3.0
package androidx.activity {
- public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
ctor public ComponentActivity();
ctor @ContentView public ComponentActivity(@LayoutRes int);
+ method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
method @Deprecated public Object? getLastCustomNonConfigurationInstance();
@@ -16,6 +17,7 @@
method public final Object? onRetainNonConfigurationInstance();
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method @Deprecated public void startActivityForResult(android.content.Intent!, int);
method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -45,6 +47,26 @@
}
+package androidx.activity.contextaware {
+
+ public interface ContextAware {
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public final class ContextAwareHelper {
+ ctor public ContextAwareHelper(androidx.activity.contextaware.ContextAware);
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void dispatchOnContextAvailable(android.content.Context, android.os.Bundle?);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public interface OnContextAvailableListener {
+ method public void onContextAvailable(androidx.activity.contextaware.ContextAware, android.content.Context, android.os.Bundle?);
+ }
+
+}
+
package androidx.activity.result {
public final class ActivityResult implements android.os.Parcelable {
diff --git a/activity/activity/api/public_plus_experimental_current.txt b/activity/activity/api/public_plus_experimental_current.txt
index 1daf641..c40287f 100644
--- a/activity/activity/api/public_plus_experimental_current.txt
+++ b/activity/activity/api/public_plus_experimental_current.txt
@@ -1,9 +1,10 @@
// Signature format: 3.0
package androidx.activity {
- public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
ctor public ComponentActivity();
ctor @ContentView public ComponentActivity(@LayoutRes int);
+ method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
method @Deprecated public Object? getLastCustomNonConfigurationInstance();
@@ -16,6 +17,7 @@
method public final Object? onRetainNonConfigurationInstance();
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method @Deprecated public void startActivityForResult(android.content.Intent!, int);
method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -45,6 +47,26 @@
}
+package androidx.activity.contextaware {
+
+ public interface ContextAware {
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public final class ContextAwareHelper {
+ ctor public ContextAwareHelper(androidx.activity.contextaware.ContextAware);
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void dispatchOnContextAvailable(android.content.Context, android.os.Bundle?);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public interface OnContextAvailableListener {
+ method public void onContextAvailable(androidx.activity.contextaware.ContextAware, android.content.Context, android.os.Bundle?);
+ }
+
+}
+
package androidx.activity.result {
public final class ActivityResult implements android.os.Parcelable {
diff --git a/activity/activity/api/restricted_1.2.0-alpha07.txt b/activity/activity/api/restricted_1.2.0-alpha07.txt
index 1daf641..c40287f 100644
--- a/activity/activity/api/restricted_1.2.0-alpha07.txt
+++ b/activity/activity/api/restricted_1.2.0-alpha07.txt
@@ -1,9 +1,10 @@
// Signature format: 3.0
package androidx.activity {
- public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
ctor public ComponentActivity();
ctor @ContentView public ComponentActivity(@LayoutRes int);
+ method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
method @Deprecated public Object? getLastCustomNonConfigurationInstance();
@@ -16,6 +17,7 @@
method public final Object? onRetainNonConfigurationInstance();
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method @Deprecated public void startActivityForResult(android.content.Intent!, int);
method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -45,6 +47,26 @@
}
+package androidx.activity.contextaware {
+
+ public interface ContextAware {
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public final class ContextAwareHelper {
+ ctor public ContextAwareHelper(androidx.activity.contextaware.ContextAware);
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void dispatchOnContextAvailable(android.content.Context, android.os.Bundle?);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public interface OnContextAvailableListener {
+ method public void onContextAvailable(androidx.activity.contextaware.ContextAware, android.content.Context, android.os.Bundle?);
+ }
+
+}
+
package androidx.activity.result {
public final class ActivityResult implements android.os.Parcelable {
diff --git a/activity/activity/api/restricted_current.txt b/activity/activity/api/restricted_current.txt
index 1daf641..c40287f 100644
--- a/activity/activity/api/restricted_current.txt
+++ b/activity/activity/api/restricted_current.txt
@@ -1,9 +1,10 @@
// Signature format: 3.0
package androidx.activity {
- public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
ctor public ComponentActivity();
ctor @ContentView public ComponentActivity(@LayoutRes int);
+ method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
method @Deprecated public Object? getLastCustomNonConfigurationInstance();
@@ -16,6 +17,7 @@
method public final Object? onRetainNonConfigurationInstance();
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
method @Deprecated public void startActivityForResult(android.content.Intent!, int);
method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -45,6 +47,26 @@
}
+package androidx.activity.contextaware {
+
+ public interface ContextAware {
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public final class ContextAwareHelper {
+ ctor public ContextAwareHelper(androidx.activity.contextaware.ContextAware);
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void dispatchOnContextAvailable(android.content.Context, android.os.Bundle?);
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public interface OnContextAvailableListener {
+ method public void onContextAvailable(androidx.activity.contextaware.ContextAware, android.content.Context, android.os.Bundle?);
+ }
+
+}
+
package androidx.activity.result {
public final class ActivityResult implements android.os.Parcelable {
diff --git a/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityLifecycleTest.kt b/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityLifecycleTest.kt
index 09de5e3..d8ac2bf 100644
--- a/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityLifecycleTest.kt
+++ b/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityLifecycleTest.kt
@@ -28,6 +28,7 @@
import org.junit.runner.RunWith
internal enum class LifecycleSource {
+ CONTEXT_AWARE,
ACTIVITY,
ACTIVITY_CALLBACK
}
@@ -48,6 +49,7 @@
// followed by the activity's lifecycle observers
assertThat(events)
.containsExactly(
+ LifecycleSource.CONTEXT_AWARE to Lifecycle.Event.ON_CREATE,
LifecycleSource.ACTIVITY_CALLBACK to Lifecycle.Event.ON_CREATE,
LifecycleSource.ACTIVITY to Lifecycle.Event.ON_CREATE,
LifecycleSource.ACTIVITY_CALLBACK to Lifecycle.Event.ON_START,
@@ -69,6 +71,9 @@
internal val events = mutableListOf<Pair<LifecycleSource, Lifecycle.Event>>()
init {
+ addOnContextAvailableListener { _, _, _ ->
+ events.add(LifecycleSource.CONTEXT_AWARE to Lifecycle.Event.ON_CREATE)
+ }
lifecycle.addObserver(LifecycleEventObserver { _, event ->
events.add(LifecycleSource.ACTIVITY to event)
})
diff --git a/activity/activity/src/androidTest/java/androidx/activity/contextaware/ContextAwareHelperTest.kt b/activity/activity/src/androidTest/java/androidx/activity/contextaware/ContextAwareHelperTest.kt
new file mode 100644
index 0000000..3087989
--- /dev/null
+++ b/activity/activity/src/androidTest/java/androidx/activity/contextaware/ContextAwareHelperTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2020 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 androidx.activity.contextaware
+
+import android.content.Context
+import android.os.Bundle
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ContextAwareHelperTest {
+ private val contextAware = TestContextAware()
+
+ @Test
+ fun addOnContextAvailableListener() {
+ var receivedContextAware: ContextAware? = null
+ val listener = OnContextAvailableListener { contextAware, _, _ ->
+ receivedContextAware = contextAware
+ }
+ contextAware.addOnContextAvailableListener(listener)
+ contextAware.dispatchOnContextAvailable()
+
+ assertThat(receivedContextAware).isSameInstanceAs(contextAware)
+ }
+
+ @Test
+ fun removeOnContextAvailableListener() {
+ var callbackCount = 0
+ val listener = OnContextAvailableListener { _, _, _ ->
+ callbackCount++
+ }
+ contextAware.addOnContextAvailableListener(listener)
+ contextAware.dispatchOnContextAvailable()
+
+ assertThat(callbackCount).isEqualTo(1)
+
+ // Now remove the listener and check that the count doesn't increase
+ contextAware.removeOnContextAvailableListener(listener)
+ contextAware.dispatchOnContextAvailable()
+
+ assertThat(callbackCount).isEqualTo(1)
+ }
+
+ @Test
+ fun reentrantRemove() {
+ var callbackCount = 0
+ val listener = object : OnContextAvailableListener {
+ override fun onContextAvailable(
+ contextAware: ContextAware,
+ context: Context,
+ savedInstanceState: Bundle?
+ ) {
+ callbackCount++
+ contextAware.removeOnContextAvailableListener(this)
+ }
+ }
+ contextAware.addOnContextAvailableListener(listener)
+ contextAware.dispatchOnContextAvailable()
+
+ assertThat(callbackCount).isEqualTo(1)
+
+ callbackCount = 0
+ contextAware.dispatchOnContextAvailable()
+
+ assertThat(callbackCount).isEqualTo(0)
+ }
+}
+
+class TestContextAware : ContextAware {
+ private val contextAwareHelper = ContextAwareHelper(this)
+
+ override fun addOnContextAvailableListener(listener: OnContextAvailableListener) {
+ contextAwareHelper.addOnContextAvailableListener(listener)
+ }
+
+ override fun removeOnContextAvailableListener(listener: OnContextAvailableListener) {
+ contextAwareHelper.removeOnContextAvailableListener(listener)
+ }
+
+ fun dispatchOnContextAvailable(savedInstanceState: Bundle? = null) {
+ contextAwareHelper.dispatchOnContextAvailable(
+ ApplicationProvider.getApplicationContext(), savedInstanceState)
+ }
+}
\ No newline at end of file
diff --git a/activity/activity/src/main/java/androidx/activity/ComponentActivity.java b/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
index 24a4863..60ddd6b 100644
--- a/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
+++ b/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
@@ -43,6 +43,9 @@
import android.view.ViewGroup;
import android.view.Window;
+import androidx.activity.contextaware.ContextAware;
+import androidx.activity.contextaware.ContextAwareHelper;
+import androidx.activity.contextaware.OnContextAvailableListener;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultCaller;
import androidx.activity.result.ActivityResultLauncher;
@@ -87,6 +90,7 @@
* without enforcing a deep Activity class hierarchy or strong coupling between components.
*/
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
+ ContextAware,
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
@@ -100,6 +104,7 @@
ViewModelStore viewModelStore;
}
+ private final ContextAwareHelper mContextAwareHelper = new ContextAwareHelper(this);
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
private final SavedStateRegistryController mSavedStateRegistryController =
SavedStateRegistryController.create(this);
@@ -279,6 +284,7 @@
*/
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
+ mContextAwareHelper.dispatchOnContextAvailable(this, savedInstanceState);
super.onCreate(savedInstanceState);
mSavedStateRegistryController.performRestore(savedInstanceState);
mActivityResultRegistry.onRestoreInstanceState(savedInstanceState);
@@ -397,6 +403,26 @@
/**
* {@inheritDoc}
+ *
+ * Any listener added here will receive a callback as part of
+ * <code>super.onCreate()</code>, but importantly <strong>before</strong> any other
+ * logic is done (including calling through to the framework
+ * {@link Activity#onCreate(Bundle)}.
+ */
+ @Override
+ public final void addOnContextAvailableListener(
+ @NonNull OnContextAvailableListener listener) {
+ mContextAwareHelper.addOnContextAvailableListener(listener);
+ }
+
+ @Override
+ public final void removeOnContextAvailableListener(
+ @NonNull OnContextAvailableListener listener) {
+ mContextAwareHelper.removeOnContextAvailableListener(listener);
+ }
+
+ /**
+ * {@inheritDoc}
* <p>
* Overriding this method is no longer supported and this method will be made
* <code>final</code> in a future version of ComponentActivity. If you do override
diff --git a/activity/activity/src/main/java/androidx/activity/contextaware/ContextAware.java b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAware.java
new file mode 100644
index 0000000..a8dde12
--- /dev/null
+++ b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAware.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 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 androidx.activity.contextaware;
+
+import androidx.annotation.NonNull;
+
+/**
+ * A <code>ContextAware</code> class is associated with a {@link android.content.Context} as
+ * a part of its lifecycle.
+ *
+ * @see ContextAwareHelper
+ */
+public interface ContextAware {
+
+ /**
+ * Add a new {@link OnContextAvailableListener} for receiving a callback for when
+ * this class is associated with a {@link android.content.Context}.
+ * <p>
+ * This will only receive a callback when associated with a new Context: no callback
+ * will be triggered if this is already associated with a Context.
+ *
+ * @param listener The listener that should be added.
+ * @see #removeOnContextAvailableListener(OnContextAvailableListener)
+ */
+ void addOnContextAvailableListener(@NonNull OnContextAvailableListener listener);
+
+ /**
+ * Remove a {@link OnContextAvailableListener} previously added via
+ * {@link #addOnContextAvailableListener(OnContextAvailableListener)}.
+ *
+ * @param listener The listener that should be removed.
+ * @see #addOnContextAvailableListener(OnContextAvailableListener)
+ */
+ void removeOnContextAvailableListener(@NonNull OnContextAvailableListener listener);
+}
diff --git a/activity/activity/src/main/java/androidx/activity/contextaware/ContextAwareHelper.java b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAwareHelper.java
new file mode 100644
index 0000000..3e21c20
--- /dev/null
+++ b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAwareHelper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 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 androidx.activity.contextaware;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * Helper class for implementing {@link ContextAware}. Classes using this helper should
+ * call {@link #addOnContextAvailableListener(OnContextAvailableListener)} and
+ * {@link #removeOnContextAvailableListener(OnContextAvailableListener)} as the respective
+ * methods of {@link ContextAware} are called.
+ * <p>
+ * You must call {@link #dispatchOnContextAvailable(Context, Bundle)} once the
+ * {@link Context} is available to dispatch the callbacks to all registered listeners.
+ */
+public final class ContextAwareHelper {
+
+ private final ContextAware mContextAware;
+
+ private final Set<OnContextAvailableListener> mListeners = new CopyOnWriteArraySet<>();
+
+ /**
+ * Construct a new ContextAwareHelper for the given {@link ContextAware} instance.
+ *
+ * @param contextAware The ContextAware instance that listeners are being added to.
+ */
+ public ContextAwareHelper(@NonNull ContextAware contextAware) {
+ mContextAware = contextAware;
+ }
+
+ /**
+ * Add a new {@link OnContextAvailableListener} for receiving a callback for when
+ * this class is associated with a {@link android.content.Context}.
+ *
+ * @param listener The listener that should be added.
+ * @see #removeOnContextAvailableListener(OnContextAvailableListener)
+ */
+ public void addOnContextAvailableListener(@NonNull OnContextAvailableListener listener) {
+ mListeners.add(listener);
+ }
+
+ /**
+ * Remove a {@link OnContextAvailableListener} previously added via
+ * {@link #addOnContextAvailableListener(OnContextAvailableListener)}.
+ *
+ * @param listener The listener that should be removed.
+ * @see #addOnContextAvailableListener(OnContextAvailableListener)
+ */
+ public void removeOnContextAvailableListener(@NonNull OnContextAvailableListener listener) {
+ mListeners.remove(listener);
+ }
+
+ /**
+ * Dispatch the callback of {@link OnContextAvailableListener#onContextAvailable} to
+ * all currently added listeners.
+ *
+ * @param context The {@link Context} the {@link ContextAware} object is now associated with.
+ * @param savedInstanceState The saved instance state, if any.
+ */
+ public void dispatchOnContextAvailable(@NonNull Context context,
+ @Nullable Bundle savedInstanceState) {
+ for (OnContextAvailableListener listener : mListeners) {
+ listener.onContextAvailable(mContextAware, context, savedInstanceState);
+ }
+ }
+}
diff --git a/activity/activity/src/main/java/androidx/activity/contextaware/OnContextAvailableListener.java b/activity/activity/src/main/java/androidx/activity/contextaware/OnContextAvailableListener.java
new file mode 100644
index 0000000..00614a2
--- /dev/null
+++ b/activity/activity/src/main/java/androidx/activity/contextaware/OnContextAvailableListener.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 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 androidx.activity.contextaware;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Listener for receiving a callback at the first moment a {@link Context} is made
+ * available to the {@link ContextAware} class.
+ *
+ * @see ContextAware#addOnContextAvailableListener(OnContextAvailableListener)
+ */
+public interface OnContextAvailableListener {
+
+ /**
+ * Called when the given {@link ContextAware} object is associated to a {@link Context}.
+ *
+ * @param contextAware The object that this listener for added to.
+ * @param context The {@link Context} the {@link ContextAware} object is now associated with.
+ * @param savedInstanceState The saved instance state, if any.
+ */
+ void onContextAvailable(@NonNull ContextAware contextAware,
+ @SuppressLint("ContextFirst") /* The object being operated on should be first */
+ @NonNull Context context,
+ @Nullable Bundle savedInstanceState);
+}
diff --git a/appcompat/appcompat/build.gradle b/appcompat/appcompat/build.gradle
index bdd7054..1afec62 100644
--- a/appcompat/appcompat/build.gradle
+++ b/appcompat/appcompat/build.gradle
@@ -15,7 +15,10 @@
api(project(":core:core"))
implementation("androidx.collection:collection:1.0.0")
api("androidx.cursoradapter:cursoradapter:1.0.0")
- api("androidx.fragment:fragment:1.1.0")
+ api(project(":activity:activity"))
+ // Activity 1.2 requires depending on Fragment 1.3, so we need project dependencies on both
+ // despite only directly requiring new APIs in Activity 1.2
+ api(project(":fragment:fragment"))
api(project(":appcompat:appcompat-resources"))
api("androidx.drawerlayout:drawerlayout:1.0.0")
implementation(project(":lifecycle:lifecycle-runtime"))
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatActivity.java b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatActivity.java
index 664d69f..8c35ee4 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatActivity.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatActivity.java
@@ -30,6 +30,8 @@
import android.view.ViewGroup;
import android.view.Window;
+import androidx.activity.contextaware.ContextAware;
+import androidx.activity.contextaware.OnContextAvailableListener;
import androidx.annotation.CallSuper;
import androidx.annotation.ContentView;
import androidx.annotation.IdRes;
@@ -88,6 +90,7 @@
*/
public AppCompatActivity() {
super();
+ initDelegate();
}
/**
@@ -103,6 +106,19 @@
@ContentView
public AppCompatActivity(@LayoutRes int contentLayoutId) {
super(contentLayoutId);
+ initDelegate();
+ }
+
+ private void initDelegate() {
+ addOnContextAvailableListener(new OnContextAvailableListener() {
+ @Override
+ public void onContextAvailable(@NonNull ContextAware contextAware,
+ @NonNull Context context, @Nullable Bundle savedInstanceState) {
+ final AppCompatDelegate delegate = getDelegate();
+ delegate.installViewFactory();
+ delegate.onCreate(savedInstanceState);
+ }
+ });
}
@Override
@@ -111,14 +127,6 @@
}
@Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- final AppCompatDelegate delegate = getDelegate();
- delegate.installViewFactory();
- delegate.onCreate(savedInstanceState);
- super.onCreate(savedInstanceState);
- }
-
- @Override
public void setTheme(@StyleRes final int resId) {
super.setTheme(resId);
getDelegate().setTheme(resId);
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java
index 8085a9c..0c1a46a 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java
@@ -38,6 +38,8 @@
import androidx.activity.ComponentActivity;
import androidx.activity.OnBackPressedDispatcher;
import androidx.activity.OnBackPressedDispatcherOwner;
+import androidx.activity.contextaware.ContextAware;
+import androidx.activity.contextaware.OnContextAvailableListener;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultRegistry;
import androidx.activity.result.ActivityResultRegistryOwner;
@@ -99,6 +101,7 @@
*/
public FragmentActivity() {
super();
+ init();
}
/**
@@ -114,6 +117,22 @@
@ContentView
public FragmentActivity(@LayoutRes int contentLayoutId) {
super(contentLayoutId);
+ init();
+ }
+
+ private void init() {
+ addOnContextAvailableListener(new OnContextAvailableListener() {
+ @Override
+ public void onContextAvailable(@NonNull ContextAware contextAware,
+ @NonNull Context context, @Nullable Bundle savedInstanceState) {
+ mFragments.attachHost(null /*parent*/);
+
+ if (savedInstanceState != null) {
+ Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
+ mFragments.restoreSaveState(p);
+ }
+ }
+ });
}
// ------------------------------------------------------------------------
@@ -230,13 +249,6 @@
*/
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
- mFragments.attachHost(null /*parent*/);
-
- if (savedInstanceState != null) {
- Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
- mFragments.restoreSaveState(p);
- }
-
super.onCreate(savedInstanceState);
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);