0

I'm developing a Flex Mobile application for some android tablet and until now I've been unable to prevent the Back Button from leaving the application. I still want it's regular functionality, it's just that I don't want it to exit the app. I want the user to do this manually.

Any ideas on how to achieve this? Maybe by catching some event? Any help will be greatly appreciated.

Regards,

Sebastián

ketan
  • 19,129
  • 42
  • 60
  • 98
SebastianT
  • 263
  • 3
  • 14

3 Answers3

1

Here is how I handle it:

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark"
        initialize="init()"
        viewActivate="activate(event)"
        viewDeactivate="deactivate(event)">

<fx:Declarations>
    <fx:Component className="ConfirmExit">
        <s:Callout 
            horizontalPosition="middle"
            verticalPosition="middle">
            <s:VGroup width="100%">

                <s:Label text="Really quit?" />

                <s:HGroup width="100%">

                    <s:Button label="Yes"
                              click="close(true)" />
                    <s:Button label="No"
                              click="close(false)" />
                </s:HGroup>
            </s:VGroup>
        </s:Callout>        
    </fx:Component>
</fx:Declarations>

<fx:Script>
    <![CDATA[
        import spark.events.ViewNavigatorEvent;

        private function activate(event:ViewNavigatorEvent):void {
            // add exit confirmation dialog - Samsung Apps requirement
            if (Capabilities.version.indexOf('AND') >= 0 &&
                Capabilities.manufacturer.search(/Samsung/i) >= 0) {
                _confirmExit.addEventListener(PopUpEvent.CLOSE, handleLeaveCallback, false, 0, true);
                stage.addEventListener(KeyboardEvent.KEY_UP, handleKeyUp, false, 1, true);
            } 
        }

        private function deactivate(event:ViewNavigatorEvent):void {
            _confirmExit.removeEventListener(PopUpEvent.CLOSE, handleLeaveCallback);
            stage.removeEventListener(KeyboardEvent.KEY_UP, handleKeyUp);
        }

        private function handleKeyUp(event:KeyboardEvent):void {
            if (event.keyCode == Keyboard.BACK /* && navigator.length == 1 */) {
                _confirmExit.open(this, true);
                // event.preventDefault();
            }
        }

        private function handleLeaveCallback(event:PopUpEvent):void {
            if (!event.commit)
                return;

            try {
                NativeApplication.nativeApplication.exit();
            } catch (e:Error) {
            }
        }

I.e. don't call any base class methods and use the priority of 1 here:

stage.addEventListener(KeyboardEvent.KEY_UP, handleKeyUp, false, 1, true);
Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
  • Hello Alexander, I had to add `event.cancelable; event.preventDefault();` after the `if (event.keyCode == Keyboard.BACK)` to stop the app from leaving. Could you add that to your answer so I can mark it as the correct one? Thanks for your help. – SebastianT Nov 21 '13 at 19:31
  • I also added the `(navigator.length == 1)` part that Josh mentioned, this so the back button works as usual always but when there's only one `View` left. – SebastianT Nov 21 '13 at 19:41
  • I didn't really need `navigator.length == 1`, because that was my very first View on the stack. – Alexander Farber Nov 23 '13 at 21:02
  • I'm sorry Alexander. I tried this code but it didn't work. It doesn't stop the default actions of the ´Back Key´. I did almost the same thing you did. using viewActivate and viewDeactivate. The only difference was that I didn't use the CallOut component (I'm on Flex 4.5). I have the following: ´private function handleKeyUp(event:KeyboardEvent):void { if (event.keyCode == Keyboard.BACK) { event.preventDefault(); event.stopImmediatePropagation(); } }´. I would really appretiate it if you could help me find out what I am doing wrong. Regards, Sebastián – SebastianT Nov 28 '13 at 20:19
  • Do you use priority 1 when adding the listener? – Alexander Farber Nov 29 '13 at 10:05
  • Yes. I used the exact same code you presented, when setting the listerner. – SebastianT Nov 29 '13 at 13:56
  • I traced it and it enters the if. I tried using event.stopImmediatePropagation(); event.stopPropagation(); event.preventDefault(); and nothing happened. How did you make it work? – SebastianT Nov 29 '13 at 14:02
  • I don't remember, older project, moved to native now. – Alexander Farber Nov 29 '13 at 16:46
1

The only code needed to solve this issue is the following:

<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                            xmlns:s="library://ns.adobe.com/flex/spark">

...

      <fx:Script>
        <![CDATA[

                   ...

            /**
             * Overrides the default backKeyUpHandler method so the event 
             * is stopped when there's only one View left on the navigator's stack. 
             */
            override protected function backKeyUpHandler(event:KeyboardEvent):void
            {               
                if (navigator.length == 1){                 
                    event.stopImmediatePropagation();                   
                    event.preventDefault();                 
                }else{
                    super.backKeyUpHandler(event)
                }
            }

        ]]>
    </fx:Script>

</s:ViewNavigatorApplication>

On the View you should have:

<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark"
        xmlns:componets="componets.*"       
        viewActivate="addKeyListeners(event)"
        viewDeactivate="removeKeyListeners(event)">

...
        <fx:Script>
        <![CDATA[
                          ...
            /**
             * Stops the Back key event.
             */
            private function keyDown(event:KeyboardEvent):void
            {               
                if(event.keyCode == Keyboard.BACK)
                {
                    event.stopImmediatePropagation();                   
                    event.preventDefault();                 
                }
            }
       ]]>
    </fx:Script>

</s:View>

Thanks Alexander and Josh for your help.

Regards,

Sebastián

SebastianT
  • 263
  • 3
  • 14
0

The ViewNavigator will exit the app if there are no more views to pop. You can see how many views are currently being managed by it using ViewNavigator.length. So, theoretically, something like this should work:

stage.addEventListener( KeyboardEvent.KEY_UP, backButtonHandler );

private function backButtonHandler( e:KeyboardEvent ):void {
    if ( e.charCode == Keyboard.BACK && this.navigator.length == 1 ) {
        e.stopImmediatePropagation();
    }
}

Now, that is untested. I believe it should work, however. You may need to check if the length is equal to 0 instead of 1; I'm unsure if the current view counts against the length off the top of my head. That should prevent the back button from running any operation when there are no more views to pop, however.

Josh
  • 8,079
  • 3
  • 24
  • 49
  • Thanks for the help Josh. When or how can one call 'stage' on a Flex Mobile? I tried your advise but it gives me 'Cannot access a property or method of a null object reference' error, when I try to add the listener. – SebastianT Nov 18 '13 at 16:06
  • I did it with 'applicationComplete' instead of 'creationComplete'. The problem is that it didn't work. It still left the application. I tried it with '1'1 and with '0' and in both cases it exited the app. Any more advises? – SebastianT Nov 18 '13 at 16:10
  • `stage` is not available until `Event.ADDED_TO_STAGE` is fired. This should be added to the top level of your application (preferably not even in a view, but in the Application class itself). Try adding `e.preventDefault()` into the conditional. Beyond that, I'm unsure why this isn't working – Josh Nov 18 '13 at 16:26
  • I added the listener in the ViewNavigatorApplication on the "applicationComplete" event. Also added the 'preventDefault()' but the problem persists. Thanks for your help though. – SebastianT Nov 18 '13 at 16:32
  • Maybe try `stage.addEventListener( KeyboardEvent.KEY_UP, backButtonHandler, false, 1, true );` – Alexander Farber Nov 19 '13 at 09:09