JavaScript Samples

The following JavaScript samples are examples of how you can use the JavaScript engine:

See Android Plus JavaScript Scripts for more information.
Note: Some script editors (primarily those accessed from the legacy console, such as within File Sync policies, specifically SOTI MobiControl package scripts) do not include the switch specifying the script type. Start your script with the following shebang line: #!/usr/bin/env js to ensure the Android device agent recognizes the script as a JavaScript script.

Simple log

Demonstrates simple logging to the console.

mobicontrol.log.info('Hello world!');
			#!/usr/bin/env js
			mobicontrol.log.info('Hello world!');

Executing a simple command on the device

Enters admin mode on the device.

#!/usr/bin/env js
				mobicontrol.agent.enterAdminMode();

Log real-time device information to the console

Logs device battery charge level to the console.

#!/usr/bin/env js
				mobicontrol.log.info('The current battery level is: ' + mobicontrol.battery.level);

Conditioning on agent's values

Logs camera permission status.

#!/usr/bin/env js
while (mobicontrol.featureControl.camera.isDisabled()) {
    mobicontrol.featureControl.camera.allow();
}
mobicontrol.log.info('Camera feature is allowed');

if loop and string operations

Demonstrates some JavaScript standard features: if loop and string operations.

#!/usr/bin/env js
if (mobicontrol.device.name.startsWith('Headquarters')) {
    mobicontrol.featureControl.camera.disable();
}

Arrays

Demonstrates a JavaScript standard feature: arrays.

#!/usr/bin/env js
// Stop clock app if it runs in the foreground
var clockApp = 'clock';
var foregroundActivities = mobicontrol.app.foregroundActivities;
foregroundActivities.forEach(function(activity) {
    if (activity.packageName.includes(clockApp)) {
         mobicontrol.app.stop(activity.packageName);
    }
});

Simple asynchronous callback execution

Installs an then starts an app.

#!/usr/bin/env js
// Install an app and start it as soon as it has been installed
mobicontrol.app.install('/sdcard/example.apk', onFinish);

function onFinish(result) {
    if (result.isSuccessful) {
        mobicontrol.app.start('net.soti.example');
    }
}

Complex asynchronous callback execution

Creates an asynchronous callback including an invocation timeout parameter and failure scenario.

#!/usr/bin/env js

mobicontrol.agent.disconnect()
pause(3000)
mobicontrol.agent.connect(onFinish, 3000)

function onFinish(result) {
    if (result.isTimedOut) {
        mobicontrol.log.info('Timeout')
    } else {
        mobicontrol.log.info('Failure')
    }
    if (result.statusCode == mobicontrol.agent.ConnectResult.NO_NETWORK) {
        mobicontrol.log.info('No network')
    } else {
        mobicontrol.log.info(result.statusCode)
    }
}

function pause(numberMillis) {
    var now = new Date()
    var exitTime = now.getTime() + numberMillis
    while (true) {
       now = new Date()
       if (now.getTime() > exitTime)
           return;
    }
}

Randomize code execution over time

Randomizes device reboots over 30 minutes so the DS (which might serve up to 100-200K devices) does not become unresponsive.

#!/usr/bin/env js
setTimeout(reboot, Math.random() * 30 * 60 * 1000);

function reboot() {
   mobicontrol.device.reboot();
}

Verify agent version

Verifies that the version of the agent is correct.

#!/usr/bin/env js
var CORRECT_VERSION = '14.3.3 Build 1234';
if (mobicontrol.agent.version != CORRECT_VERSION) {
    mobicontrol.log.error("The agent has incorrect version: " + mobicontrol.agent.version);
}

Check minimum OS version

Checks the minimum Android operating system version on a device.

#!/usr/bin/env js
var MINIMUM_ANDROID_OS_LEVEL = 26;
if (mobicontrol.os.apiLevel < MINIMUM_ANDROID_OS_LEVEL) {
    mobicontrol.log.error("Device must be upgraded to Oreo or higher");
}

Check SIM card status

Checks if a SIM card is present in the device.

#!/usr/bin/env js
if (mobicontrol.cellular.signalStrength == null) {
    mobicontrol.log.error("SIM card is removed.");
}

Force agent connection

Forces the agent to connect if it is not already online, and provides error messages if the connection fails.

#!/usr/bin/env js
mobicontrol.agent.connect(onFinish);

function onFinish(result) {
    if (result.isSuccessful) {
        mobicontrol.log.info('Success');
    } else if (result.isTimedOut) {
        mobicontrol.log.info('Timeout');
    } else {
        switch (result.statusCode) {
            case mobicontrol.agent.ConnectResult.NO_NETWORK:
                mobicontrol.log.info('No available networks');
                break;
            case mobicontrol.agent.ConnectResult.SERVER_UNREACHABLE:
                mobicontrol.log.info('The agent cannot establish network connection to the deployment server');
                break;
            case mobicontrol.agent.ConnectResult.SERVER_BUSY:
                mobicontrol.log.info('The network connection to the deployment server was established, but the server didn't acknowledge connection');
                break;
            default:
                mobicontrol.log.info('Other error occurred: ' + result.statusCode);
        }
    }
}

Device property check and action

Sends a message to the screen when identifying certain device properties. This example checks signal strength and suggests a remedy.

#!/usr/bin/env js
if (mobicontrol.cellular.signalStrength == null) {
    mobicontrol.message.createInfoDialog("Check that your SIM card is properly inserted.").show();
}

Request user acknowledgement before action

Sends a custom dialog with many options for controlling app install time. The package pushes to the device, and the pre-install script checks if the app is running in the foreground. If it is, the script asks the user to install the app now, in 5 minutes, or in 1 hour.

#!/usr/bin/env js
var FIVE_MINUTES = 5 * 60 * 1000;
var ONE_HOUR = 60 * 60 * 1000;
var buttonLabels = ['Install now', 'Install in 5 minutes', 'Install in 1 hour'];

if (isAppRunningInForeground('com.acme.importantapp')) {
    mobicontrol.message.createInfoDialog('Would you like to install ImportantApp?')
        .withButtons(buttonLabels[0], buttonLabels[1], buttonLabels[2])
        .withCallback(onConfirm).show();
}

function onConfirm(result) {
    if (result.buttonIndex != null) {
        switch (buttonLabels[result.buttonIndex]) {
            case 'Install now':
                installImportantPcg();
                break;
            case 'Install in 5 minutes':
                setTimeout(installImportantPcg, FIVE_MINUTES);
                break;
            case 'Install in 1 hour':
                setTimeout(installImportantPcg, ONE_HOUR);
                break;
         }
    }
}

function installImportantPcg() {
    // Do nothing - the normal return from the script will launch the package installation
}

function isAppRunningInForeground(app) {
    return mobicontrol.app.foregroundActivities.filter(activity => activity.packageName == app).length > 0;
}

Device self-service scripts

Organize the following simple scripts as icons users can select to perform self-help actions based on condtional logic:

Restarts the agent if the battery is charging.

#!/usr/bin/env js
if (mobicontrol.battery.isCharging) {
    mobicontrol.agent.restart();
}

Performs a check-in if the device is not currently roaming.

#!/usr/bin/env js
if (!mobicontrol.cellullar.isRoaming) {
    mobicontrol.agent.checkIn();
}

Reboots the device if the clock app is not running in the foreground.

#!/usr/bin/env js
if (isAppRunningInForeground('com.android.deskclock')) {
    mobicontrol.device.reboot()
}

function isAppRunningInForeground(app) {
    return mobicontrol.app.foregroundActivities.filter(activity => activity.packageName == app).length > 0;
}

Closes an app after detecting a low memory state.

#!/usr/bin/env js
var ONE_HUNDRED_KB = 100 * 1024;
if (mobicontrol.memory.availableSpace < ONE_HUNDRED_KB) {
    mobicontrol.app.stop('com.example');
}

Device compliance support

Promotes device compliance by running periodic checks to ensure the device is operating within accepted parameters. In this case, a persistent pop-up window displays for user action if the device battery is low.

#!/usr/bin/env js
if (mobicontrol.battery.level < 0.20 && !mobicontrol.battery.isCharging) {
    mobicontrol.message.createWarnDialog('The battery is low, charge your device!').show();
}

Package deployment support

Controls the flow and execution of package installation. In this case, installation aborts on devices running Android below Oreo OS.

#!/usr/bin/env js
if (mobicontrol.os.level < 26) {
    mobicontrol.log.warn('Aborting package installation, as device has below-Oreo OS');
    throw(mobicontrol.packages.Termination.ABORTED);
}

Device relocation by custom data, attribute, or properties

Controls the deployment progress or ensures the proper configurations deploy based on specific values. The following examples feature SSID and geofencing scenarios.

If a device's SSID is abc, move the device to the ABC folder (device group). To set this up, perform the following steps:

  1. Create the ABC folder (device group) and configure it with a certain payload (for example, Disable Camera) and INI custom data ssid.ini, with section info and key ssidIsAbc.
  2. Create a relocation policy from the original folder to the ABC folder when ssidIsAbc becomes true.
  3. Create a relocation policy from ABC to the original folder when ssidIsAbc becomes false.
  4. Run the following JavaScript on schedule to ensure that when the device connects to and disconnects from abc SSID the device is successfully relocated:
#!/usr/bin/env js
var ini = require('ini');

var iniFile = new mobicontrol.io.File(mobicontrol.storage.internal.dataDirectory + '/ssid.ini');
var config = ini.parse(iniFile.readText());
var currentSsidIsAbc = mobicontrol.network.ssid == 'abc';
if (config.info.ssidIsAbc != currentSsidIsAbc) {
    config.info.ssidIsAbc = currentSsidIsAbc;
    iniFile.writeText(ini.stringify(config));
    mobicontrol.agent.checkIn();
}

If a device whose name starts with 'Headquarters' enters geofence abc, move the device to the ABC folder. To set this up, perform the following steps:

  1. Create the ABC folder (device group). Then configure the folder with a specific payload (for example, Disable Camera) and XML custom data geofence.xml, with the name isInAbc and XPath expression /isInAbc.
  2. Create a relocation policy from the original folder to the ABC folder when isInAbc becomes true.
  3. Create a relocation policy from ABC to the original folder when isInAbc becomes false.
  4. Create a rule for entering the abc geofence with the following script:
    #!/usr/bin/env js
    if (mobicontrol.device.name.startsWith('Headquarters')) {
        var xmlFile = new mobicontrol.io.File(mobicontrol.storage.internal.dataDirectory + '/geofence.xml');
        var config = new XML(xmlFile.readText());
        config.isInAbc = true;
        xmlFile.writeText(config.toString());
        mobicontrol.agent.checkIn();
    }
  5. Create a rule for exiting abc geofence with the same script as above, but with false instead of true.
  6. Ensure a device relocates when it enters or exits the abc geofence.

Here is the same script with some custom troubleshooting code:

#!/usr/bin/env js
if (mobicontrol.device.name.startsWith('Headquarters')) {
    try {
        var xmlFile = new mobicontrol.io.File(mobicontrol.storage.internal.dataDirectory + '/geofence.xml');
        var config = new XML(xmlFile.readText());
        config.isInAbc = true;
        xmlFile.writeText(config.toString());
        mobicontrol.agent.checkIn();
    } catch(err) {
        if (err.statusCode == mobicontrol.io.IoError.FILE_NOT_FOUND) {
            mobicontrol.log.err("XML file is missing");
        } else if (err.statusCode == mobicontrol.io.IoError.NOT_ACCESSIBLE) {
            mobicontrol.log.err("XML file is not accessible");
        }
    }
}

Upgrade application if it is not runnning in the foreground

Installs an application if it is not currently running in the foreground. The device battery must be charging past a threshold before the upgrade can begin. When the installation is complete, the agent automatically checks in so that the WebConsole immediately reflects the change.

#!/usr/bin/env js

function isBatteryFullOrCharging() {
    return mobicontrol.battery.level > 0.75 || mobicontrol.battery.isCharging;
}

function isForegroundApp(app) {
    return mobicontrol.app.foregroundActivities.some(function(activity) {
        return activity.packageName == app;
    });
}

if (!isForegroundApp('com.example.bundleid') && isBatteryFullOrCharging()) {
    mobicontrol.app.install('sdcard/PathTo/ExampleApp.apk', onFinish);
} else {
    mobicontrol.log.info('Either Secure web is running or the battery is low and not charging')
}

function onFinish(result) {
    if (result.isSuccessful) {
        mobicontrol.agent.checkIn();
        mobicontrol.log.info('Application ' + result.apkFileName + ' successfully installed');
    } else {
        mobicontrol.log.error('Application ' + result.apkFileName + ' installation failure: ' + result.statusCode);
    }
}