chromium/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcherImpl.java

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.init;

import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;

import androidx.annotation.VisibleForTesting;

import org.chromium.base.ObserverList;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.ActivityResultWithNativeObserver;
import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver;
import org.chromium.chrome.browser.lifecycle.DestroyObserver;
import org.chromium.chrome.browser.lifecycle.InflationObserver;
import org.chromium.chrome.browser.lifecycle.LifecycleObserver;
import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
import org.chromium.chrome.browser.lifecycle.OnUserLeaveHintObserver;
import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver;
import org.chromium.chrome.browser.lifecycle.RecreateObserver;
import org.chromium.chrome.browser.lifecycle.SaveInstanceStateObserver;
import org.chromium.chrome.browser.lifecycle.StartStopWithNativeObserver;
import org.chromium.chrome.browser.lifecycle.TopResumedActivityChangedObserver;
import org.chromium.chrome.browser.lifecycle.WindowFocusChangedObserver;

/**
 * Dispatches lifecycle events of activities extending {@link AsyncInitializationActivity} to
 * registered observers.
 *
 * All observers will be automatically cleared when the backing activity is destroyed.
 */
public class ActivityLifecycleDispatcherImpl implements ActivityLifecycleDispatcher {
    private final ObserverList<InflationObserver> mInflationObservers = new ObserverList<>();
    private final ObserverList<NativeInitObserver> mNativeInitObservers = new ObserverList<>();
    private final ObserverList<PauseResumeWithNativeObserver> mPauseResumeObservers =
            new ObserverList<>();
    private final ObserverList<StartStopWithNativeObserver> mStartStopObservers =
            new ObserverList<>();
    private final ObserverList<DestroyObserver> mDestroyables = new ObserverList<>();
    private final ObserverList<SaveInstanceStateObserver> mSaveInstanceStateObservers =
            new ObserverList<>();
    private final ObserverList<WindowFocusChangedObserver> mWindowFocusChangesObservers =
            new ObserverList<>();
    private final ObserverList<ActivityResultWithNativeObserver>
            mActivityResultWithNativeObservers = new ObserverList<>();
    private final ObserverList<ConfigurationChangedObserver> mConfigurationChangedListeners =
            new ObserverList<>();
    private final ObserverList<RecreateObserver> mRecreateObservers = new ObserverList<>();
    private final ObserverList<OnUserLeaveHintObserver> mOnUserLeaveHintObservers =
            new ObserverList<>();
    private final ObserverList<TopResumedActivityChangedObserver>
            mTopResumedActivityChangedObservers = new ObserverList<>();

    private final Activity mActivity;

    private @ActivityState int mActivityState = ActivityState.DESTROYED;
    private boolean mIsNativeInitialized;
    private boolean mDestroyed;

    public ActivityLifecycleDispatcherImpl(Activity activity) {
        mActivity = activity;
    }

    @Override
    public void register(LifecycleObserver observer) {
        if (observer instanceof InflationObserver) {
            mInflationObservers.addObserver((InflationObserver) observer);
        }
        if (observer instanceof PauseResumeWithNativeObserver) {
            mPauseResumeObservers.addObserver((PauseResumeWithNativeObserver) observer);
        }
        if (observer instanceof StartStopWithNativeObserver) {
            mStartStopObservers.addObserver((StartStopWithNativeObserver) observer);
        }
        if (observer instanceof NativeInitObserver) {
            mNativeInitObservers.addObserver((NativeInitObserver) observer);
        }
        if (observer instanceof DestroyObserver) {
            mDestroyables.addObserver((DestroyObserver) observer);
        }
        if (observer instanceof SaveInstanceStateObserver) {
            mSaveInstanceStateObservers.addObserver((SaveInstanceStateObserver) observer);
        }
        if (observer instanceof WindowFocusChangedObserver) {
            mWindowFocusChangesObservers.addObserver((WindowFocusChangedObserver) observer);
        }
        if (observer instanceof ActivityResultWithNativeObserver) {
            mActivityResultWithNativeObservers.addObserver(
                    (ActivityResultWithNativeObserver) observer);
        }
        if (observer instanceof ConfigurationChangedObserver) {
            mConfigurationChangedListeners.addObserver((ConfigurationChangedObserver) observer);
        }
        if (observer instanceof RecreateObserver) {
            mRecreateObservers.addObserver((RecreateObserver) observer);
        }
        if (observer instanceof OnUserLeaveHintObserver) {
            mOnUserLeaveHintObservers.addObserver((OnUserLeaveHintObserver) observer);
        }
        if (observer instanceof TopResumedActivityChangedObserver) {
            mTopResumedActivityChangedObservers.addObserver(
                    (TopResumedActivityChangedObserver) observer);
        }
    }

    @Override
    public void unregister(LifecycleObserver observer) {
        if (observer instanceof InflationObserver) {
            mInflationObservers.removeObserver((InflationObserver) observer);
        }
        if (observer instanceof PauseResumeWithNativeObserver) {
            mPauseResumeObservers.removeObserver((PauseResumeWithNativeObserver) observer);
        }
        if (observer instanceof StartStopWithNativeObserver) {
            mStartStopObservers.removeObserver((StartStopWithNativeObserver) observer);
        }
        if (observer instanceof NativeInitObserver) {
            mNativeInitObservers.removeObserver((NativeInitObserver) observer);
        }
        if (observer instanceof DestroyObserver) {
            mDestroyables.removeObserver((DestroyObserver) observer);
        }
        if (observer instanceof SaveInstanceStateObserver) {
            mSaveInstanceStateObservers.removeObserver((SaveInstanceStateObserver) observer);
        }
        if (observer instanceof WindowFocusChangedObserver) {
            mWindowFocusChangesObservers.removeObserver((WindowFocusChangedObserver) observer);
        }
        if (observer instanceof ActivityResultWithNativeObserver) {
            mActivityResultWithNativeObservers.removeObserver(
                    (ActivityResultWithNativeObserver) observer);
        }
        if (observer instanceof ConfigurationChangedObserver) {
            mConfigurationChangedListeners.removeObserver((ConfigurationChangedObserver) observer);
        }
        if (observer instanceof RecreateObserver) {
            mRecreateObservers.removeObserver((RecreateObserver) observer);
        }
        if (observer instanceof OnUserLeaveHintObserver) {
            mOnUserLeaveHintObservers.removeObserver((OnUserLeaveHintObserver) observer);
        }
        if (observer instanceof TopResumedActivityChangedObserver) {
            mTopResumedActivityChangedObservers.removeObserver(
                    (TopResumedActivityChangedObserver) observer);
        }
    }

    @Override
    public int getCurrentActivityState() {
        return mActivityState;
    }

    @Override
    public boolean isNativeInitializationFinished() {
        return mIsNativeInitialized;
    }

    @Override
    public boolean isActivityFinishingOrDestroyed() {
        return mDestroyed || mActivity.isFinishing();
    }

    void dispatchPreInflationStartup() {
        for (InflationObserver observer : mInflationObservers) {
            observer.onPreInflationStartup();
        }
    }

    void dispatchOnInflationComplete() {
        for (InflationObserver observer : mInflationObservers) {
            observer.onInflationComplete();
        }
    }

    void dispatchPostInflationStartup() {
        if (isActivityFinishingOrDestroyed()) return;
        for (InflationObserver observer : mInflationObservers) {
            observer.onPostInflationStartup();
        }
    }

    void onCreateWithNative() {
        mActivityState = ActivityState.CREATED_WITH_NATIVE;
    }

    void dispatchOnResumeWithNative() {
        mActivityState = ActivityState.RESUMED_WITH_NATIVE;
        for (PauseResumeWithNativeObserver observer : mPauseResumeObservers) {
            observer.onResumeWithNative();
        }
    }

    void dispatchOnPauseWithNative() {
        mActivityState = ActivityState.PAUSED_WITH_NATIVE;
        for (PauseResumeWithNativeObserver observer : mPauseResumeObservers) {
            observer.onPauseWithNative();
        }
    }

    void dispatchOnStartWithNative() {
        mActivityState = ActivityState.STARTED_WITH_NATIVE;
        for (StartStopWithNativeObserver observer : mStartStopObservers) {
            observer.onStartWithNative();
        }
    }

    void dispatchOnStopWithNative() {
        mActivityState = ActivityState.STOPPED_WITH_NATIVE;
        for (StartStopWithNativeObserver observer : mStartStopObservers) {
            observer.onStopWithNative();
        }
    }

    void dispatchNativeInitializationFinished() {
        mIsNativeInitialized = true;
        for (NativeInitObserver observer : mNativeInitObservers) {
            observer.onFinishNativeInitialization();
        }
    }

    void onDestroyStarted() {
        mDestroyed = true;
    }

    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
    protected void dispatchOnDestroy() {
        mActivityState = ActivityState.DESTROYED;

        for (DestroyObserver destroyable : mDestroyables) {
            destroyable.onDestroy();
        }

        // Drain observers to prevent possible memory leaks.
        // TODO(twellington): Add some state to this class to prevent observers from being
        //                    registered after the activity has been destroyed.
        mInflationObservers.clear();
        mPauseResumeObservers.clear();
        mStartStopObservers.clear();
        mNativeInitObservers.clear();
        mSaveInstanceStateObservers.clear();
        mWindowFocusChangesObservers.clear();
        mActivityResultWithNativeObservers.clear();
        mConfigurationChangedListeners.clear();
        mDestroyables.clear();
        mRecreateObservers.clear();
        mTopResumedActivityChangedObservers.clear();
    }

    void dispatchOnSaveInstanceState(Bundle outBundle) {
        for (SaveInstanceStateObserver observer : mSaveInstanceStateObservers) {
            observer.onSaveInstanceState(outBundle);
        }
    }

    void dispatchOnWindowFocusChanged(boolean hasFocus) {
        for (WindowFocusChangedObserver observer : mWindowFocusChangesObservers) {
            observer.onWindowFocusChanged(hasFocus);
        }
    }

    void dispatchOnActivityResultWithNative(int requestCode, int resultCode, Intent data) {
        for (ActivityResultWithNativeObserver observer : mActivityResultWithNativeObservers) {
            observer.onActivityResultWithNative(requestCode, resultCode, data);
        }
    }

    void dispatchOnConfigurationChanged(Configuration newConfig) {
        for (ConfigurationChangedObserver observer : mConfigurationChangedListeners) {
            observer.onConfigurationChanged(newConfig);
        }
    }

    void dispatchOnRecreate() {
        for (RecreateObserver observer : mRecreateObservers) {
            observer.onRecreate();
        }
    }

    void dispatchOnUserLeaveHint() {
        for (OnUserLeaveHintObserver observer : mOnUserLeaveHintObservers) {
            observer.onUserLeaveHint();
        }
    }

    void dispatchOnTopResumedActivityChanged(boolean isTopResumedActivity) {
        for (TopResumedActivityChangedObserver observer : mTopResumedActivityChangedObservers) {
            observer.onTopResumedActivityChanged(isTopResumedActivity);
        }
    }
}