fix(Android|PiP): do not invoke 'enterPictureInPicture' in PAUSED state

Activity.enterPictureInPictureMode method must be invoked synchronously
on userLeaveHint callback in order to be sure that the current Activity
is still visible (does not transit to PAUSED state). Previously if the
asynchronous processing would be delayed enough for the Activity to go
into the PAUSED state it will be too late to go into the PiP mode.
This commit is contained in:
paweldomas
2018-05-02 17:06:24 +02:00
committed by Saúl Ibarra Corretgé
parent effd3728b6
commit 565fd37f28
10 changed files with 165 additions and 175 deletions
@@ -9,16 +9,3 @@
* @public
*/
export const ENTER_PICTURE_IN_PICTURE = Symbol('ENTER_PICTURE_IN_PICTURE');
/**
* The type of redux action to set the {@code EventEmitter} subscriptions
* utilized by the feature picture-in-picture.
*
* {
* type: _SET_EMITTER_SUBSCRIPTIONS,
* emitterSubscriptions: Array|undefined
* }
*
* @protected
*/
export const _SET_EMITTER_SUBSCRIPTIONS = Symbol('_SET_EMITTER_SUBSCRIPTIONS');
@@ -4,10 +4,7 @@ import { NativeModules } from 'react-native';
import { Platform } from '../../base/react';
import {
ENTER_PICTURE_IN_PICTURE,
_SET_EMITTER_SUBSCRIPTIONS
} from './actionTypes';
import { ENTER_PICTURE_IN_PICTURE } from './actionTypes';
/**
* Enters (or rather initiates entering) picture-in-picture.
@@ -47,22 +44,3 @@ export function enterPictureInPicture() {
}
};
}
/**
* Sets the {@code EventEmitter} subscriptions utilized by the feature
* picture-in-picture.
*
* @param {Array<Object>} emitterSubscriptions - The {@code EventEmitter}
* subscriptions to be set.
* @protected
* @returns {{
* type: _SET_EMITTER_SUBSCRIPTIONS,
* emitterSubscriptions: Array<Object>
* }}
*/
export function _setEmitterSubscriptions(emitterSubscriptions: ?Array<Object>) {
return {
type: _SET_EMITTER_SUBSCRIPTIONS,
emitterSubscriptions
};
}
@@ -1,6 +1,3 @@
export * from './actions';
export * from './actionTypes';
export * from './components';
import './middleware';
import './reducer';
@@ -1,70 +0,0 @@
// @flow
import { DeviceEventEmitter } from 'react-native';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../../app';
import { MiddlewareRegistry } from '../../base/redux';
import { enterPictureInPicture, _setEmitterSubscriptions } from './actions';
import { _SET_EMITTER_SUBSCRIPTIONS } from './actionTypes';
/**
* Middleware that handles Picture-in-Picture requests. Currently it enters
* the native PiP mode on Android, when requested.
*
* @param {Store} store - Redux store.
* @returns {Function}
*/
MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case APP_WILL_MOUNT:
return _appWillMount(store, next, action);
case APP_WILL_UNMOUNT:
store.dispatch(_setEmitterSubscriptions(undefined));
break;
case _SET_EMITTER_SUBSCRIPTIONS: {
// Remove the current/old EventEmitter subscriptions.
const { emitterSubscriptions } = store.getState()['features/pip'];
if (emitterSubscriptions) {
for (const emitterSubscription of emitterSubscriptions) {
// XXX We may be removing an EventEmitter subscription which is
// in both the old and new Array of EventEmitter subscriptions!
// Thankfully, we don't have such a practical use case at the
// time of this writing.
emitterSubscription.remove();
}
}
break;
}
}
return next(action);
});
/**
* Notifies the feature pip that the action {@link APP_WILL_MOUNT} is being
* dispatched within a specific redux {@code store}.
*
* @param {Store} store - The redux store in which the specified {@code action}
* is being dispatched.
* @param {Dispatch} next - The redux dispatch function to dispatch the
* specified {@code action} to the specified {@code store}.
* @param {Action} action - The redux action {@code APP_WILL_MOUNT} which is
* being dispatched in the specified {@code store}.
* @private
* @returns {*} The value returned by {@code next(action)}.
*/
function _appWillMount({ dispatch }, next, action) {
dispatch(_setEmitterSubscriptions([
// Android's onUserLeaveHint activity lifecycle callback
DeviceEventEmitter.addListener(
'onUserLeaveHint',
() => dispatch(enterPictureInPicture()))
]));
return next(action);
}
@@ -1,17 +0,0 @@
// @flow
import { ReducerRegistry } from '../../base/redux';
import { _SET_EMITTER_SUBSCRIPTIONS } from './actionTypes';
ReducerRegistry.register('features/pip', (state = {}, action) => {
switch (action.type) {
case _SET_EMITTER_SUBSCRIPTIONS:
return {
...state,
emitterSubscriptions: action.emitterSubscriptions
};
}
return state;
});