Android Tutorial Device Owner / TaskLock / Kiosk apps 2017

Discussion in 'Tutorials & Examples' started by Erel, Jul 18, 2017.

Thread Status:
Not open for further replies.

Similar threads

B4A Tutorial Android "Kiosk mode" tutorial
B4A Question Kiosk
B4A Question Can I avoid the toast message in Kiosk mode?
B4A Question Kiosk mode
B4A Question B4A Kiosk Mode (2017)
  1. Erel

    Erel Administrator Staff Member Licensed User

    [​IMG]

    Starting from Android 5 (API 21) there is better support for kiosk applications.
    Kiosk applications = applications that the user cannot exit from.
    As you can see in this screenshot, the home button and recent apps button are missing. The top notifications drawer is also inaccessible.

    This solution is good for devices that serve a specific purpose. For example point of sale solutions or tourist information stands.

    Device Owner App

    1. The first step is to create an app and provision it as the device owner app. Download the attached example, change its package name to any value you like and run it on the device in Release mode.

    2. Connect the device to the PC in USB debug mode. Open command line and run the following command:
    Replace your.package.name.here with the correct package name.
    Code:
    adb shell dpm set-device-owner your.package.name.here/anywheresoftware.b4a.objects.AdminReceiver2
    [​IMG]

    Existing user accounts on the device must first be removed (Settings - Accounts).

    3. Add this code to the manifest editor (it is already there in the example project):
    Code:
    AddApplicationText(<receiver android:name="anywheresoftware.b4a.objects.AdminReceiver2"
      android:permission=
    "android.permission.BIND_DEVICE_ADMIN">
      <meta-data android:name=
    "android.app.device_admin"
      android:resource=
    "@xml/device_admin" />
      <
    intent-filter>
      <action android:name=
    "android.app.action.DEVICE_ADMIN_ENABLED" />
      </
    intent-filter>
    </receiver>)
    CreateResource(xml, device_admin.xml,
    <device-admin xmlns:android=
    "http://schemas.android.com/apk/res/android">
      <uses-policies>
      <limit-password />
      <reset-password />
      <force-
    lock />
      </uses-policies>
    </device-admin>
    )
    4. See how the example code locks and unlocks the activity.

    Note that for the solution to be more robust it is recommended to make the activity a home launcher activity.

    This is done by adding this code to the manifest editor:
    Code:
    AddActivityText(Main,
    <
    intent-filter>
      <action android:name=
    "android.intent.action.MAIN" />
      <category android:name=
    "android.intent.category.HOME" />
      <category android:name=
    "android.intent.category.DEFAULT" />
    </
    intent-filter>
    )
    With this code you need to click on the home button once and then you will be asked to choose the home launcher app. Choose your app.
    This is important to make sure that your app starts as soon as possible after a restart.
    During development you might prefer to disable it.

    It depends on Administrator library v1.1+: https://www.b4x.com/android/forum/threads/updates-to-internal-libraries.59340/#post-518017
     

    Attached Files:

  2. EvgenyB4A

    EvgenyB4A Active Member Licensed User

    What will happen if it will be any run-time error?
     
    Cableguy likes this.
  3. Erel

    Erel Administrator Staff Member Licensed User

    The program will exit. You can catch unhandled exceptions in Application_Error.

    Another things that you can do for a kiosk application is to run another app with a foreground service that starts the main app with an intent every minute.

    If the app is already running then nothing will happen (assuming that the main activity is visible). If it crashed for some reason then it will be restarted.
    This is a good approach for apps that need to run for very long times.

    The UI cloud devices, for example, use this technique and they run for months.
     
    Peter Simpson and luke2012 like this.
  4. Star-Dust

    Star-Dust Expert Licensed User

    Can you use it to create a screen locker?
     
  5. Erel

    Erel Administrator Staff Member Licensed User

    This is a solution for devices that run a specific task and requires special configuration.
     
    Peter Simpson and Star-Dust like this.
  6. Star-Dust

    Star-Dust Expert Licensed User

    ok, Thank's
     
  7. RauchG

    RauchG Active Member Licensed User

    Code:
    Timer1.Initialize("Timer1"100)        '300)
    It is possible to restart the kiosk mode faster once you have left it.
     
  8. DonManfred

    DonManfred Expert Licensed User

    you´ll not notice a difference between 100 and 300 ms. It is 0.3 seconds (in total)....
     
    RauchG likes this.
  9. EvgenyB4A

    EvgenyB4A Active Member Licensed User

    Is it possible to hide the back button and/or the navigation bar?
     
  10. Erel

    Erel Administrator Staff Member Licensed User

    Yes. Search for immersive mode.

    Note that even with the top bar and the back button visible, the user cannot quit the app.
     
  11. vbigdan

    vbigdan Member Licensed User

    Excellent! I've been implementing the previous version of kiosk for a few years now and this is a breath of fresh air (no home or recent apps presses or swipes down from top)

    Question: is there any way to bypass the ADB element? Any manual way to set up the default account as admin? I've got over 500 tablets in various venues that will benefit from this update, and connecting every one will be possible but difficult.
     
  12. DonManfred

    DonManfred Expert Licensed User

    No
     
  13. coslad

    coslad Well-Known Member Licensed User

  14. DonManfred

    DonManfred Expert Licensed User

    Ask the Author!
     
  15. Star-Dust

    Star-Dust Expert Licensed User

  16. jareal

    jareal Member Licensed User

    I am having a problem with the example of the first post when setup as Home Launcher running on Android 6.0:
    It seems not to Lock the app, and I always receive the toast "Screen unpinned" immediately following the "Screen pinned".

    My devices with Android 5 have no problem, Home Launcher or not.
    My devices with Android 6 and the app not Home Launcher also no problem.

    Looking the unfiltered log of the problematic configuration it shows an intent LOCK_TASK_EXITING that is not present when it works.
    OBS: Only changed the package name to match the name of the Owner App of my devices.

    [Beco.app/Beco.app.main](this:0xb4207000,id:99,api:1,p:4442,c:205) queueBuffer: fps=2.10 dur=22899.45 max=22031.79 min=5.23
    Broadcast: Intent { act=android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED flg=0x40000010 } ordered=false userid=0 callerApp=ProcessRecord{f8314d 844:system/1000}
    setEnabledFunctions functions=mtp,adb, forceRestart=false
    applyAcmFunction - sys.usb.acm_idx=,mAcmPortIdx=
    applyAcmFunction - functions: mtp,adb
    setKeyguardEnabled(true)
    Set focused app to: AppWindowToken{a58629a token=Token{7c01960 ActivityRecord{8ecc963 u0 Beco.app/.main t11}}} old focus=AppWindowToken{a58629a token=Token{7c01960 ActivityRecord{8ecc963 u0 Beco.app/.main t11}}} moveFocusNow=false
    Looking for focus: 7 = Window{56c0571 u0 StatusBar}, flags=-2122055608, canReceive=false
    findFocusedWindow: Found new focus @ 5 = Window{558aaf2 u0 Beco.app/Beco.app.main}
    notifyActivityDrawnForKeyguard: waiting=false Callers=com.android.server.wm.WindowManagerService.handleAppTransitionReadyLocked:10101 com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedInner:10721 com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop:9465 com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLocked:9412 com.android.server.wm.WindowManagerService.executeAppTransition:4601
    Looking for focus: 7 = Window{56c0571 u0 StatusBar}, flags=-2122055608, canReceive=false
    findFocusedWindow: Found new focus @ 5 = Window{558aaf2 u0 Beco.app/Beco.app.main}
    enqueueToast pkg=android callback=android.widget.Toast$TN@cb03d50 duration=1
    noteOperation: allowing code 11 uid 1000 package android
    Show pkg=android callback=android.widget.Toast$TN@cb03d50
    disable statusbar calling PID = 844
    from settings cache , name = lock_screen_show_notifications , value = 1
    [Built-in Screen (type:0)] fps:0.261930,dur:7635.63,max:7619.82,min:15.81
    Broadcast: Intent { act=android.app.action.LOCK_TASK_ENTERING flg=0x10 cmp=Beco.app/anywheresoftware.b4a.objects.AdminReceiver2 (has extras) } ordered=false userid=0 callerApp=ProcessRecord{f8314d 844:system/1000}
    disable statusbar calling PID = 844
    Broadcast: Intent { act=android.app.action.LOCK_TASK_EXITING flg=0x10 cmp=Beco.app/anywheresoftware.b4a.objects.AdminReceiver2 } ordered=false userid=0 callerApp=ProcessRecord{f8314d 844:system/1000}
    mDeviceProvisioned is true
    mDeviceProvisioned is true
    mDeviceProvisioned is true
    updateNotificationShade: mUserSetup=true
    enqueueToast pkg=android callback=android.widget.Toast$TN@cb6416f duration=1
    noteOperation: allowing code 11 uid 1000 package android
    disable1: 0x00000000 -> 0x00000000 (diff1: 0x00000000)
    disable2: 0x00000000 -> 0x00000000 (diff2: 0x00000000)
    from settings cache , name = lock_to_app_exit_locked , value = 0
    disable: < expand icons alerts system_info back home recent clock search quick_settings >
    Add to mViews: android.widget.LinearLayout{f27e74d V.E...... ......I. 0,0-0,0}, this = android.view.WindowManagerGlobal@9e80c7e
    CanvasContext() 0x9b717000
    hardware acceleration is enabled, this = ViewRoot{c63de7c Toast,ident = 39}
    startOperation: allowing code 45 uid 1000 package android
    addWindowToListInOrderLocked: win=Window{f20ef5a u0 Toast} Callers=com.android.server.wm.WindowManagerService.addWindow:2787 com.android.server.wm.Session.addToDisplay:171 android.view.ViewRootImpl.setView:643 android.view.WindowManagerGlobal.addView:319
    Free window: Adding window Window{f20ef5a u0 Toast} at 8 of 8
    [unnamed-205-102](this:0xb4db3000,id:102,api:0,p:-1,c:-1) BufferQueue core=(205:/system/bin/surfaceflinger)
    BDC-Calling onReceive: intent=Intent { act=android.app.action.LOCK_TASK_ENTERING flg=0x10 cmp=Beco.app/anywheresoftware.b4a.objects.AdminReceiver2 (has extras) }, receiver=anywheresoftware.b4a.objects.AdminReceiver2@131d69e
    [unnamed-205-102] this:0xb5cdf4e0, value:0xbed07650, iLen:6
    [unnamed-205-102](this:0xb4db3000,id:102,api:0,p:-1,c:205) connect(C): consumer=(205:/system/bin/surfaceflinger) controlledByApp=false
    [unnamed-205-102] this:0xb5cdf4e0, value:0xbed07670, iLen:6
    [unnamed-205-102](this:0xb4db3000,id:102,api:0,p:-1,c:205) setConsumerName: unnamed-205-102
    [Toast] this:0xb5cdf4e0, value:0xbed076c8, iLen:6
    Beco.app.managerservice not found.
    [Toast](this:0xb4db3000,id:102,api:0,p:-1,c:205) setConsumerName: Toast
    [Toast](this:0xb4db3000,id:102,api:0,p:-1,c:205) setDefaultBufferSize: width=1 height=1
    BDC-RECEIVER handled : 0 / ReceiverData{intent=Intent { act=android.app.action.LOCK_TASK_ENTERING flg=0x10 cmp=Beco.app/anywheresoftware.b4a.objects.AdminReceiver2 (has extras) } packageName=Beco.app resultCode=-1 resultData=null resultExtras=null}
    [StatusBar](this:0xb4f15800,id:9,api:1,p:1162,c:205) queueBuffer: fps=0.26 dur=7671.93 max=7651.01 min=20.92
    Looking for focus: 7 = Window{56c0571 u0 StatusBar}, flags=-2122055608, canReceive=false
    findFocusedWindow: Found new focus @ 5 = Window{558aaf2 u0 Beco.app/Beco.app.main}
    BDC-Calling onReceive: intent=Intent { act=android.app.action.LOCK_TASK_EXITING flg=0x10 cmp=Beco.app/anywheresoftware.b4a.objects.AdminReceiver2 }, receiver=anywheresoftware.b4a.objects.AdminReceiver2@dd0b57f
    Beco.app.managerservice not found.
    BDC-RECEIVER handled : 0 / ReceiverData{intent=Intent { act=android.app.action.LOCK_TASK_EXITING flg=0x10 cmp=Beco.app/anywheresoftware.b4a.objects.AdminReceiver2 } packageName=Beco.app resultCode=-1 resultData=null resultExtras=null}
    [Toast](this:0xb4db3000,id:102,api:0,p:-1,c:205) setDefaultBufferSize: width=204 height=66

    [Beco.app/Beco.app.main](this:0xb4db7800,id:107,api:1,p:4875,c:205) queueBuffer: fps=17.69 dur=2714.15 max=1849.67 min=12.83
    Broadcast: Intent { act=android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED flg=0x40000010 } ordered=false userid=0 callerApp=ProcessRecord{f8314d 844:system/1000}
    Set focused app to: AppWindowToken{408a5a2 token=Token{cf1a4b5 ActivityRecord{6ccc8ec u0 Beco.app/.main t14}}} old focus=AppWindowToken{408a5a2 token=Token{cf1a4b5 ActivityRecord{6ccc8ec u0 Beco.app/.main t14}}} moveFocusNow=false
    setEnabledFunctions functions=mtp,adb, forceRestart=false
    applyAcmFunction - sys.usb.acm_idx=,mAcmPortIdx=
    applyAcmFunction - functions: mtp,adb
    setKeyguardEnabled(true)
    Looking for focus: 7 = Window{56c0571 u0 StatusBar}, flags=-2122055608, canReceive=false
    findFocusedWindow: Found new focus @ 5 = Window{e1eb050 u0 Beco.app/Beco.app.main}
    from settings cache , name = lock_screen_show_notifications , value = 1
    notifyActivityDrawnForKeyguard: waiting=false Callers=com.android.server.wm.WindowManagerService.handleAppTransitionReadyLocked:10101 com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedInner:10721 com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop:9465 com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLocked:9412 com.android.server.wm.WindowManagerService.executeAppTransition:4601
    enqueueToast pkg=android callback=android.widget.Toast$TN@f901dd3 duration=1
    Looking for focus: 7 = Window{56c0571 u0 StatusBar}, flags=-2122055608, canReceive=false
    noteOperation: allowing code 11 uid 1000 package android
    findFocusedWindow: Found new focus @ 5 = Window{e1eb050 u0 Beco.app/Beco.app.main}
    [Built-in Screen (type:0)] fps:1.831054,dur:1092.27,max:1073.71,min:18.56
    mDeviceProvisioned is true
    mDeviceProvisioned is true
    mDeviceProvisioned is true
    updateNotificationShade: mUserSetup=true
    disable statusbar calling PID = 844
    Broadcast: Intent { act=android.app.action.LOCK_TASK_ENTERING flg=0x10 cmp=Beco.app/anywheresoftware.b4a.objects.AdminReceiver2 (has extras) } ordered=false userid=0 callerApp=ProcessRecord{f8314d 844:system/1000}
    setKeyguardEnabled(false)
    BDC-Calling onReceive: intent=Intent { act=android.app.action.LOCK_TASK_ENTERING flg=0x10 cmp=Beco.app/anywheresoftware.b4a.objects.AdminReceiver2 (has extras) }, receiver=anywheresoftware.b4a.objects.AdminReceiver2@6b3b1bf
    Beco.app.managerservice not found.
    BDC-RECEIVER handled : 0 / ReceiverData{intent=Intent { act=android.app.action.LOCK_TASK_ENTERING flg=0x10 cmp=Beco.app/anywheresoftware.b4a.objects.AdminReceiver2 (has extras) } packageName=Beco.app resultCode=-1 resultData=null resultExtras=null}
     
    Last edited: Sep 25, 2017
  17. Erel

    Erel Administrator Staff Member Licensed User

    It is probably not related, however it is recommended to use lower case package names.

    The example works fine here running on Android 8 (and also worked with 7).

    Might be a bug in Android 6. Note that you can run a kiosk app without setting it as the home launcher. The downside is that the default launcher will show for a few seconds when the device is restarted (until the Reboot service is started).
     
    jareal likes this.
  18. vbigdan

    vbigdan Member Licensed User

    Is it possible to read if the kiosk mode (startLockTask) has been set?
     
  19. Erel

    Erel Administrator Staff Member Licensed User

    No. You should keep a global variable with its state.
     
  20. vbigdan

    vbigdan Member Licensed User

    Thanks. Is it possible to read if the owner has been set?
     
Thread Status:
Not open for further replies.
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice