16

How can I make my Android app react to the back-button?

Is there something as high-level VCL's TApplicationEvents to handle it, or do I need to dive deep into low-level Android-specific stuff here?

Right now, most of the demo applications have an on-screen back button to go back to a previous screen. Pressing the psysical button always seems to quit the app, and in some situations it results in an access violation.

Wouter van Nifterick
  • 23,603
  • 7
  • 78
  • 122
  • 1
    More comments about using vkHardwareBack at http://docwiki.embarcadero.com/RADStudio/XE5/en/Creating_an_Android_App. That page mentions the technique used in this sample: http://docwiki.embarcadero.com/RADStudio/XE5/en/FireMonkey_Mobile_Application_Templates – nachbar Sep 20 '13 at 02:41

6 Answers6

38

In the form's OnKey... events, the Key parameter is vkHardwareBack on Android. For example:

uses
  FMX.Platform, FMX.VirtualKeyboard;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
var
  FService : IFMXVirtualKeyboardService;
begin
  if Key = vkHardwareBack then
  begin
    TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(FService));
    if (FService <> nil) and (vksVisible in FService.VirtualKeyBoardState) then
    begin
      // Back button pressed, keyboard visible, so do nothing...
    end else
    begin
      // Back button pressed, keyboard not visible or not supported on this platform, lets exit the app...
      if MessageDlg('Exit Application?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbOK, TMsgDlgBtn.mbCancel], -1) = mrOK then
      begin
        // Exit application here...
      end else
      begin
        // They changed their mind, so ignore the Back button press...
        Key := 0;
      end;
    end;
  end
  ...
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • From my tests, the only way this works on current version of Delphi (XE5) is if you make the Key := 0; even if the user presses "OK, exit". The FormKeyUp is called twice (I don't know why) and the second time the MessageDlg is shown (tried to be shown) while the app closes so the whole application hangs and can't be restarted. – ioan ghip Feb 06 '14 at 21:43
  • 6
    In XE6 and later the `vksVisible` is replaced with [TVirtualKeyboardState.Visible](http://docwiki.embarcadero.com/Libraries/en/FMX.Types.TVirtualKeyBoardState). – LU RD Oct 07 '14 at 09:08
  • Remy, you may update your code according to my answer. Tested with XE9, – Sergey Krasilnikov Aug 18 '15 at 09:24
  • 1
    No, he must not update his answer because OP asked for XE5 ^^, but @LU RD provided the only required modification (at least for me with XE7...) – Darkendorf Feb 11 '16 at 15:19
10

For future reference to anyone trying to make sense of this..

if Key = vkHardwareBack then
    begin
      // your code here
      key := 0;
end;

The key := 0; is the secret to stop the app from closing..

This goes in the forms OnKeyUp event

8

Here is an updated code for Remy's answer (works with Seattle):

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
var
  FService : IFMXVirtualKeyboardService;
begin
  if Key = vkHardwareBack then
  begin
    TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(FService));
    if (FService <> nil) and (TVirtualKeyboardState.Visible in FService.VirtualKeyBoardState) then
    begin
      // Back button pressed, keyboard visible, so do nothing...
    end else
    begin
      Key := 0;
      // Back button pressed, keyboard not visible or not supported on this platform, lets exit the app...
      MessageDlg('Exit Application?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbOK, TMsgDlgBtn.mbCancel], -1, OnCloseDialog);
    end;
  end;
end;

procedure TForm1.OnCloseDialog(Sender: TObject; const AResult: TModalResult);
begin
  if AResult = mrOK then
    Close;
end;
2

Going back to the previous screen depends on your application design.

  • If you used TTabControl for displaying pages, you can navigate to the previous TTabItem.

  • If you used TForms for displaying pages, you must use Close() procedure for closing the current form and going back to the previous screen.

Kromster
  • 7,181
  • 7
  • 63
  • 111
suathd
  • 51
  • 1
1

Try this:

uses FMX.Platform,FMX.VirtualKeyboard,FMX.Helpers.Android;

procedure THeaderFooterForm.FormKeyUp(Sender: TObject; var Key: Word;
  var KeyChar: Char; Shift: TShiftState);

var FService : IFMXVirtualKeyboardService; 
begin
  if Key = vkHardwareBack then
    begin
      TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(FService));
      if (FService <> nil) and (vksVisible in FService.VirtualKeyBoardState) then
        begin
          // Back button pressed, keyboard visible, so do nothing...
        end
      else
        begin
          if MessageDlg('Exit Application?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbOK, TMsgDlgBtn.mbCancel], -1) = mrOK then
            begin
            // Exit application here...
              SharedActivity.Finish;
            end;
        end;
     end
  else
    // Menu button pressed
    if Key = sgiUpRightLong then
      begin
        showmessage('Menu button pressed');
      end;
end;
Ingo
  • 5,239
  • 1
  • 30
  • 24
  • 1
    In XE6 and later the `vksVisible` is replaced with [TVirtualKeyboardState.Visible](http://docwiki.embarcadero.com/Libraries/en/FMX.Types.TVirtualKeyBoardState). – LU RD Oct 07 '14 at 09:01
1

The Card View Wizard 1.0 available from GetIt Package Manager (https://getitnow.embarcadero.com/card-view-wizard/) has this code (I only changed the plain "// do nothing comment" there to be more descriptive) for exiting the app only when a set of startup card sequence is still or back on the 1st card, else navigate to previous card:

procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char;
  Shift: TShiftState);
var
  FService : IFMXVirtualKeyboardService;
begin
  if Key = vkHardwareBack then
  begin
    TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(FService));
    if (FService <> nil) and (TVirtualKeyboardState.Visible in FService.VirtualKeyBoardState) then
      begin
        // Back button pressed, keyboard visible, so do nothing...
      end
    else
      begin
        if WizardTabControl.ActiveTab <> TabItem1 then
          begin
            WizardTabControl.SetActiveTabWithTransitionAsync(WizardTabControl.Tabs[WizardTabControl.TabIndex-1],TTabTransition.Slide,TTabTransitionDirection.Reversed,nil);
            Key := 0;
          end;
      end;
  end
end;

Of course as other answers show you could also prompt the user in case they accidentally tried to exit the application, to not proceed.

George Birbilis
  • 2,782
  • 2
  • 33
  • 35
  • for more on Card View Wizard, see https://blogs.embarcadero.com/modernize-your-multi-device-fire-monkey-app-easy-to-use-card-view-wizard-layout-template/ – George Birbilis Sep 20 '21 at 15:44