Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change view before Android App is put to background?

I have an App with two Views, blue view must be shown only when app is in active state (foreground) and the green view must be shown when app is put on background (e.g. clocking on hardware square button on Android).

enter image description here

The following picture shows what I currently get when I put the App in background state:

enter image description here

The following one is what I want to do when App is put on background (on iOS works, on Android not so well):

enter image description here

And this is the implementation.

Please, ignore for the moment that the component for iOS is almost identical to that for Android except for the style of the View. I was doing other tests with different components and for the moment it's okay for me to keep them like this. The difference between the two components (iOS / Android) lies in the style, because in iOS the zIndex works, while in Android I have to use elevation to overlap the views.

const showSecurityScreenFromAppState = appState =>
    ['background', 'inactive'].includes(appState);

const withSecurityScreenIOS = Wrapped => {
    return class WithSecurityScreen extends React.Component {
        constructor(props) {
            super(props);
        }

        state = {
            showSecurityScreen: showSecurityScreenFromAppState(AppState.currentState),
        };

        componentDidMount() {
            AppState.addEventListener('change', this.onChangeAppState);
        }

        componentWillUnmount() {
            AppState.removeEventListener('change', this.onChangeAppState);
        }

        onChangeAppState = nextAppState => {
            const showSecurityScreen = showSecurityScreenFromAppState(nextAppState);

            this.setState({showSecurityScreen});
        };

        //this.state.showSecurityScreen
        render() {
            return (
                <>
                    <View style={[styles.container, {zIndex: this.state.showSecurityScreen ? 1 : -1}]}>
                        <View style={{flex: 1, backgroundColor: globalStyles.colors.customerGreen}}>
                            <View style={styles.upperView}>
                                <Text style={styles.upperViewText}>MyApp</Text>
                            </View>
                        </View>
                    </View>
                    <Wrapped {...this.props}/>
                </>
            );
        }
    };
};

const withSecurityScreenAndroid = Wrapped => {
    return class WithSecurityScreen extends React.Component {
        constructor(props) {
            super(props);
        }

        state = {
            showSecurityScreen: showSecurityScreenFromAppState(AppState.currentState),
        };

        componentDidMount() {
            AppState.addEventListener('change', this.onChangeAppState);
        }

        componentWillUnmount() {
            AppState.removeEventListener('change', this.onChangeAppState);
        }

        onChangeAppState = nextAppState => {
            const showSecurityScreen = showSecurityScreenFromAppState(nextAppState);

            this.setState({showSecurityScreen});
        };

        //this.state.showSecurityScreen
        render() {
            return (
                <>
                    <View style={[styles.container, {elevation: this.state.showSecurityScreen ? 1 : -1}]}>
                        <View style={{flex: 1, backgroundColor: globalStyles.colors.customerGreen}}>
                            <View style={styles.upperView}>
                                <Text style={styles.upperViewText}>MyApp</Text>
                            </View>
                        </View>
                    </View>
                    <Wrapped {...this.props}/>
                </>
            );
        }
    };
};

export const withSecurityScreen =
    Platform.OS === 'ios' ? withSecurityScreenIOS : withSecurityScreenAndroid;

There is not problems in the code, it works very well in iOS, but on Android sometimes it works and sometimes it doesn't. I suspect the cause is that Android OS, when the square button is pressed, it takes a screenshot of the current view and uses it as a background image of the App. Sometimes, however, it happens that the change of layer (elevation) is faster than the Android screenshot and therefore I can see the green screen in the background, as Android is using it as an image.

Is there a way to synchronize these operations? That is: can I make sure that when I press the square button, Android waits for the view to change and then let it go in the background?

Note: I have tested the functioning of elevation when the app is in the foreground, simply inverting the values of elevation when it is in the background or in the foreground, I assure that elevation is working.

Note: in the following animation, when the View in background tasks is white, is a fail. When the View becomes green in background, is a success. Why is random?

enter image description here


Update 1

I realize now that the question may be badly set.

First of all I used incorrect terms to refer to the background status of the apps, the view I speak of in Android is called Recent Apps (or Task View). Then, secondly, in Recent Apps (Task View) what Android does, after pressing the square or circle button, a screenshot of the current view and then shows the Tasks View, using as the image for my App, the screenshot that he just did. The problem is quite annoying, because (as shown in the GIF above) sometimes the screenshot is done AFTER the change of view. Sometimes instead (and often times) the screenshot occurs BEFORE the change of view (the green one).

This is why sometimes in Task View I see the blue screen and sometimes the green one. It's almost a competition problem, let's say. My approach is probably not suitable, I should find another one. Is it possible to manually change the image used in Task View for my App?

like image 742
shogitai Avatar asked Nov 07 '22 08:11

shogitai


1 Answers

You can try like this:

    onChangeAppState = async nextAppState => {
        const showSecurityScreen = await showSecurityScreenFromAppState(nextAppState);

        this.setState({showSecurityScreen});
    };
like image 92
Sebastian Godja Avatar answered Nov 15 '22 06:11

Sebastian Godja