Android Question [B4XPages] How to update Kiosk app remotely

Mike1970

Well-Known Member
Licensed User
Longtime User
Hi everyone, I'm doing some researches for a customer project that needs a kiosk.
So I bought an Android PC and now I'm studying all the necessary stuff to do what I need. In particular I already saw the Kiosk Tutorial and the Immersive Mode Tutorial.

I still miss some pieces to get all working robustlly... on of them is:
Is it possibile to update my kiosk app remotely (ota-style)? (since the account must be removed from the device and playstore cannot be used)

Thanks in advance
 

DonManfred

Expert
Licensed User
Longtime User
I guess you need to use adb dpm again to remove it.
B4X:
adb shell dpm set-device-owner your.package.name.here/anywheresoftware.b4a.objects.AdminReceiver2
check adb dpm docs on how to remove the deviceowner.

i don´t think you can do it remotely.
 
Upvote 0

Mike1970

Well-Known Member
Licensed User
Longtime User
I guess you need to use adb dpm again to remove it.
B4X:
adb shell dpm set-device-owner your.package.name.here/anywheresoftware.b4a.objects.AdminReceiver2
check adb dpm docs on how to remove the deviceowner.

i don´t think you can do it remotely.
but in this way I cannot use the Kiosk functionallity anymore, am I right? (since it is a requirement in the Tutorial)
 
Upvote 0

Mike1970

Well-Known Member
Licensed User
Longtime User
yes (i GUESS! NEVER used Kioskapps), but you can then update the app and set the deviceowner again.
uhm ok, let's assume that this is the right route... how can I do it remotely (Imagine to have the kiosk 200km away)?
Exposing the ADB port to the world does not seem to be a safe thing 😂😂

And more over, how can i send the update .apk to the device automatically? (I hope it is possible)
 
Upvote 0

f0raster0

Well-Known Member
Licensed User
Longtime User
If internet connection is available:
I provide a link to my APK on my website (in reallity on my usaas webapplication). When my client accesses the website and clicks the link, myapp.apk is downloaded onto the kiosk tablet..then they simple click to install the app
 
Upvote 0

Mike1970

Well-Known Member
Licensed User
Longtime User
If internet connection is available:
I provide a link to my APK on my website (in reallity on my usaas webapplication). When my client accesses the website and clicks the link, myapp.apk is downloaded onto the kiosk tablet..
Ok so it cannot be done automatically like a play store update

there must be an operator that "knows what he is doing" and must manually install the .apk from the storage. Did I understand right?
 
Upvote 0

f0raster0

Well-Known Member
Licensed User
Longtime User
@Filippo created his own "store" if I'm correct, maybe in his store the app can be auto updated.

About the "operator", I created a website/doc too :) - once it is donwloaded it ask to run..

Edit:
 
Last edited:
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
1) Make the Kiosk launcher as the device owner, that can check\download the updated app from your server
2) Make the second (updateable) app with needed project logic. Include the app into the allowed apps list of the Kiosk.
3) Update p.2 by p.1 when needed, execute update, user will have to confirm the update. Check the version of p.2 and start it by p.1
 
Upvote 0

Mike1970

Well-Known Member
Licensed User
Longtime User
1) Make the Kiosk launcher as the device owner, that can check\download the updated app from your server
2) Make the second (updateable) app with needed project logic. Include the app into the allowed apps list of the Kiosk.
3) Update p.2 by p.1 when needed, execute update, user will have to confirm the update. Check the version of p.2 and start it by p.1
So, just to know if I understood right.

I need TWO apps.
One of them could be like a "watchdog" that have the job to check for updates, download them from the server. This app is the one that will be nominated as "device owner" and will start automatically at the device startup.

The other app must the be the ACTUAL app I need that can be upgraded (with user confirmation) by the watchdog.

At this point I've one question:
Since the kiosk mode will launch the watchdog app automatically, WHO will start the actual Application? I imagine that will be the watchdog app to do so.. correct?
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Correct.

B4X:
Sub Activity_Click
    If All_isChecked = True Then
        others.StartApp(Starter.App2Package)
        Activity.Finish
    End If
End Sub


others:
Sub StartApp (package As String)
    Dim In As Intent
    Dim pm As PackageManager

    In = pm.GetApplicationIntent(package)

    Dim List1 As List
    List1.Initialize

    List1 = QueryIntent(In)

    If In.IsInitialized Then
        Try
            StartActivity(In)
            Log(package & " was started...")
        Catch
            ToastMessageShow("Starting error...", False)
        End Try
    Else
        ToastMessageShow("Starting error (system)...", False)
    End If
End Sub

Sub QueryIntent(Intent1 As Intent) As List
    Dim r As Reflector
    r.Target = r.GetContext
    r.Target = r.RunMethod("getPackageManager")
    Dim list1 As List
    Try
        list1 = r.RunMethod4("queryIntentActivities", Array As Object(Intent1, 0), Array As String("android.content.Intent", "java.lang.int"))
    Catch
    End Try
    Return list1
End Sub

Manifest of the Kiosk app:
'This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: http://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="33"/>
<supports-screens android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="true"
    android:anyDensity="true"/>
)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
'End of default text.
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>)
AddReceiverText(reboot, <intent-filter>
    <action android:name="android.intent.action.PACKAGE_REPLACED" />
    <data android:scheme="package"/>
</intent-filter>)

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>
)
 
Last edited:
Upvote 0

Mike1970

Well-Known Member
Licensed User
Longtime User
Correct.

B4X:
Sub Activity_Click
    If All_isChecked = True Then
        others.StartApp(Starter.App2Package)
        Activity.Finish
    End If
End Sub


others:
Sub StartApp (package As String)
    Dim In As Intent
    Dim pm As PackageManager

    In = pm.GetApplicationIntent(package)

    Dim List1 As List
    List1.Initialize

    List1 = QueryIntent(In)

    If In.IsInitialized Then
        Try
            StartActivity(In)
            Log(package & " was started...")
        Catch
            ToastMessageShow("Starting error...", False)
        End Try
    Else
        ToastMessageShow("Starting error (system)...", False)
    End If
End Sub

Sub QueryIntent(Intent1 As Intent) As List
    Dim r As Reflector
    r.Target = r.GetContext
    r.Target = r.RunMethod("getPackageManager")
    Dim list1 As List
    Try
        list1 = r.RunMethod4("queryIntentActivities", Array As Object(Intent1, 0), Array As String("android.content.Intent", "java.lang.int"))
    Catch
    End Try
    Return list1
End Sub
Ok thanks you for the sample code (btw can you also post the one needed to start the upgrade?)
 
Upvote 0

Mike1970

Well-Known Member
Licensed User
Longtime User
Download new .APK file of the app2 from your server and start it for installation: https://www.b4x.com/android/forum/threads/version-safe-apk-installation.87667/
oh ok! awesome, thanks.

At the moment i've some doubts that i think will be cleared while testing... but i want to explicitate them here, maybe someone already solved.
  1. What if the ACTUAL app crashes, can the "watchdog" detect that the app closed and start it again?
  2. What if the watchdog crashes, or worse, it is killed by Android (since once the actual app is started it will be in background)?
  3. What if the user goes back using the android "back button", can he close the actual app to show the "watchdog" instead...? technically it seems possibile since both are listed in the allowed kiosk apps
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
App1 must be default launcher that
  1. is automatically launched by the system if system "HOME" button is used
  2. "BACK" button does not work, app exit is impossible
Any return from any app goes to this default launcher app. That can immediately launch your app2.
But anyway - crash must be localized and fixed.
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
App1 is launcher just for lock the device and start your app2.
All depends on app2 next.
 
Upvote 0

Mike1970

Well-Known Member
Licensed User
Longtime User
All depends on app2 next.
exactly, is here my doubt... assume that app2 is currently showe. It has, idk, 3 b4xpages that I want to be able to navigate back and forth using the back button...
When I am on page 0 of app2 and I hit "back" technically I expect it to close app2 and show app1 (both allowed in kiosk) in a normal scenario...

Do I have to prevent it manually in app2 in the _KeyPress sub? someting like If page 0 is showed and user ask for back, then do nothing
 
Upvote 0

Mike1970

Well-Known Member
Licensed User
Longtime User
Correct.

B4X:
Sub Activity_Click
    If All_isChecked = True Then
        others.StartApp(Starter.App2Package)
        Activity.Finish
    End If
End Sub


others:
Sub StartApp (package As String)
    Dim In As Intent
    Dim pm As PackageManager

    In = pm.GetApplicationIntent(package)

    Dim List1 As List
    List1.Initialize

    List1 = QueryIntent(In)

    If In.IsInitialized Then
        Try
            StartActivity(In)
            Log(package & " was started...")
        Catch
            ToastMessageShow("Starting error...", False)
        End Try
    Else
        ToastMessageShow("Starting error (system)...", False)
    End If
End Sub

Sub QueryIntent(Intent1 As Intent) As List
    Dim r As Reflector
    r.Target = r.GetContext
    r.Target = r.RunMethod("getPackageManager")
    Dim list1 As List
    Try
        list1 = r.RunMethod4("queryIntentActivities", Array As Object(Intent1, 0), Array As String("android.content.Intent", "java.lang.int"))
    Catch
    End Try
    Return list1
End Sub

Manifest of the Kiosk app:
'This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: http://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="33"/>
<supports-screens android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="true"
    android:anyDensity="true"/>
)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
'End of default text.
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>)
AddReceiverText(reboot, <intent-filter>
    <action android:name="android.intent.action.PACKAGE_REPLACED" />
    <data android:scheme="package"/>
</intent-filter>)

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>
)
Hi, I just tested this method to start an app, and unfortunately it does not work any more just like this...
I found this answer by @drgottjr and I managed it to work by adding the additional manifest code. Thanks to both.
 
Upvote 0
Top