/** * Copyright (c) 2015-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format * @flow */ 'use strict'; const MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim'); const NativeEventEmitter = require('NativeEventEmitter'); const NativeModules = require('NativeModules'); const RCTAppState = NativeModules.AppState; const logError = require('logError'); const invariant = require('fbjs/lib/invariant'); /** * `AppState` can tell you if the app is in the foreground or background, * and notify you when the state changes. * * See http://facebook.github.io/react-native/docs/appstate.html */ class AppState extends NativeEventEmitter { _eventHandlers: Object; currentState: ?string; isAvailable: boolean = true; constructor() { super(RCTAppState); this.isAvailable = true; this._eventHandlers = { change: new Map(), memoryWarning: new Map(), }; // TODO: Remove the 'active' fallback after `initialAppState` is exported by // the Android implementation. this.currentState = RCTAppState.initialAppState || 'active'; let eventUpdated = false; // TODO: this is a terrible solution - in order to ensure `currentState` // prop is up to date, we have to register an observer that updates it // whenever the state changes, even if nobody cares. We should just // deprecate the `currentState` property and get rid of this. this.addListener('appStateDidChange', appStateData => { eventUpdated = true; this.currentState = appStateData.app_state; }); // TODO: see above - this request just populates the value of `currentState` // when the module is first initialized. Would be better to get rid of the // prop and expose `getCurrentAppState` method directly. RCTAppState.getCurrentAppState(appStateData => { // It's possible that the state will have changed here & listeners need to be notified if (!eventUpdated && this.currentState !== appStateData.app_state) { this.currentState = appStateData.app_state; this.emit('appStateDidChange', appStateData); } }, logError); } // TODO: now that AppState is a subclass of NativeEventEmitter, we could // deprecate `addEventListener` and `removeEventListener` and just use // addListener` and `listener.remove()` directly. That will be a breaking // change though, as both the method and event names are different // (addListener events are currently required to be globally unique). /** * Add a handler to AppState changes by listening to the `change` event type * and providing the handler. * * See http://facebook.github.io/react-native/docs/appstate.html#addeventlistener */ addEventListener(type: string, handler: Function) { invariant( ['change', 'memoryWarning'].indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type, ); if (type === 'change') { this._eventHandlers[type].set( handler, this.addListener('appStateDidChange', appStateData => { handler(appStateData.app_state); }), ); } else if (type === 'memoryWarning') { this._eventHandlers[type].set( handler, this.addListener('memoryWarning', handler), ); } } /** * Remove a handler by passing the `change` event type and the handler. * * See http://facebook.github.io/react-native/docs/appstate.html#removeeventlistener */ removeEventListener(type: string, handler: Function) { invariant( ['change', 'memoryWarning'].indexOf(type) !== -1, 'Trying to remove listener for unknown event: "%s"', type, ); if (!this._eventHandlers[type].has(handler)) { return; } this._eventHandlers[type].get(handler).remove(); this._eventHandlers[type].delete(handler); } } if (__DEV__ && !RCTAppState) { class MissingNativeAppStateShim extends MissingNativeEventEmitterShim { constructor() { super('RCTAppState', 'AppState'); } get currentState(): ?string { this.throwMissingNativeModule(); } addEventListener(...args: Array) { this.throwMissingNativeModule(); } removeEventListener(...args: Array) { this.throwMissingNativeModule(); } } // This module depends on the native `RCTAppState` module. If you don't // include it, `AppState.isAvailable` will return `false`, and any method // calls will throw. We reassign the class variable to keep the autodoc // generator happy. AppState = new MissingNativeAppStateShim(); } else { AppState = new AppState(); } module.exports = AppState;