Merge "Remove LifecycleDispatcher & Rename LifecycleRuntimeTrojanProvider" into oc-mr1-support-27.0-dev
diff --git a/lifecycle/extensions/src/main/AndroidManifest.xml b/lifecycle/extensions/src/main/AndroidManifest.xml
index f7698eb..f8a5c48 100644
--- a/lifecycle/extensions/src/main/AndroidManifest.xml
+++ b/lifecycle/extensions/src/main/AndroidManifest.xml
@@ -20,6 +20,6 @@
         <provider android:authorities="${applicationId}.lifecycle-trojan"
             android:multiprocess="true"
             android:exported="false"
-            android:name="android.arch.lifecycle.LifecycleRuntimeTrojanProvider"/>
+            android:name="android.arch.lifecycle.ProcessLifecycleOwnerInitializer"/>
     </application>
 </manifest>
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleDispatcher.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleDispatcher.java
deleted file mode 100644
index 9fdec95..0000000
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleDispatcher.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2017 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.arch.lifecycle;
-
-import static android.arch.lifecycle.Lifecycle.Event.ON_CREATE;
-import static android.arch.lifecycle.Lifecycle.Event.ON_DESTROY;
-import static android.arch.lifecycle.Lifecycle.Event.ON_PAUSE;
-import static android.arch.lifecycle.Lifecycle.Event.ON_RESUME;
-import static android.arch.lifecycle.Lifecycle.Event.ON_START;
-import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
-import static android.arch.lifecycle.Lifecycle.State.CREATED;
-
-import android.app.Activity;
-import android.app.Application;
-import android.arch.lifecycle.Lifecycle.State;
-import android.content.Context;
-import android.os.Bundle;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-
-import java.util.Collection;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * When initialized, it hooks into the Activity callback of the Application and observes
- * Activities. It is responsible to hook in child-fragments to activities and fragments to report
- * their lifecycle events. Another responsibility of this class is to mark as stopped all lifecycle
- * providers related to an activity as soon it is not safe to run a fragment transaction in this
- * activity.
- */
-class LifecycleDispatcher {
-
-    private static final String REPORT_FRAGMENT_TAG = "android.arch.lifecycle"
-            + ".LifecycleDispatcher.report_fragment_tag";
-
-    private static AtomicBoolean sInitialized = new AtomicBoolean(false);
-
-    static void init(Context context) {
-        if (sInitialized.getAndSet(true)) {
-            return;
-        }
-        ((Application) context.getApplicationContext())
-                .registerActivityLifecycleCallbacks(new DispatcherActivityCallback());
-    }
-
-    @SuppressWarnings("WeakerAccess")
-    @VisibleForTesting
-    static class DispatcherActivityCallback extends EmptyActivityLifecycleCallbacks {
-        private final FragmentCallback mFragmentCallback;
-
-        DispatcherActivityCallback() {
-            mFragmentCallback = new FragmentCallback();
-        }
-
-        @Override
-        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
-            if (activity instanceof FragmentActivity) {
-                ((FragmentActivity) activity).getSupportFragmentManager()
-                        .registerFragmentLifecycleCallbacks(mFragmentCallback, true);
-            }
-            ReportFragment.injectIfNeededIn(activity);
-        }
-
-        @Override
-        public void onActivityStopped(Activity activity) {
-            if (activity instanceof FragmentActivity) {
-                markState((FragmentActivity) activity, CREATED);
-            }
-        }
-
-        @Override
-        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
-            if (activity instanceof FragmentActivity) {
-                markState((FragmentActivity) activity, CREATED);
-            }
-        }
-    }
-
-    @SuppressWarnings("WeakerAccess")
-    public static class DestructionReportFragment extends Fragment {
-        @Override
-        public void onPause() {
-            super.onPause();
-            dispatch(ON_PAUSE);
-        }
-
-        @Override
-        public void onStop() {
-            super.onStop();
-            dispatch(ON_STOP);
-        }
-
-        @Override
-        public void onDestroy() {
-            super.onDestroy();
-            dispatch(ON_DESTROY);
-        }
-
-        protected void dispatch(Lifecycle.Event event) {
-            dispatchIfLifecycleOwner(getParentFragment(), event);
-        }
-    }
-
-    private static void markState(FragmentManager manager, State state) {
-        Collection<Fragment> fragments = manager.getFragments();
-        if (fragments == null) {
-            return;
-        }
-        for (Fragment fragment : fragments) {
-            if (fragment == null) {
-                continue;
-            }
-            markStateIn(fragment, state);
-            if (fragment.isAdded()) {
-                markState(fragment.getChildFragmentManager(), state);
-            }
-        }
-    }
-
-    private static void markStateIn(Object object, State state) {
-        if (object instanceof LifecycleRegistryOwner) {
-            LifecycleRegistry registry = ((LifecycleRegistryOwner) object).getLifecycle();
-            registry.markState(state);
-        }
-    }
-
-    private static void markState(FragmentActivity activity, State state) {
-        markStateIn(activity, state);
-        markState(activity.getSupportFragmentManager(), state);
-    }
-
-    private static void dispatchIfLifecycleOwner(Fragment fragment, Lifecycle.Event event) {
-        if (fragment instanceof LifecycleRegistryOwner) {
-            ((LifecycleRegistryOwner) fragment).getLifecycle().handleLifecycleEvent(event);
-        }
-    }
-
-    @SuppressWarnings("WeakerAccess")
-    @VisibleForTesting
-    static class FragmentCallback extends FragmentManager.FragmentLifecycleCallbacks {
-
-        @Override
-        public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
-            dispatchIfLifecycleOwner(f, ON_CREATE);
-
-            if (!(f instanceof LifecycleRegistryOwner)) {
-                return;
-            }
-
-            if (f.getChildFragmentManager().findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
-                f.getChildFragmentManager().beginTransaction().add(new DestructionReportFragment(),
-                        REPORT_FRAGMENT_TAG).commit();
-            }
-        }
-
-        @Override
-        public void onFragmentStarted(FragmentManager fm, Fragment f) {
-            dispatchIfLifecycleOwner(f, ON_START);
-        }
-
-        @Override
-        public void onFragmentResumed(FragmentManager fm, Fragment f) {
-            dispatchIfLifecycleOwner(f, ON_RESUME);
-        }
-    }
-}
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/ProcessLifecycleOwner.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ProcessLifecycleOwner.java
index ec8274c..179e2c4 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/ProcessLifecycleOwner.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ProcessLifecycleOwner.java
@@ -157,7 +157,8 @@
         app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
             @Override
             public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
-                ReportFragment  .get(activity).setProcessListener(mInitializationListener);
+                ReportFragment.injectIfNeededIn(activity);
+                ReportFragment.get(activity).setProcessListener(mInitializationListener);
             }
 
             @Override
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleRuntimeTrojanProvider.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ProcessLifecycleOwnerInitializer.java
similarity index 93%
rename from lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleRuntimeTrojanProvider.java
rename to lifecycle/extensions/src/main/java/android/arch/lifecycle/ProcessLifecycleOwnerInitializer.java
index ac278c0..8ba297f 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LifecycleRuntimeTrojanProvider.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ProcessLifecycleOwnerInitializer.java
@@ -29,10 +29,9 @@
  * @hide
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class LifecycleRuntimeTrojanProvider extends ContentProvider {
+public class ProcessLifecycleOwnerInitializer extends ContentProvider {
     @Override
     public boolean onCreate() {
-        LifecycleDispatcher.init(getContext());
         ProcessLifecycleOwner.init(getContext());
         return true;
     }
diff --git a/lifecycle/extensions/src/test/java/android/arch/lifecycle/DispatcherActivityCallbackTest.java b/lifecycle/extensions/src/test/java/android/arch/lifecycle/DispatcherActivityCallbackTest.java
deleted file mode 100644
index 86b25b6..0000000
--- a/lifecycle/extensions/src/test/java/android/arch/lifecycle/DispatcherActivityCallbackTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2017 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.arch.lifecycle;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentTransaction;
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DispatcherActivityCallbackTest {
-    @Test
-    public void onCreateFrameworkActivity() {
-        LifecycleDispatcher.DispatcherActivityCallback callback =
-                new LifecycleDispatcher.DispatcherActivityCallback();
-        Activity activity = mock(Activity.class);
-        checkReportFragment(callback, activity);
-    }
-
-    @Test
-    public void onCreateFragmentActivity() {
-        LifecycleDispatcher.DispatcherActivityCallback callback =
-                new LifecycleDispatcher.DispatcherActivityCallback();
-        FragmentActivity activity = mock(FragmentActivity.class);
-        FragmentManager fragmentManager = mock(FragmentManager.class);
-        when(activity.getSupportFragmentManager()).thenReturn(fragmentManager);
-
-        checkReportFragment(callback, activity);
-
-        verify(activity).getSupportFragmentManager();
-        verify(fragmentManager).registerFragmentLifecycleCallbacks(
-                any(FragmentManager.FragmentLifecycleCallbacks.class), eq(true));
-    }
-
-    @SuppressLint("CommitTransaction")
-    private void checkReportFragment(LifecycleDispatcher.DispatcherActivityCallback callback,
-            Activity activity) {
-        android.app.FragmentManager fm = mock(android.app.FragmentManager.class);
-        FragmentTransaction transaction = mock(FragmentTransaction.class);
-        when(activity.getFragmentManager()).thenReturn(fm);
-        when(fm.beginTransaction()).thenReturn(transaction);
-        when(transaction.add(any(Fragment.class), anyString())).thenReturn(transaction);
-        callback.onActivityCreated(activity, mock(Bundle.class));
-        verify(activity).getFragmentManager();
-        verify(fm).beginTransaction();
-        verify(transaction).add(any(ReportFragment.class), anyString());
-        verify(transaction).commit();
-    }
-}
diff --git a/lifecycle/integration-tests/testapp/src/androidTest/java/android/arch/lifecycle/ProcessOwnerTest.java b/lifecycle/integration-tests/testapp/src/androidTest/java/android/arch/lifecycle/ProcessOwnerTest.java
index 37bdcdb..77baf94 100644
--- a/lifecycle/integration-tests/testapp/src/androidTest/java/android/arch/lifecycle/ProcessOwnerTest.java
+++ b/lifecycle/integration-tests/testapp/src/androidTest/java/android/arch/lifecycle/ProcessOwnerTest.java
@@ -31,6 +31,7 @@
 import android.arch.lifecycle.testapp.NavigationDialogActivity;
 import android.arch.lifecycle.testapp.NavigationTestActivityFirst;
 import android.arch.lifecycle.testapp.NavigationTestActivitySecond;
+import android.arch.lifecycle.testapp.NonSupportActivity;
 import android.content.Context;
 import android.content.Intent;
 import android.support.test.InstrumentationRegistry;
@@ -95,6 +96,22 @@
     }
 
     @Test
+    public void testNavigationToNonSupport() throws Throwable {
+        FragmentActivity firstActivity = setupObserverOnResume();
+        Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(
+                NonSupportActivity.class.getCanonicalName(), null, false);
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.addMonitor(monitor);
+
+        Intent intent = new Intent(firstActivity, NonSupportActivity.class);
+        firstActivity.finish();
+        firstActivity.startActivity(intent);
+        NonSupportActivity secondActivity = (NonSupportActivity) monitor.waitForActivity();
+        assertThat("Failed to navigate", secondActivity, notNullValue());
+        checkProcessObserverSilent(secondActivity);
+    }
+
+    @Test
     public void testRecreation() throws Throwable {
         FragmentActivity activity = setupObserverOnResume();
         FragmentActivity recreated = TestUtils.recreateActivity(activity, activityTestRule);
@@ -164,4 +181,11 @@
         activityTestRule.runOnUiThread(() ->
                 ProcessLifecycleOwner.get().getLifecycle().removeObserver(mObserver));
     }
+
+    private void checkProcessObserverSilent(NonSupportActivity activity) throws Throwable {
+        assertThat(activity.awaitResumedState(), is(true));
+        assertThat(mObserver.mChangedState, is(false));
+        activityTestRule.runOnUiThread(() ->
+                ProcessLifecycleOwner.get().getLifecycle().removeObserver(mObserver));
+    }
 }
diff --git a/lifecycle/integration-tests/testapp/src/main/AndroidManifest.xml b/lifecycle/integration-tests/testapp/src/main/AndroidManifest.xml
index bf88f97..50f2924 100644
--- a/lifecycle/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/lifecycle/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -71,5 +71,6 @@
         <activity android:name=".NavigationDialogActivity"
             android:launchMode="singleTask"
             android:theme="@android:style/Theme.DeviceDefault.Dialog" />
+        <activity android:name=".NonSupportActivity"/>
     </application>
 </manifest>
diff --git a/lifecycle/integration-tests/testapp/src/main/java/android/arch/lifecycle/testapp/NonSupportActivity.java b/lifecycle/integration-tests/testapp/src/main/java/android/arch/lifecycle/testapp/NonSupportActivity.java
new file mode 100644
index 0000000..835d846
--- /dev/null
+++ b/lifecycle/integration-tests/testapp/src/main/java/android/arch/lifecycle/testapp/NonSupportActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 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.arch.lifecycle.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Activity which doesn't extend FragmentActivity, to test ProcessLifecycleOwner because it
+ * should work anyway.
+ */
+public class NonSupportActivity extends Activity {
+
+    private static final int TIMEOUT = 1; //secs
+    private final Lock mLock = new ReentrantLock();
+    private Condition mIsResumedCondition = mLock.newCondition();
+    private boolean mIsResumed = false;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mLock.lock();
+        try {
+            mIsResumed = true;
+            mIsResumedCondition.signalAll();
+        } finally {
+            mLock.unlock();
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mLock.lock();
+        try {
+            mIsResumed = false;
+        } finally {
+            mLock.unlock();
+        }
+    }
+
+    /**
+     *  awaits resumed state
+     * @return
+     * @throws InterruptedException
+     */
+    public boolean awaitResumedState() throws InterruptedException {
+        mLock.lock();
+        try {
+            while (!mIsResumed) {
+                if (!mIsResumedCondition.await(TIMEOUT, TimeUnit.SECONDS)) {
+                    return false;
+                }
+            }
+            return true;
+        } finally {
+            mLock.unlock();
+        }
+    }
+}