Garbage Collector

Tales from an old nibble


Disabling Home Button on Zebra Android devices

Intro #

I presented in the past a method to disable the Home Button on Zebra’s MC40 Android device, using a custom intent1. After having published it, I got some enquiries, about having the same behaviour on other Zebra’s devices. Well, it turns out that there’s now a “standard” way to do this in Zebra’s Mx extension using the UI Manager profile. This post is going to show how to implement a simple application that can disable the Home Button on all Zebra’s devices that have Mx v4.3 installed2.

The basic idea #

Mx v4.3 introduced the support in the UI Manager to disable the Home Button to disable the normal Home button behavior: You can disable it and there’s no way to exit from the foreground application.

Project setup #

We start creating a new Android application in Android Studio. I’m using Android Studio v2.1.2 with Build tools 23.0.3, and the EMDK v4.2. Your mileage can vary if you’re using a different setup.

Note: I prefer to integrate Zebra Technologies’ EMDK as a library in the gradle module file. You can find more information about this in the EMDK documentation and in [this blog]({{ relref . “emdk_and_android_sdk.md” }}).

Create a new Android project #

Creating a new Android Application, step 1 Creating a new Android Application, step 2 Creating a new Android Application, step 3 Creating a new Android Application, step 4

Add the EMDK library reference to the project #

Next step is to add a reference to the EMDK library that you need to have already installed on your development machine following the Getting Started guide. In my case I’m using a mac and I need to modify my gradle file as:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "com.pietromaggi.sample.mxhomebutton"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    provided fileTree(include: ['com.symbol.emdk.jar'], dir: '/Applications/androidSDK/add-ons/addon-symbol-emdk_v4.2-API-16/libs/')
    compile fileTree(exclude: ['com.symbol.emdk.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'
}

Add the EMDK library and permission reference to the Android Manifest XML file #

Next we need to update the AndroidManifest.xml file to add the requirement of having the EMDK library and requesting the EMDK permission:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.pietromaggi.sample.mxhomebutton">

    <uses-permission android:name="com.symbol.emdk.permission.EMDK" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <uses-library android:name="com.symbol.emdk" />

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Create the Mx Profile to disable the Home Button #

We can use EMDK’s Wizard to create the

Create EMDK UIManager Profile, step 1 Create EMDK UIManager Profile, step 2 Create EMDK UIManager Profile, step 3 Create EMDK UIManager Profile, step 4

In this way we obtain this profile to disable the home button:

<?xml version="1.0" encoding="UTF-8"?>
<!--This is an auto generated document. Changes to this document may cause incorrect behavior.-->
<wap-provisioningdoc>
    <characteristic type="ProfileInfo">
        <parm name="created_wizard_version" value="4.1.1"/>
    </characteristic>
    <characteristic type="Profile">
        <parm name="ProfileName" value="HomeButton"/>
        <parm name="ModifiedDate" value="2016-08-01 14:12:10"/>
        <parm name="TargetSystemVersion" value="4.4"/>
        <characteristic type="UiMgr" version="4.3">
        <parm name="emdk_name" value=""/>
        <parm name="HomeKeyUsage" value="2"/>
        </characteristic>
    </characteristic>
</wap-provisioningdoc>

Add handling of EMDK Profile APIs in MainActivity #

Here we can follow along EMDK documentation’s Data Capture Profile Feature Tutorial. First step is to implement the EMDKListener interface in the MainActivity class, obtaining this code:

package com.pietromaggi.sample.mxhomebutton;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.symbol.emdk.EMDKManager;

public class MainActivity extends AppCompatActivity implements EMDKManager.EMDKListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onOpened(EMDKManager emdkManager) {

    }

    @Override
    public void onClosed() {

    }
}

We’ve now to request an EMDKMAnager Instance and, in the onOpened callback, get an instance of the Profile Manager to process the profile we created at the previous step.

Again, this is just a cut and past from the Data Capture Profile Feature Tutorial:

package com.pietromaggi.sample.mxhomebutton;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

import com.symbol.emdk.EMDKManager;
import com.symbol.emdk.EMDKResults;
import com.symbol.emdk.ProfileManager;

public class MainActivity extends AppCompatActivity implements EMDKManager.EMDKListener {

    private EMDKManager emdkManager;
    private ProfileManager mProfileManager;
    private String profileName = "HomeButton";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //The EMDKManager object will be created and returned in the callback.
        EMDKResults results = EMDKManager.getEMDKManager(getApplicationContext(), this);

        //Check the return status of getEMDKManager
        if(results.statusCode != EMDKResults.STATUS_CODE.SUCCESS)
        {
            //Failed to create EMDKManager object
            Toast.makeText(this, "Error retrieving EMDK Manager instance.", Toast.LENGTH_SHORT);
        }
    }

    @Override
    public void onOpened(EMDKManager emdkManager) {
        this.emdkManager = emdkManager;
        //Get the ProfileManager object to process the profiles
        mProfileManager = (ProfileManager) emdkManager.getInstance(EMDKManager.FEATURE_TYPE.PROFILE);

        if(mProfileManager != null)
        {
            try{

                String[] modifyData = new String[1];
                //Call processProfile with profile name and SET flag to create the profile. The modifyData can be null.

                EMDKResults results = mProfileManager.processProfile(profileName, ProfileManager.PROFILE_FLAG.SET, modifyData);
                if(results.statusCode == EMDKResults.STATUS_CODE.FAILURE)
                {
                    //Failed to set profile
                }
            }catch (Exception ex){
                // Handle any exception
            }


        }
    }

    @Override
    public void onClosed() {

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //Clean up the objects created by EMDK manager
        emdkManager.release();
    }
}

}

If we run this application on a Zebra device with Mx v4.3+ we see that it disables the Home Button. Notes that this is not a kiosk mode, settings and notifications are still available and you need to use other Mx Profiles to disable these. However, this setting is now persisted on the device even if you reset it. To revert back to the default you need to do an Enterprise Reset or a Factory Reset.

Add a small interface to enable/disable the home button #

To complete this sample could be useful to add a small UI that allows to enable/disable the home button; something like:

Sample UI with Toggle Button

This is the new layout file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.pietromaggi.sample.mxhomebutton.MainActivity">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/home_button_status"
            android:layout_centerHorizontal="true" />

        <ToggleButton
            android:id="@+id/tgHomeButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textOn="Enabled"
            android:textOff="Disabled" />


    </LinearLayout>
</RelativeLayout>

And this is the code taking care of the click event for the toggle button. You can find here the whole onCreate callback:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //The EMDKManager object will be created and returned in the callback.
    EMDKResults results = EMDKManager.getEMDKManager(getApplicationContext(), this);

    final ToggleButton tgHomeButton = (ToggleButton)findViewById(R.id.tgHomeButton);

    //Check the return status of getEMDKManager
    if(results.statusCode != EMDKResults.STATUS_CODE.SUCCESS)
    {
        //Failed to create EMDKManager object
        Toast.makeText(this, "Error retrieving EMDK Manager instance.", Toast.LENGTH_SHORT);
        tgHomeButton.setEnabled(false);
    } else {
        tgHomeButton.setEnabled(true);

        tgHomeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mProfileManager != null)
                {
                    try{

                        String[] modifyData = new String[1];

                        boolean on = ((ToggleButton) v).isChecked();
                            modifyData[0] =
                                    "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!--This is an auto generated document. Changes to this document may cause incorrect behavior.--><wap-provisioningdoc>\n" +
                                    "  <characteristic type=\"ProfileInfo\">\n" +
                                    "    <parm name=\"created_wizard_version\" value=\"4.1.1\"/>\n" +
                                    "  </characteristic>\n" +
                                    "  <characteristic type=\"Profile\">\n" +
                                    "    <parm name=\"ProfileName\" value=\"HomeButton\"/>\n" +
                                    "    <parm name=\"ModifiedDate\" value=\"2016-08-01 16:30:10\"/>\n" +
                                    "    <parm name=\"TargetSystemVersion\" value=\"4.4\"/>\n" +
                                    "    <characteristic type=\"UiMgr\" version=\"4.3\">\n" +
                                    "      <parm name=\"emdk_name\" value=\"\"/>\n" +
                                    "      <parm name=\"HomeKeyUsage\" value=\"" + (on?"1":"2") + "\"/>\n" +
                                    "    </characteristic>\n" +
                                    "  </characteristic>\n" +
                                    "</wap-provisioningdoc>\n";

                        //Call processProfile with profile name and SET flag to create the profile. The modifyData can be null.
                        EMDKResults results = mProfileManager.processProfile(profileName, ProfileManager.PROFILE_FLAG.SET, modifyData);
                        if(results.statusCode == EMDKResults.STATUS_CODE.FAILURE)
                        {
                            //Failed to set profile
                            Toast.makeText(MainActivity.this, "Failed to set the new profile", Toast.LENGTH_SHORT).show();
                        } else if (results.statusCode == EMDKResults.STATUS_CODE.CHECK_XML) {
                            String responseXML = results.getStatusString();
                            if (responseXML.contains("error")) {
                                Toast.makeText(MainActivity.this, "Failed to set the new profile", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }catch (Exception ex){
                        // Handle any exception
                        Toast.makeText(MainActivity.this, "Failed to set the new profile", Toast.LENGTH_SHORT).show();
                    }


                }
            }

        });
    }
}

Conclusion #

Mx is getting better and better, and the latest version have introduced some interesting additional features and more are going to be added in the future. I hope that this small blog has made this clear and you can find more interesting suggestion on EMDK official documentation.

For now I leave you with a video of the app working and the complete source code of the project available on github.

Sample UI with Toggle Button