Version 7 (modified by 5 years ago) ( diff ) | ,
---|
- Gateworks Android Kiosk Mode - Digital Signage Software
-
Kiosk Mode Development
- Building Kiosk Mode from Source
-
Design Theory
- Create a Boot Receiver
- Suppress Back Navigation Button
- Disabling the Power Button
- Prevent Screen Dimming
- Create a Background Service
- Set Immersive Mode
- Set Lock Task Mode
- Remove System Navigation Bar
- Hiding Browser Navigation
- Add Bootloader URL and Exit Logic
- Set Base Homepage
- Replace Default Home App
- Bootloader Configuration
- Trimming Down the OS
Gateworks Android Kiosk Mode - Digital Signage Software
Digital Signage has exploded over the last few years and is now utilized in businesses ranging from fast food restaurants for menu boards to factories for showing real time productivity analytics. The uses for digital signage is unlimited and the cost has come down to a price point that even small businesses can afford.
Gateworks has created a simple digital signage software interface using Android to be used on the Gateworks Single Board Computers, specifically the Ventana Family. The signage solution can be connected to a large HDMI monitor or an LVDS LCD display.
The Gateworks Kiosk software uses the Android Operating System and Default Browser. Gateworks has modified the software so that the browser will launch automatically when the system is booted. The browser launches to a URL defined in the bootloader.
Kiosk mode has the following features:
- Browser launches to URL defined in the bootloader
- Failover URL to local storage is available when network connection is lost
- A refresh rate can be defined through a variable in the bootloader
- These features can be configured using the information: here
Gateworks has provided a pre-compiled binary for getting started quickly with the Kiosk Mode.
This pre-compiled binary features the following:
- Fits on 256MB Flash devices (rare for Android, this is a trimmed down optimized Android build)
- Boots to the URL defined in the bootloader as explained here: Bootloader Configuration
Please contact Gateworks support for a pre-compiled binary.
For Gateworks Single Board Computers, please see the following link: http://www.gateworks.com/imx6-single-board-computer-gateworks-ventana-family
Getting Started with Pre-Built Binary
Gateworks provides pre-built Android images that you can evaluate without building the source if needed. You have the following options:
- download UBI image if you have a board with 1GB/2GB of NAND flash and want to boot Android from flash
- download tarball and image a removable block storage device (mSATA / USB / uSD)
Latest images:
- Android 5.1.1 (Lollipop) Kiosk:
- Built on 2019-03-23 from Gateworks Android Kiosk BSP:
- Source: https://github.com/Gateworks/imx_android/tree/gateworks_l5.1.1_2.1.0-ga_kioskmode
- Based on Freescale l5.1.1_2.1.0-ga source
- ubi images:
- ventana-android-l5-1-1_2-1-0-ga_kioskmode-user-20190923-3_normal-ubi - UBI image for 2K page size 'normal' geometry FLASH (see here to determine your flash geometry)(sha256sum:447c9c09f0fa0e58dda38859ef857c6bb760ca9847658bfd1ca6708997dd8b1d)
- ventana-android-l5-1-1_2-1-0-ga_kioskmode-user-20190923-3_large-ubi - UBI image for 4K page size 'large' geometry FLASH (see here to determine your flash geometry)(sha256sum:447c9c09f0fa0e58dda38859ef857c6bb760ca9847658bfd1ca6708997dd8b1d)
- see here for info about flashing UBI images
- tarballs (for imaging onto removable block storage devices):
- ventana-android-l5-1-1_2-1-0-ga_kioskmode-user-20190923-3-ta.xz (sha256sum:1d60401c23e5531d9f5738a6c7640358e185b222f5074e92bd8ee4fcd474f0f4)
- Built on 2019-03-23 from Gateworks Android Kiosk BSP:
To Install:
- Download Pre-Built binary
- Install Pre-Built Android Kiosk binary to the board, Instructions Here
- Boot board and enter into bootloader command prompt
- Set bootloader variables as described here: Bootloader Configuration
- Ensure board has proper internet connection
- Boot board and enjoy the signage!
Kiosk Mode Development
The goal of this page is to outline the process of modifying the stock browser app on Android systems to simulate a "Kiosk" mode. It also details modifications to the AOSP source that will supplement this function. This could potentially be used for demonstration purposes, digital signage, or for unsupervised public access applications. A self-service configuration such as this empowers multiple users to complete tasks or view information at their convenience and at their own pace while retaining the security of your device and any potentially sensitive data it may contain.
This particular implementation effects a system that immediately after booting opens the stock AOSP browser app and displays a web page that the user can navigate within. The opened browser app can not be closed or otherwise switched out of nor can they enter in their own URL. The kiosk mode browser will check for particular bootloader arguments at runtime that allow for a configurable target URL to be set. Keyboard, mouse, or touch-screen are supported but certain functions that would allow the user to break out of the browser or access the URL/address-bar are disabled. No attempt is made to secure the device by disabling serial console or adb, however one could easily add that if desired.
This process description assumes a basic understanding of both Android development and using the Android OS in general. It specifically pertains to modifying the com.android.browser
application included in AOSP 5.1 (Lollipop) but can be used as a reference for modifying other applications and/or versions.
Building Kiosk Mode from Source
Before continuing, follow the steps at Android/Building if you have not already set up a working AOSP directory.
Once you reach the Fetching Source section of the build page, be sure to use gateworks_l5.1.1_2.1.0-ga_kioskmode
as your target of the ./repo init
command. This will apply all of the necessary target changes and modifications necessary for producing a 256M Kiosk image by following the rest of the build steps.
Design Theory
The following modifications create a kiosk mode environment for the stock Android Browser application. It is recommended to at least implement the following sections in order to implement a relatively secure Kiosk version of the browser app that still maintains proper functionality:
- Create a Boot Receiver
- Set Immersive Mode
- Set Lock Task Mode
- Hiding Browser Navigation
- Add Bootloader URL and Exit Logic
- Suppress Back Navigation Button
The decision ultimately falls on the developer to choose which Kiosk features they wish to implement. Pick whatever combination of modifications necessary to achieve the desired functionality of your kiosk/single use application.
Create a Boot Receiver
This section details the steps necessary for an app to receive the BOOT_COMPLETED
intent action which will cause your application to begin immediately after system start up in place of the default launcher application.
This step is not specific to the stock Android browser or kiosk mode and can be done to any app that you wish to launch on the completion of Android's boot-up.
- Add the following 2 sections to the top level
./AndroidManifest.xml
:<!-- Should be placed near the top of the file with other permission declarations --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- Should be placed near the bottom of the file with other receiver declarations --> <receiver android:name=".BootReceiver"> <intent-filter android:priority="999"> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver>
- Create the
./src/com/android/browser/BootReceiver.java
classpublic class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent myIntent = new Intent(context, MyKioskModeActivity.class); myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(myIntent); } }
Suppress Back Navigation Button
This section details the process for consuming and ignoring a back navigation button press in your main activity. This disables the normal function of exiting your app once in the main activity.
This step is specific to the Android app you are working with.
Due to the nature of the stock Android browser app with its use of WebView elements in a single Activity, the back press is handled in the ./src/com/android/browser/Controller.java
class. In order to override closing your app when the back key is pressed (and to avoid potential bugs when using Lock Task Mode), make the following edits to the goBackOnePageOrQuit()
method of the aforementioned Controller.java
class.
void goBackOnePageOrQuit() { Tab current = mTabControl.getCurrentTab(); if (current == null) { mActivity.moveTaskToBack(true); return; } if (current.canGoBack()) { current.goBack(); } else { Tab parent = current.getParent(); if (parent != null) { switchToTab(parent); //closeTab(current); // Comment out this line (1/3) } else { if ((current.getAppId() != null) || current.closeOnBack()) { //closeCurrentTab(true); // Comment out this line (2/3) } //mActivity.moveTaskToBack(true); // Comment out this line (3/3) } } }
If not using the stock Android browser app, you need to edit your main activity class and override the onBackPressed()
method. The main activity can be found by looking in your top level ./AndroidManifest.xml
for android.intent.action.MAIN
and seeing which activity contains it.
@Override public void onBackPressed() { // nothing to do here }
Disabling the Power Button
This section details how to disable the power button (a physical button tied to the Android POWER
key event). This can be done one of two ways. The short and simple method is to disable the POWER
key mapping in your AOSP's key layout file.
Key layout files are searched for in the following order:
/system/usr/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/system/usr/keylayout/Vendor_XXXX_Product_XXXX.kl
/system/usr/keylayout/DEVICE_NAME.kl
/data/system/devices/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/data/system/devices/keylayout/Vendor_XXXX_Product_XXXX.kl
/data/system/devices/keylayout/DEVICE_NAME.kl
/system/usr/keylayout/Generic.kl
/data/system/devices/keylayout/Generic.kl
If you are using an external input device such as a keyboard and are unsure about which key layout file applies to your input device, perform a adb shell cat /proc/bus/input/devices
. This will list the currently connected devices. The vendor, product, and version information is found in the first line of each section in the following format:
Bus=0018 Vendor=0000 Product=0000 Version=0000
Otherwise, edit <AOSP_DIR>/out/target/product/ventana/system/usr/keylayout/Generic.kl
and remove or comment out the lines containing the POWER
event. Note that there may be multiple keys attached to the same event.
The second method for ignoring power events while in your application is substantially more complex, but can be preferred if you wish to keep any code changes contained to just the application source. Note that although this is done using a similar intent/receiver method used for creating a boot receiver, you can not declare the receivers in the top level AndroidManifest.xml
when handling power button related intents. Therefore the receivers must be registered programmatically.
Disable Short Button Press
Disabling short power button presses is done by handling the ACTION_SCREEN_OFF
intent and kicking the screen back to life by acquiring a wake lock:
- Create the
./src/com/android/browser/OnScreenOffReceiver.java
class:public class OnScreenOffReceiver extends BroadcastReceiver { private static final String PREF_KIOSK_MODE = "pref_kiosk_mode"; @Override public void onReceive(Context context, Intent intent) { if(Intent.ACTION_SCREEN_OFF.equals(intent.getAction())){ AppContext ctx = (AppContext) context.getApplicationContext(); // is Kiosk Mode active? if(isKioskModeActive(ctx)) { wakeUpDevice(ctx); } } } private void wakeUpDevice(AppContext context) { PowerManager.WakeLock wakeLock = context.getWakeLock(); if (wakeLock.isHeld()) { wakeLock.release(); } wakeLock.acquire(); wakeLock.release(); } private boolean isKioskModeActive(final Context context) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); return sp.getBoolean(PREF_KIOSK_MODE, false); } }
- Edit the
./src/com/android/browser/Browser.java
class to add the following logic (other apps should create a new class that extendsApplication
):public class Browser extends Application { /* Added instance variables */ private PowerManager.WakeLock wakeLock; private OnScreenOffReceiver onScreenOffReceiver; @Override public void onCreate() { super.onCreate(); registerKioskModeScreenOffReceiver(); // Add this } /* Add the following two methods */ private void registerKioskModeScreenOffReceiver() { // register screen off receiver final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); onScreenOffReceiver = new OnScreenOffReceiver(); registerReceiver(onScreenOffReceiver, filter); } public PowerManager.WakeLock getWakeLock() { if(wakeLock == null) { // lazy loading: first call, create wakeLock via PowerManager. PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "wakeup"); } return wakeLock; } }
- Add the permission WAKE_LOCK to your manifest:
<uses-permission android:name="android.permission.WAKE_LOCK" />
- Other apps will also need to register their subclass of
Application
in the top levelAndroidManifest.xml
:<application android:name=".AppContext" android:icon="@drawable/ic_launcher" android:label="@string/app_name">
- Other apps will also need to register their subclass of
- To make the wake up also deactivate the keyguard/lockscreen, add the following indicated line to the main activity
./src/com/android/browser/BrowserActivity.java
following thesuper.onCreate()
call:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); // Add this // … }
Disable Long Button Press
Disabling the the effect of a long-press on the power button disables the system dialogue window used for power off, reset, and emergency mode. Once again only relevant if the device has a physical button tied to the Android POWER
key event.
- Override the
onWindowFocusChanged()
method in the./src/com/android/browser/BrowserActivity.java
class/* Add this method */ @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if(!hasFocus) { // Close every kind of system dialog Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); sendBroadcast(closeDialog); } }
Prevent Screen Dimming
Since the default behavior of the Android framework is to dim the screen after a set interval of inactivity in order to save battery life, a view attribute must be set to keep the screen lit while in your application.
Add android:keepScreenOn="true"
attribute to the rootview of your activity (./res/layout/browser_subwindow.xml
for stock browser app).
Create a Background Service
In order to guard against the circumstance that your app crashes and/or is somehow moved from the foreground, a background service will be created to catch these events and restore your application. This modification is only necessary if your app is not set as the default "home" application.
- Add
src/com/android/browser/KioskService.java
:public class KioskService extends Service { // periodic interval to check in seconds -> 2 seconds private static final long INTERVAL = TimeUnit.SECONDS.toMillis(2); private static final String TAG = KioskService.class.getSimpleName(); private static final String PREF_KIOSK_MODE = "pref_kiosk_mode"; private Thread t = null; private Context ctx = null; private boolean running = false; @Override public void onDestroy() { Log.i(TAG, "Stopping service 'KioskService'"); running =false; super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "Starting service 'KioskService'"); running = true; ctx = this; // start a thread that periodically checks if your app is in the foreground t = new Thread(new Runnable() { @Override public void run() { do { handleKioskMode(); try { Thread.sleep(INTERVAL); } catch (InterruptedException e) { Log.i(TAG, "Thread interrupted: 'KioskService'"); } }while(running); stopSelf(); } }); t.start(); return Service.START_NOT_STICKY; } private void handleKioskMode() { // is Kiosk Mode active? if(isKioskModeActive()) { // is App in background? if(isInBackground()) { restoreApp(); } } } private boolean isInBackground() { ActivityManager am = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1); ComponentName componentInfo = taskInfo.get(0).topActivity; return (!ctx.getApplicationContext().getPackageName().equals(componentInfo.getPackageName())); } private void restoreApp() { // Restart activity Intent i = new Intent(ctx, BrowserActivity.class); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_REORDER_TO_FRONT |Intent.FLAG_ACTIVITY_SINGLE_TOP |Intent.FLAG_ACTIVITY_NO_ANIMATION); ctx.startActivity(i); } public boolean isKioskModeActive(final Context context) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); return sp.getBoolean(PREF_KIOSK_MODE, false); } @Override public IBinder onBind(Intent intent) { return null; } }
- Start the
KioskService
in theonCreate()
method of./src/com/android/browser/BrowserActivity.java
:@Override public void onCreate() { super.onCreate(); instance = this; registerKioskModeScreenOffReceiver(); startService(new Intent(this, KioskService.class)); // add this }
Set Immersive Mode
The aptly named "Immersive Mode" of the Android framework hides both the status and navigation bars while your app is in the foreground. However users can still swipe from the top/bottom of the screen to retrieve the system UI, so this method is not completely secure on its own. When this method is combined with lock task mode it makes for a clean and effective lockdown of the system while utilizing the maximum screen real estate.
To set immersive mode in your base activity's oncreate method:
getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
Set Lock Task Mode
This section details the steps necessary to enter your device into what is referred as "Lock Task Mode" using a Device Policy Manager.
Adding a Device Policy Manager component to your application allows for further control of the device that is normally restricted by the Android OS. For the purposes of designing a single use device the Lock Task Mode will be set to allow for a bypass of system dialogue to enable screen pinning mode of the application on startup. Pinned mode can be considered the Android system's way of locking the pinned app to the foreground. Furthermore, when pinned mode is enabled by an app that has been authorized through the Device Policy Manager, pinned mode can not be exited manually. Due to the nature of the stock Android browser app, this modification also requires suppressing back navigation in order to function properly.
To implement Lock Task Mode in the stock Android browser:
- Add the following receiver block near the end the top level
AndroidManifest.xml
within theapplication
tag.<receiver android:name="com.android.browser.DeviceAdmin" android:label="device_admin" 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>
- Create the following
./src/com/android/browser/DeviceAdmin.java
classpackage com.android.browser; import android.app.admin.DeviceAdminReceiver; import android.content.Context; import android.content.Intent; public class DeviceAdmin extends DeviceAdminReceiver { @Override public void onEnabled(Context context, Intent intent) { } @Override public void onDisabled(Context context, Intent intent) { } }
- Add the following private method to the
./src/com/android/browser/BrowserActivity.java
class.private void startKioskMode() { DevicePolicyManager DPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName mDeviceAdminSample = new ComponentName(this, DeviceAdmin.class); Intent intent; /* Check to see if application has already been authorized * for Lock Task Mode. */ if (DPM.isLockTaskPermitted(this.getPackageName())) { startLockTask(); } else if (!DPM.isDeviceOwner(getPackageName()) || !DPM.isAdminActive(mDeviceAdminSample)) { intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample); intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Enabling force lock admin"); startActivityForResult(intent, 99); } else { String[] packages = {getPackageName()}; DPM.setLockTaskPackages(mDeviceAdminSample, packages); startLockTask(); } return; }
- Make the following additions to the
onActivityResult()
method in the same class.@Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == 99) { if(resultCode == Activity.RESULT_OK){ DevicePolicyManager DPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName mDeviceAdminSample = new ComponentName(this, DeviceAdmin.class); String[] packages = {getPackageName()}; DPM.setLockTaskPackages(mDeviceAdminSample, packages); } if (resultCode == Activity.RESULT_CANCELED) { Log.d(LOGTAG, getPackageName() + " was denied device admin."); } startLockTask(); } mController.onActivityResult(requestCode, resultCode, intent); }
- Call the
startKioskMode()
method at the end of theonCreate()
method in the same class.
Implementing these changes will cause the app to request authorization from the Device Policy Manager to become a device admin and enter the priviledged pinned mode referred to at the beginning of this section. However, if building from source you can bypass the request to the user and give your app device ownership/admin on first boot by injecting the following two files under out/target/product/ventana/data/system/
. The injection is done by adding the files to the PRODUCT_COPY_FILES
variable in your device configuration file (ie device/gateworks/ventana/ventana.mk
).
Additions to PRODUCT_COPY_FILES
should be of the form:
<source_path>:<destination_path>
device_owner.xml
contents:<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <device-owner package="com.android.browser" />
device_policies.xml
contents:<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <policies setup-complete="true"> <admin name="com.android.browser/com.android.browser.DeviceAdmin"> <policies flags="8" /> </admin> <lock-task-component name="com.android.browser" /> </policies>
For more information see the Android developer pages:
Remove System Navigation Bar
The Android System Navigation Bar is the bar at the bottom of the screen which presents the back, home, and app-switch soft-keys.
As the system navigation bar is independent from any installed Android application in particular, removing it is done in the Android OS.
To accomplish this on a rooted installed device you can set the qemu.hw.mainkeys
property to 1 by editing /system/build.prop
:
qemu.hw.mainkeys=1
To accomplish this at build time you would set the 'config_showNavigationBar' value to false in your device overlay (ie device/gateworks/ventana/overlay/frameworks/base/core/res/res/values/config.xml
):
<bool name="config_showNavigationBar">false</bool>
Note you could also make build.prop
modifications at build time by adding to the PRODUCT_DEFAULT_PROPERTY_OVERRIDES
or ADDITIONAL_BUILD_PROPERTIES
variables which can be found in your device target configuration (ie imx6.mk
and BoardConfig.mk
in device/gateworks/ventana/
).
Additionally, you can hide the navigation bar (and status bar) within an application by setting the SYSTEM_UI_FLAG_HIDE_NAVIGATION
flag however it will pop back if the user touches anywhere on the screen.
Hiding Browser Navigation
To disable the stock browser app's own navigation UI and fix resulting layout changes there are four necessary steps:
- Add the following attribute to the top level
RelativeLayout
in the./res/layout/nav_screen.xml
. This will hide the toolbar containing the url and other navigation buttons, effectively limiting navigation away from the targeted website.android:visibility="gone"
- Add the following line to the
onResume()
method in./src/com/android/browser/BrowserActivity.java
to hide access to settings and tabs.getActionBar().hide();
- Add the following line to
./res/values/styles.xml
in theActionBarStyle
tag:<style name="ActionBarStyle" parent="@android:style/Widget.Holo.ActionBar"> <item name="android:background">@drawable/bg_urlbar</item> <item name="android:displayOptions"></item> + <item name="android:visibility">gone</item> </style>
- Remove the
android:fitsSystemWindows="true"
attribute from the rootLinearLayout
in./res/layout/tab.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" - android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent">
Add Bootloader URL and Exit Logic
The final modification to the stock browser app is to provide dynamic URL pointing and an exit mechanism for the locked application. This allows for the changing of targeted website as well as normal access to the rest of the system without the need for recompiling.
- Add the following code to the
onCreate()
method in./src/com/android/browser/BrowserActivity.java
. Be sure to insert thero.boot.kioskdisable
check after thesuper.onCreate()
and thero.boot.url
check after the call tocreateController()
.super.onCreate(icicle); /* ADD THIS SECTION */ if (propReader("ro.boot.kioskdisable") != null) { Log.d(LOGTAG, "Found a reset key"); finish(); return; } /* END OF ADDED SECTION 1 */ if (shouldIgnoreIntents()) { finish(); return; } if (IntentHandler.handleWebSearchIntent(this, null, getIntent())) { finish(); return; } mController = createController(); Intent intent = (icicle == null) ? getIntent() : null; mController.start(intent); /* ADD THIS SECTION */ String newUrl = propReader("ro.boot.url"); if (newUrl != null) { Log.d(LOGTAG, "Found a url, setting to: " + newUrl); BrowserSettings.getInstance().setHomePage(newUrl); ((UiController)mController).openTabToHomePage(); } /* END OF ADDED SECTION 2 */
- Add the following private method to
./src/com/android/browser/BrowserActivity.java
:/* Returns result of a getprop call taking a property * and returning a string upon success or null on failure. */ public static String propReader(String propName) { Process proc = null; String line; try { proc = Runtime.getRuntime().exec("/system/bin/getprop " + propName); } catch (IOException e) { e.printStackTrace(); return null; } BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream())); try { if ((line = br.readLine()) != null && !line.isEmpty()) return line.trim(); } catch (IOException e) { e.printStackTrace(); } return null; }
Set Base Homepage
This section details the steps for the browser application to point to a new "Factory" default home page which will be the fallback in the case that a androidboot.url
was not set in the extra
environment variable of the bootloader.
- Change the
homepage_base
string in./res/values/strings.xml
Original:
<!-- The default homepage. --> <string name="homepage_base" translatable="false"> https://www.google.com/webhp?client={CID}&source=android-home</string>New:
<!-- The default homepage. --> <string name="homepage_base" translatable="false"> http://www.gateworks-info.com/www/</string>
Replace Default Home App
If designing your application for single use devices, or if you simply want to remove access to the android UI outside of your app, then your application can be made to replace the "Launcher" apps that act as Android's default home target. Replacing this will cause your app to behave just like the launcher from the perspective of the system, causing it to boot immediately, come to the foreground when the home button is pressed, and be restarted automatically in the event of termination.
- Add the
HOME
category to theMAIN
intent filter of yourBrowserActivity
activity tag in theAndroidManifest.xml
<intent-filter> <action android:name="android.intent.action.MAIN" /> <!-- Add the following line: --> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.APP_BROWSER" /> </intent-filter>
- Implement a boot receiver as described in the Create a Boot Receiver section.
- Remove the
Home
,Launcher2
, andLauncher3
packages as described in the Trimming Down the OS section.
Bootloader Configuration
As previously mentioned, the modified Browser application has the ability to check for particular bootloader arguments at run time that allow for configurable target URLs and refresh times to be set.
The Kiosk Browser will check for the bootloader parameters:
Parameter | Value | Description |
androidboot.url | URL | The primary URL target (should include the full http:// prefix).
|
androidboot.fallback | URL/File path | The secondary URL target or file path (e.g. file:///data/logo.png ).
|
androidboot.refreshtime | Integer | The time in seconds to refresh the primary URL page. If parameter is not present then the kiosk will not attempt to refresh. |
androidboot.kioskdisable | Boolean | Any value, if present, will allow the Android settings to be accessed by swiping down from top of screen. |
To edit one of the above parameters:
- Power on the device and break into the bootloader.
- Add
androidboot.url|fallback|refreshtime=<value>
to the environment variableextra
setenv extra "${extra} androidboot.<PARAMETER>=<VALUE>" saveenv
- Note that previous assignments of these bootloader parameters in the
extra
environment variable should be deleted before adding a new one and that parameters not assigned a value will be considered invalid.
Trimming Down the OS
Although the Android system will manage and allocate memory as needed, it may be beneficial to the function of your application to remove unnecessary packages and files during the build process. Not only does this allow for potentially faster operation and start up time, but could also reduce the total file size of the system image. A small enough system image could allow for smaller storage media such as 256M flash.
Since kiosk mode only runs the browser from power up, you can remove any other existing applications available to the user by setting the LOCAL_OVERRIDES_PACKAGES
variable in <AOSP_DIR>/packages/apps/Browser/Android.mk
.
For example:
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3 \ Calculator Calender Settings Downloads Development \ Camera Clock Contacts Email Gallery Messaging \ Music Search SpeechRecorder
If you wanted to further cut down on file size you could add any number of packages to the LOCAL_OVERRIDES_PACKAGES
variable to include unused libraries, system services, etc.
The full list of included packages are iteratively added to the PRODUCT_PACKAGES
variable when the <AOSP_DIR>/device/gateworks/ventana/ventana.mk
makefile is executed. Note that at the top of this makefile, other makefiles are included which may add to PRODUCT_PACKAGES
. To see the full list of installed packages you could either follow the tree of makefiles and track additions to PRODUCT_PACKAGES
, or execute an adb shell pm list packages -f
which will show all installed packages on your connected device. Another file which may be of interest is the out/target/product/ventana/installed-files.txt
file which contains the final list of files added to the system image, sorted by file size.
Attachments (1)
- kioskblast.jpg (236.1 KB ) - added by 7 years ago.
Download all attachments as: .zip