2

I'd like to keep device on and avoid unloading my application from memory even while there is no user activity. Something like service. I made module like How to check if network is available on Android and iOS ( Delphi XE5 ) but system crushes when I run SetWakeLock:

unit Android.PowerManager;

interface

function SetWakeLock : boolean;
procedure ReleaseWakeLock;

implementation

uses
  System.SysUtils,
  Androidapi.JNI,
  Androidapi.JNIBridge,
  Androidapi.JNI.GraphicsContentViewText,
  Androidapi.JNI.JavaTypes,
  FMX.Helpers.Android;

type
  JPowerManager = interface;
  JWakeLock = interface;

  JWakeLockClass = interface(JObjectClass)
  ['{4CF7A13D-15A9-4DEE-8CA7-66600C188CB7}']
  end;

  [JavaSignature('android/os/PowerManager/WakeLock')]
  JWakeLock = interface(JObject)
  ['{55983EDC-782F-490A-BF0C-12207EB7829E}']
    {Methods}
    procedure acquire; cdecl;
    procedure release; cdecl;
    function isHeld: Boolean; cdecl;
  end;
  TJWakeLock = class(TJavaGenericImport<JWakeLockClass, JWakeLock>) end;

  JPowerManagerClass = interface(JObjectClass)
  ['{B127DD4E-1DA6-49E7-98BA-5966DC7E26FA}']
  end;

  [JavaSignature('android/os/PowerManager')]
  JPowerManager = interface(JObject)
  ['{241C3B3D-3DF0-489B-A33E-3CD7F5D26313}']
    {Methods}
    function newWakeLock(levelAndFlags: integer; tag: JString): JWakeLock; cdecl;
  end;
  TJPowerManager = class(TJavaGenericImport<JPowerManagerClass, JPowerManager>) end;

function GetPowerManager: JPowerManager;
var
  PowerServiceNative: JObject;
begin
  PowerServiceNative := SharedActivityContext.getSystemService(TJContext.JavaClass.POWER_SERVICE);
  if not Assigned(PowerServiceNative) then
    raise Exception.Create('Could not locate Power Service');
  Result := TJPowerManager.Wrap(
    (PowerServiceNative as ILocalObject).GetObjectID);
  if not Assigned(Result) then
    raise Exception.Create('Could not access Power Manager');
end;

var fWakeLock : JWakeLock = nil;

function SetWakeLock : boolean;
var
  PowerManager: JPowerManager;
begin
  result := fWakeLock<>nil;
  if result then begin
    PowerManager := GetPowerManager;
    fWakeLock := PowerManager.newWakeLock(1,StringToJString('VC'));  //PARTIAL_WAKE_LOCK =1
    Result := fWakeLock<>nil;
    if Result then begin
       fWakeLock.acquire;
       Result := fWakeLock.IsHeld;
    end;
  end else if not fWakeLock.IsHeld then
    fWakeLock.acquire;
end;

procedure ReleaseWakeLock;
begin
  if fWakeLock<>nil then begin
    fWakeLock.release;
  end;
end;

end.
Community
  • 1
  • 1
chshkhr
  • 23
  • 1
  • 1
  • 5

6 Answers6

7

Ignoring the wrong-looking logic that I cited in a comment, you're not referring to a nested class correctly in the interface declaration.

This unit works for me. Note I'm using a screen wake lock (which is deprecated, but still works).

unit Android.JNI.PowerManager;

interface

function AcquireWakeLock : Boolean;
procedure ReleaseWakeLock;

implementation

uses
  System.SysUtils,
  Androidapi.JNI,
  Androidapi.JNIBridge,
  Androidapi.JNI.GraphicsContentViewText,
  Androidapi.JNI.JavaTypes,
  FMX.Helpers.Android;

type
  JPowerManager = interface;
  JWakeLock = interface;

  JWakeLockClass = interface(JObjectClass)
  ['{918E171F-CDB8-4464-9507-F49272CE7636}']
  end;

  [JavaSignature('android/os/PowerManager$WakeLock')]
  JWakeLock = interface(JObject)
  ['{D17B1136-FA15-4AEB-85B1-2D490F0FD320}']
    {Methods}
    procedure acquire; cdecl;
    procedure release; cdecl;
    function isHeld: Boolean; cdecl;
  end;
  TJWakeLock = class(TJavaGenericImport<JWakeLockClass, JWakeLock>) end;

  JPowerManagerClass = interface(JObjectClass)
  ['{7D0696A2-ADEA-4158-AE1F-5E720DEDBCF9}']
    {Property methods}
    function _GetFULL_WAKE_LOCK: Integer; cdecl;
    function _GetSCREEN_BRIGHT_WAKE_LOCK: Integer; cdecl;
    function _GetSCREEN_DIM_WAKE_LOCK: Integer; cdecl;
    function _GetPARTIAL_WAKE_LOCK: Integer; cdecl;
    {Properties}
    //Keep screen on bright & keyboard on
    //Deprecated in API level 17 - Jelly Bean MR1
    property FULL_WAKE_LOCK: Integer read _GetFULL_WAKE_LOCK;
    //Keep screen on bright
    //Deprecated in API level 13 - Honeycomb MR2
    property SCREEN_BRIGHT_WAKE_LOCK: Integer read _GetSCREEN_BRIGHT_WAKE_LOCK;
    //Keep screen on dim
    //Deprecated in API level 17 - Jelly Bean MR1
    property SCREEN_DIM_WAKE_LOCK: Integer read _GetSCREEN_DIM_WAKE_LOCK;
    //Keep CPU running, screen & keyboard can go off
    property PARTIAL_WAKE_LOCK: Integer read _GetPARTIAL_WAKE_LOCK;
  end;

  [JavaSignature('android/os/PowerManager')]
  JPowerManager = interface(JObject)
  ['{DEAED658-4353-4D17-B0A3-8179E48BE87F}']
    {Methods}
    function newWakeLock(levelAndFlags: Integer; tag: JString): JWakeLock; cdecl;
  end;
  TJPowerManager = class(TJavaGenericImport<JPowerManagerClass, JPowerManager>) end;

function GetPowerManager: JPowerManager;
var
  PowerServiceNative: JObject;
begin
  PowerServiceNative := SharedActivityContext.getSystemService(
    TJContext.JavaClass.POWER_SERVICE);
  if not Assigned(PowerServiceNative) then
    raise Exception.Create('Could not locate Power Service');
  Result := TJPowerManager.Wrap(
    (PowerServiceNative as ILocalObject).GetObjectID);
  if not Assigned(Result) then
    raise Exception.Create('Could not access Power Manager');
end;

var
  WakeLock: JWakeLock = nil;

function AcquireWakeLock: Boolean;
var
  PowerManager: JPowerManager;
begin
  Result := Assigned(WakeLock);
  if not Result then
  begin
    PowerManager := GetPowerManager;
    WakeLock := PowerManager.newWakeLock(
      TJPowerManager.JavaClass.SCREEN_BRIGHT_WAKE_LOCK,
      StringToJString('Delphi'));
    Result := Assigned(WakeLock);
  end;
  if Result then
  begin
    if not WakeLock.IsHeld then
    begin
      WakeLock.acquire;
      Result := WakeLock.isHeld
    end;
  end;
end;

procedure ReleaseWakeLock;
begin
  if Assigned(WakeLock) then
  begin
    WakeLock.release;
    WakeLock := nil
  end;
end;

end.
blong
  • 2,145
  • 13
  • 23
  • I think one more correction is need: procedure ReleaseWakeLock; begin if Assigned(WakeLock) then begin WakeLock.release; WakeLock := nil; end; end; – chshkhr Sep 26 '13 at 12:23
  • Yes, probably a good idea to tidy up when done. I'll edit my post accordingly. – blong Sep 26 '13 at 22:07
3

Did you add in the android.permission.WAKELOCK permission (shown as Wake lock in Delphi)?

bozzmob
  • 12,364
  • 16
  • 50
  • 73
blong
  • 2,145
  • 13
  • 23
  • Yes, Wake lock permission is set. I can't manage to debug but by commenting code lines I found that crush happens on GetPowerManager – chshkhr Sep 26 '13 at 09:54
  • Probably something to do with your Boolean logic. If fWakeLock is nil, you branch downwards and call isHeld, it seems. – blong Sep 26 '13 at 10:27
2

Thanks a lot to blong for solution. For it began to work in Delphi Berlin, I redid the module code. I hope this is useful.

It needs to enable android.permission.WAKELOCK permission in your project.

unit Android.JNI.PowerManager;

interface

function AcquireWakeLock: Boolean;
procedure ReleaseWakeLock;

implementation

uses
  System.SysUtils,
  Androidapi.JNI,
  Androidapi.JNIBridge,
  Androidapi.JNI.GraphicsContentViewText,
  Androidapi.JNI.JavaTypes,
  Androidapi.Helpers,
  Androidapi.JNI.Os, // added in Berlin
  FMX.Helpers.Android;

//type
  // *** this is in Androidapi.JNI.Os
  // JPowerManager = interface;
  // JWakeLock = interface;

  // *** this is in Androidapi.JNI.Os
  // JWakeLockClass = interface(JObjectClass)
  // ['{918E171F-CDB8-4464-9507-F49272CE7636}']
  // end;

  // *** this is in Androidapi.JNI.Os
  // [JavaSignature('android/os/PowerManager$WakeLock')]
  // JWakeLock = interface(JObject)
  // ['{D17B1136-FA15-4AEB-85B1-2D490F0FD320}']
  // { Methods }
  // procedure acquire; cdecl;
  // procedure release; cdecl;
  // function isHeld: Boolean; cdecl;
  // end;
  // TJWakeLock = class(TJavaGenericImport<JWakeLockClass, JWakeLock>)
  // end;

  // *** this is in Androidapi.JNI.Os
  // JPowerManagerClass = interface(JObjectClass)
  // ['{7D0696A2-ADEA-4158-AE1F-5E720DEDBCF9}']
  // { Property methods }
  // function _GetFULL_WAKE_LOCK: Integer; cdecl;
  // function _GetSCREEN_BRIGHT_WAKE_LOCK: Integer; cdecl;
  // function _GetSCREEN_DIM_WAKE_LOCK: Integer; cdecl;
  // function _GetPARTIAL_WAKE_LOCK: Integer; cdecl;
  // { Properties }
  // // Keep screen on bright & keyboard on
  // // Deprecated in API level 17 - Jelly Bean MR1
  // property FULL_WAKE_LOCK: Integer read _GetFULL_WAKE_LOCK;
  // // Keep screen on bright
  // // Deprecated in API level 13 - Honeycomb MR2
  // property SCREEN_BRIGHT_WAKE_LOCK: Integer read _GetSCREEN_BRIGHT_WAKE_LOCK;
  // // Keep screen on dim
  // // Deprecated in API level 17 - Jelly Bean MR1
  // property SCREEN_DIM_WAKE_LOCK: Integer read _GetSCREEN_DIM_WAKE_LOCK;
  // // Keep CPU running, screen & keyboard can go off
  // property PARTIAL_WAKE_LOCK: Integer read _GetPARTIAL_WAKE_LOCK;
  // end;

  // *** this is in Androidapi.JNI.Os
  // [JavaSignature('android/os/PowerManager')]
  // JPowerManager = interface(JObject)
  // ['{DEAED658-4353-4D17-B0A3-8179E48BE87F}']
  // { Methods }
  // function newWakeLock(levelAndFlags: Integer; tag: JString): JWakeLock; cdecl;
  // end;
  // TJPowerManager = class(TJavaGenericImport<JPowerManagerClass, JPowerManager>)
  // end;

function GetPowerManager: JPowerManager;
var
  PowerServiceNative: JObject;
begin
  PowerServiceNative := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.POWER_SERVICE);
  if not Assigned(PowerServiceNative) then
    raise Exception.Create('Could not locate Power Service');
  Result := TJPowerManager.Wrap((PowerServiceNative as ILocalObject).GetObjectID);
  if not Assigned(Result) then
    raise Exception.Create('Could not access Power Manager');
end;

var
  // *** this is in Androidapi.JNI.Os
  // WakeLock: JWakeLock = nil;
  WakeLock: JPowerManager_WakeLock = nil;

function AcquireWakeLock: Boolean;
var
  PowerManager: JPowerManager;
begin
  Result := Assigned(WakeLock);
  if not Result then
  begin
    PowerManager := GetPowerManager;
    WakeLock := PowerManager.newWakeLock(TJPowerManager.JavaClass.SCREEN_BRIGHT_WAKE_LOCK,
      StringToJString('Delphi'));
    Result := Assigned(WakeLock);
  end;
  if Result then
  begin
    if not WakeLock.isHeld then
    begin
      WakeLock.acquire;
      Result := WakeLock.isHeld
    end;
  end;
end;

procedure ReleaseWakeLock;
begin
  if Assigned(WakeLock) then
  begin
    WakeLock.release;
    WakeLock := nil
  end;
end;

end.
Community
  • 1
  • 1
Pax Beach
  • 2,059
  • 1
  • 20
  • 27
1

You Need:

1) setting the Project Options, Uses Permissions, Wake lock = True

2) Adding Android.JNI.PowerManager to the uses clause

3) call:

 AcquireWakeLock; // at start up.

 ReleaseWakeLock; // at shutdown.

from the Android.JNI.PowerManager Unit

Ingo
  • 5,239
  • 1
  • 30
  • 24
0

When compiling for Android on XE6, add Androidapi.helpers to the uses clause or it can't find the StringToJString routine.

VMAtm
  • 27,943
  • 17
  • 79
  • 125
Chester
  • 11
  • 1
0

I tested it on XE8 and works perfect, just add FMX.Platform.Android and Androidapi.Helpers to uses. Here is the IOS version.

uses
  iOSapi.UIKit;

procedre SetSleep(Enable:Boolean);
    var
      UIApp : UIApplication;
    begin
      UIApp := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication);
      UIApp.setIdleTimerDisabled(Enable); //Change it to false on app close
    end;
Morrismx
  • 1
  • 2