Replace ReportFragment with LifecycleCallbacks on API 29+

Instead of requiring a framework fragment in
ReportFragment to listen for the correct
Lifecycle callbacks, we can instead use the
new ActivityLifecycleCallbacks added in API 29 to
achieve the same relative ordering.

Test: existing Fragment, Activity, and Lifecycle tests pass
Fixes: 116118635
Change-Id: I60a98ccda226b4e958930d67e4a6485c1b1987d3
diff --git a/lifecycle/lifecycle-process/src/main/java/androidx/lifecycle/ProcessLifecycleOwner.java b/lifecycle/lifecycle-process/src/main/java/androidx/lifecycle/ProcessLifecycleOwner.java
index d3789c6..9a1a494 100644
--- a/lifecycle/lifecycle-process/src/main/java/androidx/lifecycle/ProcessLifecycleOwner.java
+++ b/lifecycle/lifecycle-process/src/main/java/androidx/lifecycle/ProcessLifecycleOwner.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.Application;
 import android.content.Context;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 
@@ -159,7 +160,21 @@
         app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
             @Override
             public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
-                ReportFragment.get(activity).setProcessListener(mInitializationListener);
+                // Only use ReportFragment pre API 29 - after that, we can use the
+                // onActivityPostStarted and onActivityPostResumed callbacks directly
+                if (Build.VERSION.SDK_INT < 29) {
+                    ReportFragment.get(activity).setProcessListener(mInitializationListener);
+                }
+            }
+
+            @Override
+            public void onActivityPostStarted(@NonNull Activity activity) {
+                activityStarted();
+            }
+
+            @Override
+            public void onActivityPostResumed(@NonNull Activity activity) {
+                activityResumed();
             }
 
             @Override
diff --git a/lifecycle/lifecycle-runtime/src/main/java/androidx/lifecycle/ReportFragment.java b/lifecycle/lifecycle-runtime/src/main/java/androidx/lifecycle/ReportFragment.java
index e2a80a2..96df169 100644
--- a/lifecycle/lifecycle-runtime/src/main/java/androidx/lifecycle/ReportFragment.java
+++ b/lifecycle/lifecycle-runtime/src/main/java/androidx/lifecycle/ReportFragment.java
@@ -17,9 +17,13 @@
 package androidx.lifecycle;
 
 import android.app.Activity;
+import android.app.Application;
 import android.app.Fragment;
+import android.os.Build;
 import android.os.Bundle;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 
 /**
@@ -34,13 +38,96 @@
             + ".LifecycleDispatcher.report_fragment_tag";
 
     public static void injectIfNeededIn(Activity activity) {
-        // ProcessLifecycleOwner should always correctly work and some activities may not extend
-        // FragmentActivity from support lib, so we use framework fragments for activities
-        android.app.FragmentManager manager = activity.getFragmentManager();
-        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
-            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
-            // Hopefully, we are the first to make a transaction.
-            manager.executePendingTransactions();
+        if (Build.VERSION.SDK_INT >= 29) {
+            // On API 29+, we can register for the correct Lifecycle callbacks directly
+            activity.registerActivityLifecycleCallbacks(
+                    new Application.ActivityLifecycleCallbacks() {
+                        @Override
+                        public void onActivityCreated(@NonNull Activity activity,
+                                @Nullable Bundle bundle) {
+                        }
+
+                        @Override
+                        public void onActivityPostCreated(@NonNull Activity activity,
+                                @Nullable Bundle savedInstanceState) {
+                            dispatch(activity, Lifecycle.Event.ON_CREATE);
+                        }
+
+                        @Override
+                        public void onActivityStarted(@NonNull Activity activity) {
+                        }
+
+                        @Override
+                        public void onActivityPostStarted(@NonNull Activity activity) {
+                            dispatch(activity, Lifecycle.Event.ON_START);
+                        }
+
+                        @Override
+                        public void onActivityResumed(@NonNull Activity activity) {
+                        }
+
+                        @Override
+                        public void onActivityPostResumed(@NonNull Activity activity) {
+                            dispatch(activity, Lifecycle.Event.ON_RESUME);
+                        }
+
+                        @Override
+                        public void onActivityPrePaused(@NonNull Activity activity) {
+                            dispatch(activity, Lifecycle.Event.ON_PAUSE);
+                        }
+
+                        @Override
+                        public void onActivityPaused(@NonNull Activity activity) {
+                        }
+
+                        @Override
+                        public void onActivityPreStopped(@NonNull Activity activity) {
+                            dispatch(activity, Lifecycle.Event.ON_STOP);
+                        }
+
+                        @Override
+                        public void onActivityStopped(@NonNull Activity activity) {
+                        }
+
+                        @Override
+                        public void onActivitySaveInstanceState(@NonNull Activity activity,
+                                @NonNull Bundle bundle) {
+                        }
+
+                        @Override
+                        public void onActivityPreDestroyed(@NonNull Activity activity) {
+                            dispatch(activity, Lifecycle.Event.ON_DESTROY);
+                        }
+
+                        @Override
+                        public void onActivityDestroyed(@NonNull Activity activity) {
+                        }
+                    });
+        } else {
+            // ProcessLifecycleOwner should always correctly work and some activities may not
+            // extend FragmentActivity from support lib, so we use framework fragments for
+            // activities prior to API 29 so as to get the correct timing of Lifecycle events
+            android.app.FragmentManager manager = activity.getFragmentManager();
+            if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
+                manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
+                // Hopefully, we are the first to make a transaction.
+                manager.executePendingTransactions();
+            }
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
+        if (activity instanceof LifecycleRegistryOwner) {
+            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
+            return;
+        }
+
+        if (activity instanceof LifecycleOwner) {
+            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
+            if (lifecycle instanceof LifecycleRegistry) {
+                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
+            }
         }
     }
 
@@ -73,58 +160,43 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
         dispatchCreate(mProcessListener);
-        dispatch(Lifecycle.Event.ON_CREATE);
+        dispatch(getActivity(), Lifecycle.Event.ON_CREATE);
     }
 
     @Override
     public void onStart() {
         super.onStart();
         dispatchStart(mProcessListener);
-        dispatch(Lifecycle.Event.ON_START);
+        dispatch(getActivity(), Lifecycle.Event.ON_START);
     }
 
     @Override
     public void onResume() {
         super.onResume();
         dispatchResume(mProcessListener);
-        dispatch(Lifecycle.Event.ON_RESUME);
+        dispatch(getActivity(), Lifecycle.Event.ON_RESUME);
     }
 
     @Override
     public void onPause() {
         super.onPause();
-        dispatch(Lifecycle.Event.ON_PAUSE);
+        dispatch(getActivity(), Lifecycle.Event.ON_PAUSE);
     }
 
     @Override
     public void onStop() {
         super.onStop();
-        dispatch(Lifecycle.Event.ON_STOP);
+        dispatch(getActivity(), Lifecycle.Event.ON_STOP);
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
-        dispatch(Lifecycle.Event.ON_DESTROY);
+        dispatch(getActivity(), Lifecycle.Event.ON_DESTROY);
         // just want to be sure that we won't leak reference to an activity
         mProcessListener = null;
     }
 
-    private void dispatch(Lifecycle.Event event) {
-        Activity activity = getActivity();
-        if (activity instanceof LifecycleRegistryOwner) {
-            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
-            return;
-        }
-
-        if (activity instanceof LifecycleOwner) {
-            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
-            if (lifecycle instanceof LifecycleRegistry) {
-                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
-            }
-        }
-    }
-
     void setProcessListener(ActivityInitializationListener processListener) {
         mProcessListener = processListener;
     }