Lifecycle.kt

/*
 * 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 androidx.lifecycle

import androidx.annotation.MainThread
import androidx.annotation.RestrictTo
import androidx.lifecycle.Lifecycle.Event
import java.util.concurrent.atomic.AtomicReference

/**
 * Defines an object that has an Android Lifecycle. [Fragment][androidx.fragment.app.Fragment]
 * and [FragmentActivity][androidx.fragment.app.FragmentActivity] classes implement
 * [LifecycleOwner] interface which has the [ getLifecycle][LifecycleOwner.getLifecycle] method to access the Lifecycle. You can also implement [LifecycleOwner]
 * in your own classes.
 *
 * [Event.ON_CREATE], [Event.ON_START], [Event.ON_RESUME] events in this class
 * are dispatched **after** the [LifecycleOwner]'s related method returns.
 * [Event.ON_PAUSE], [Event.ON_STOP], [Event.ON_DESTROY] events in this class
 * are dispatched **before** the [LifecycleOwner]'s related method is called.
 * For instance, [Event.ON_START] will be dispatched after
 * [onStart][android.app.Activity.onStart] returns, [Event.ON_STOP] will be dispatched
 * before [onStop][android.app.Activity.onStop] is called.
 * This gives you certain guarantees on which state the owner is in.
 *
 * To observe lifecycle events call [.addObserver] passing an object
 * that implements either [DefaultLifecycleObserver] or [LifecycleEventObserver].
 */
public abstract class Lifecycle {
    /**
     * Lifecycle coroutines extensions stashes the CoroutineScope into this field.
     *
     * @hide used by lifecycle-common-ktx
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public var internalScopeRef: AtomicReference<Any> = AtomicReference<Any>()

    /**
     * Adds a LifecycleObserver that will be notified when the LifecycleOwner changes
     * state.
     *
     * The given observer will be brought to the current state of the LifecycleOwner.
     * For example, if the LifecycleOwner is in [State.STARTED] state, the given observer
     * will receive [Event.ON_CREATE], [Event.ON_START] events.
     *
     * @param observer The observer to notify.
     */
    @MainThread
    public abstract fun addObserver(observer: LifecycleObserver)

    /**
     * Removes the given observer from the observers list.
     *
     * If this method is called while a state change is being dispatched,
     *
     *  * If the given observer has not yet received that event, it will not receive it.
     *  * If the given observer has more than 1 method that observes the currently dispatched
     * event and at least one of them received the event, all of them will receive the event and
     * the removal will happen afterwards.
     *
     *
     * @param observer The observer to be removed.
     */
    @MainThread
    public abstract fun removeObserver(observer: LifecycleObserver)

    /**
     * Returns the current state of the Lifecycle.
     *
     * @return The current state of the Lifecycle.
     */
    @get:MainThread
    public abstract val currentState: State

    public enum class Event {
        /**
         * Constant for onCreate event of the [LifecycleOwner].
         */
        ON_CREATE,

        /**
         * Constant for onStart event of the [LifecycleOwner].
         */
        ON_START,

        /**
         * Constant for onResume event of the [LifecycleOwner].
         */
        ON_RESUME,

        /**
         * Constant for onPause event of the [LifecycleOwner].
         */
        ON_PAUSE,

        /**
         * Constant for onStop event of the [LifecycleOwner].
         */
        ON_STOP,

        /**
         * Constant for onDestroy event of the [LifecycleOwner].
         */
        ON_DESTROY,

        /**
         * An [Event] constant that can be used to match all events.
         */
        ON_ANY;

        /**
         * Returns the new [Lifecycle.State] of a [Lifecycle] that just reported
         * this [Lifecycle.Event].
         *
         * Throws [IllegalArgumentException] if called on [.ON_ANY], as it is a special
         * value used by [OnLifecycleEvent] and not a real lifecycle event.
         *
         * @return the state that will result from this event
         */
        public val targetState: State
            get() {
                when (this) {
                    ON_CREATE, ON_STOP -> return State.CREATED
                    ON_START, ON_PAUSE -> return State.STARTED
                    ON_RESUME -> return State.RESUMED
                    ON_DESTROY -> return State.DESTROYED
                    ON_ANY -> {}
                }
                throw IllegalArgumentException("$this has no target state")
            }

        public companion object {
            /**
             * Returns the [Lifecycle.Event] that will be reported by a [Lifecycle]
             * leaving the specified [Lifecycle.State] to a lower state, or `null`
             * if there is no valid event that can move down from the given state.
             *
             * @param state the higher state that the returned event will transition down from
             * @return the event moving down the lifecycle phases from state
             */
            @JvmStatic
            public fun downFrom(state: State): Event? {
                return when (state) {
                    State.CREATED -> ON_DESTROY
                    State.STARTED -> ON_STOP
                    State.RESUMED -> ON_PAUSE
                    else -> null
                }
            }

            /**
             * Returns the [Lifecycle.Event] that will be reported by a [Lifecycle]
             * entering the specified [Lifecycle.State] from a higher state, or `null`
             * if there is no valid event that can move down to the given state.
             *
             * @param state the lower state that the returned event will transition down to
             * @return the event moving down the lifecycle phases to state
             */
            @JvmStatic
            public fun downTo(state: State): Event? {
                return when (state) {
                    State.DESTROYED -> ON_DESTROY
                    State.CREATED -> ON_STOP
                    State.STARTED -> ON_PAUSE
                    else -> null
                }
            }

            /**
             * Returns the [Lifecycle.Event] that will be reported by a [Lifecycle]
             * leaving the specified [Lifecycle.State] to a higher state, or `null`
             * if there is no valid event that can move up from the given state.
             *
             * @param state the lower state that the returned event will transition up from
             * @return the event moving up the lifecycle phases from state
             */
            @JvmStatic
            public fun upFrom(state: State): Event? {
                return when (state) {
                    State.INITIALIZED -> ON_CREATE
                    State.CREATED -> ON_START
                    State.STARTED -> ON_RESUME
                    else -> null
                }
            }

            /**
             * Returns the [Lifecycle.Event] that will be reported by a [Lifecycle]
             * entering the specified [Lifecycle.State] from a lower state, or `null`
             * if there is no valid event that can move up to the given state.
             *
             * @param state the higher state that the returned event will transition up to
             * @return the event moving up the lifecycle phases to state
             */
            @JvmStatic
            public fun upTo(state: State): Event? {
                return when (state) {
                    State.CREATED -> ON_CREATE
                    State.STARTED -> ON_START
                    State.RESUMED -> ON_RESUME
                    else -> null
                }
            }
        }
    }

    /**
     * Lifecycle states. You can consider the states as the nodes in a graph and
     * [Event]s as the edges between these nodes.
     */
    public enum class State {
        /**
         * Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
         * any more events. For instance, for an [android.app.Activity], this state is reached
         * **right before** Activity's [onDestroy][android.app.Activity.onDestroy] call.
         */
        DESTROYED,

        /**
         * Initialized state for a LifecycleOwner. For an [android.app.Activity], this is
         * the state when it is constructed but has not received
         * [onCreate][android.app.Activity.onCreate] yet.
         */
        INITIALIZED,

        /**
         * Created state for a LifecycleOwner. For an [android.app.Activity], this state
         * is reached in two cases:
         *
         *  * after [onCreate][android.app.Activity.onCreate] call;
         *  * **right before** [onStop][android.app.Activity.onStop] call.
         *
         */
        CREATED,

        /**
         * Started state for a LifecycleOwner. For an [android.app.Activity], this state
         * is reached in two cases:
         *
         *  * after [onStart][android.app.Activity.onStart] call;
         *  * **right before** [onPause][android.app.Activity.onPause] call.
         *
         */
        STARTED,

        /**
         * Resumed state for a LifecycleOwner. For an [android.app.Activity], this state
         * is reached after [onResume][android.app.Activity.onResume] is called.
         */
        RESUMED;

        /**
         * Compares if this State is greater or equal to the given `state`.
         *
         * @param state State to compare with
         * @return true if this State is greater or equal to the given `state`
         */
        public fun isAtLeast(state: State): Boolean {
            return compareTo(state) >= 0
        }
    }
}