Mobile Parcel API

Mobile Parcel 1.0

Overview

Mobile Parcel API is designed based on the Android Intent architecture, reducing library dependencies and integration time for app developers. To ensure the interface is secure, it uses explicit and pending intents secured using an API token. This section discusses the Mobile Parcel APIs and how they are used. Both Certified Mobile Parcel (legal for trade certifications) and Mobile Parcel are supported by the APIs.

APIs available:

  • ENABLE_DIMENSION - Starts the Dimensioning service and configures the time-of-flight (ToF) camera for dimensioning.
  • GET_DIMENSION - Presents the Mobile Parcel UI layout on top of the line of business (LOB) app and sends dimensioning results back to the app.
  • GET_DIMENSION_PARAMETER - Reports the parameter values supported by the Mobile Parcel API.
  • SET_DIMENSION_PARAMETER - Sets parameters supported by the Mobile Parcel API.
  • DISABLE_DIMENSION - Releases all Dimensioning service resources, including camera hardware.

Notes:

  • Multi-window or split-screen is not supported due to an Android bug.
  • The API token expires after 24 hours and must be regenerated, see Generate API token.
  • Camera failure can occur from rapid succession of start/stop dimensioning after suspend/resume.

Requirements

The line-of-business (LOB) app must define the Dimensioning service package name and generate the API token. Both are required to be sent with each Mobile Parcel API request. If either the token or package name is incorrect, the Mobile Parcel API reports the error result code with an access denied message. Additionally, API security is enforced by only allowing trusted applications to communicate with the Mobile Parcel API. Make sure to add your app to this allow list.

1. Add queries tag

Add the <queries> tag in the AndroidManifest.xml of the LOB app to define two package names for Mobile Dimensioning. This is required to allow the Mobile Parcel API to communicate with the app and to allow the app to communicate with Zebra Device Manager.

<queries>
    <package android:name="com.zebra.dimensioning"/>
    <package android:name="com.zebra.devicemanager"/>
</queries>

2. Specify permission

Add the following read permission to AndroidManifest.xml:

<uses-permission android:name="com.zebra.devicemanager.provider.READ_PERMISSION" />

3. Generate API token

The API token is one of the parameters that must be sent with each API request for authentication. The API token expires after 24 hours and must be regenerated.

To generate the API token:

private String token = "";
private Instant tokenExpiration;
public static final String SERVICE_IDENTIFIER = "delegation-zebra-com.zebra.mobiledimensioning-Enable";

private void generateToken()
{
    Uri ZDM_AUTHORITY_URI = Uri.parse("content://com.zebra.devicemanager.zdmcontentprovider");
    Uri ACQUIRE_TOKEN_URI = Uri.withAppendedPath(ZDM_AUTHORITY_URI, "AcquireToken");

    try
    {
        Cursor cursor = this.getContentResolver().query(ACQUIRE_TOKEN_URI, (String[]) null,
                "delegation_scope=?", new String[]{SERVICE_IDENTIFIER}, (String) null);
        if (cursor != null && cursor.getCount() > 0)
        {
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex("query_result");
            if (columnIndex >= 0)
            {
                token = cursor.getString(columnIndex);
            }
            cursor.close();
        }
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }

    if (token != null && !token.isEmpty())
    {
        tokenExpiration = Instant.now().plus(24, ChronoUnit.HOURS);
        // Communicate with Service
    }
}

4. Add your app to the allow list

Zebra requires developers use an access control method through MX Access Manager to ensure that only trusted applications communicate with the Mobile Parcel API. To allow the LOB application package to be placed on the allow list, perform the following procedure:

A. Extract Client App Certificate

Extract the client app certificate from the LOB app. This is a pre-requisite to create the StageNow profile that places the app in the allow list.

Steps to extract the client app certificate:

  1. Download SigTools.jar from Zebra’s App Signature Tools.
  2. Follow the instructions provided from the link to extract the certificate from the LOB app APK file using command:
    java -jar SigTools.jar GetCert -INFORM APK -OUTFORM DER -IN [filename.apk] -OUTFILE [filename.crt]
    where [filename.apk] is the full path and file name of the LOB app APK file and [filename.crt] is the designated certificate file name. The file extensions should be preserved in both file names. The certificate file is extracted as the CRT file. The certificate file is needed to create the StageNow profile.

B. Create StageNow Profile

Create a StageNow profile to place the app in the allow list:

  1. Download and install StageNow on a host computer.

  2. Open StageNow. In the StageNow home screen, click Create New Profile from the left menu.

  3. Ensure MX version 11.1 or higher is selected at the top drop-down selector. The MX version on the device should match this or higher. See MX documentation for instructions how to check the version.

  4. Select Xpert Mode from the list and click Create.

  5. Enter the profile name. Click Start.

  6. Scroll to AccessMgr and click the plus (+) sign to add AccessMgr to the Config tab on the right side.

  7. Click Add.

  8. Enter the appropriate information as prompted:

    • Service Access Action: Allow Caller to Call Service
    • Service Identifier: delegation-zebra-com.zebra.mobiledimensioning-Enable
    • Caller Package Name: [Enter package name of the client app.]
    • Caller Signature: [Browse to the app certificate generated from Extract Client App Certificate.]

    Click Continue.

  9. Click Complete Profiles. Profile creation is complete.

Perform one of the following steps based on the staging method. Ensure devices are connected to the network during the staging process:

  • StageNow: Generate the barcode. Open StageNow on the device and scan the barcode to place the app in the allow list.
  • EMM: Click on Export the XML for MDM. Send the XML using either OEMConfig or MX to place the app in the allow list.

APIs

Enable Dimension

ENABLE_DIMENSION starts the Dimensioning service and enables and configures the time-of-flight (ToF) camera for the app to be ready for dimensioning. This must be called before any other API to ensure the Mobile Parcel API is enabled, allowing communication with the app.

NOTE:

  • To ensure that the Dimensioning service is properly started, ENABLE_DIMENSION should be called using the startForegroundService() method rather than the sendBroadcast() method.
  • ENABLE_DIMENSION prevents other apps from accessing the ToF camera until DISABLE_DIMENSION is called. To save battery and reduce resource conflicts, Zebra recommends calling DISABLE_DIMENSION when dimensioning is not in use or when the app is running in the background.

Request

Use the following action to call ENABLE_DIMENSION:

com.zebra.dimensioning.ENABLE_DIMENSION

Add the following keys to the intent:

Key Type Description/Value
TOKEN String API authentication token
APPLICATION_PACKAGE String LOB application package name
CALLBACK_RESPONSE PendingIntent PendingIntent object that receives the response
MODULE String

parcel


Response

The response is sent back to the app:

Key Type Description/Value
RESULT_CODE Integer 0: Success
1: Failure
2: Error
RESULT_MESSAGE String Success

• Success

Failure

• Dimensioning In Use by Another App
• Dimensioning Already In Use
• Dimensioning Not Supported
• Failed to Open Camera
• Failed to Enable
• Framework Not Installed
• Failed Integrity Check 1
• Integrity Check Fault 2
• Insufficient Permissions

Error

• Access Denied
• Invalid Module Parameter


1 Incorrect Dimensioning framework loaded.
2 System failure while running integrity check.


Sample Code

    public static final String INTENT_ACTION_ENABLE_DIMENSION = "com.zebra.dimensioning.ENABLE_DIMENSION";
    public static final String MODULE = "MODULE";
    public static final String PARCEL = "parcel";

    sendIntentApi(INTENT_ACTION_ENABLE_DIMENSION, MODULE, PARCEL);

See sendIntentApi() for the function definition.


Disable Dimension

DISABLE_DIMENSION releases the ToF camera and any other Dimensioning service resources allocated during ENABLE_DIMENSION. To save battery, call DISABLE_DIMENSION when dimensioning is not in use or when the app is running in the background.

Request

Use the following action to call DISABLE_DIMENSION:

com.zebra.dimensioning.DISABLE_DIMENSION

Add the following keys to the intent:

Key Type Description/Value
TOKEN String API authentication token
APPLICATION_PACKAGE String Line of business (LOB) application package name
CALLBACK_RESPONSE PendingIntent PendingIntent object that receives the response


Response

A response is sent to the app:

Key Type Description/Value
RESULT_CODE Integer 0: Success
1: Failure
2: Error
RESULT_MESSAGE String Success

• Success

Failure

• Dimensioning Already In Use
• Failed to Disable

Error

• Access Denied


Sample Code

    public static final String INTENT_ACTION_DISABLE_DIMENSION = "com.zebra.dimensioning.DISABLE_DIMENSION";

    sendIntentApi(INTENT_ACTION_DISABLE_DIMENSION);

See sendIntentApi() for the function definition.


Get Dimension Parameter

GET_DIMENSION_PARAMETER returns the values for all Mobile Parcel API parameters. Only call this API after ENABLE_DIMENSION is successfully called.

Request

Use the following action to call GET_DIMENSION_PARAMETER:

com.zebra.parceldimensioning.GET_DIMENSION_PARAMETER

Add the following keys with the intent:

Key Type Description/Value
TOKEN String API authentication token
APPLICATION_PACKAGE String LOB application package name
CALLBACK_RESPONSE PendingIntent PendingIntent object that receives the response


Response

A response is sent back to the app:

Key Type Description/Value
RESULT_CODE Integer 0: Success
1: Failure
2: Error
RESULT_MESSAGE String Success

• Success

Failure

• Dimensioning Already In Use
• Failed to Get Parameters


Error

• Access Denied
• Invalid State

READY_LENGTH BigDecimal Length value to display in app when ready to dimension
READY_WIDTH BigDecimal Width value to display in app when ready to dimension
READY_HEIGHT BigDecimal Height value to display in app when ready to dimension
DIMENSIONING_UNIT String

• Inch
• CM

FRAMEWORK_VERSION String Framework version
SERVICE_VERSION String Service version
BUNDLE_VERSION String Parcel dimensioning software package version
REGULATORY_APPROVAL String For Certified Solution: "OIML1234"
For Non-Certified Solution: ""
SUPPORTED_UNITS StringArray

• ("Inch","CM")
• ("CM")

REPORT_IMAGE Boolean Enable reporting proof of dimension image with dimension response:

• True
• False


Sample Code

    public static final String INTENT_ACTION_GET_DIMENSION_PARAMETER = "com.zebra.parceldimensioning.GET_DIMENSION_PARAMETER";

    sendIntentApi(INTENT_ACTION_GET_DIMENSION_PARAMETER);

See sendIntentApi() for the function definition.


Set Dimension Parameter

SET_DIMENSION_PARAMETER configures the parameters supported by the Mobile Parcel API. Set any number of parameters through a single call by adding them as intent extras. ENABLE_DIMENSION must be called before calling SET_DIMENSION_PARAMETER.

Request

Supported values for DIMENSIONING_UNIT are reported by the SUPPORTED_UNITS value in GET_DIMENSION_PARAMETER.

Use the following to call SET_DIMENSION_PARAMETER:

com.zebra.parceldimensioning.SET_DIMENSION_PARAMETER

Add the following keys to the intent:

Key Type Required Description/Value
TOKEN String Yes API authentication token
APPLICATION_PACKAGE String Yes LOB application package name
CALLBACK_RESPONSE PendingIntent Yes PendingIntent object that receives the response
DIMENSIONING_UNIT String No

• Inch
• CM

Note: Changing DIMENSIONING_UNIT will change the ready values of length, width and height.
REPORT_IMAGE Boolean No

• True
• False


Response

A response is sent back to the app:

Key Type Description/Value
RESULT_CODE Integer 0: Success
1: Failure
2: Error
RESULT_MESSAGE String Success

• Success

Failure

• Dimensioning Already In Use
• Failed to Set Parameter

Error

• Access Denied
• Invalid State
• Invalid Value
• Invalid Parameter


Sample Code

    public static final String INTENT_ACTION_SET_DIMENSION_PARAMETER = "com.zebra.parceldimensioning.SET_DIMENSION_PARAMETER";
    public static final String DIMENSIONING_UNIT = "DIMENSIONING_UNIT";

    sendIntentApi(INTENT_ACTION_SET_DIMENSION_PARAMETER, DIMENSIONING_UNIT, mUnit);

See sendIntentApi() for the function definition.


Get Dimension

GET_DIMENSION returns the values of the parcel measurements when an end-user dimensions a parcel. When this API is called, the Mobile Parcel API renders its user interface (UI) on top of the application, allowing the user to aim the camera at the parcel and begin dimensioning. Upon successful dimensioning and confirmation from the user, the results are sent back to the application through an intent response. If dimensioning fails, the result message contains details about the cause of failure.

NOTE: When calling GET_DIMENSION, the Mobile Parcel UI controls are overlaid on top of the application. This prevents the user from accessing the application until the dimensioning is complete or the user exits the dimensioning session by tapping the Back button.

Request

Use the following action to call GET_DIMENSION:

com.zebra.parceldimensioning.GET_DIMENSION

Add the following keys to the intent:

Key Type Required Description/Value
TOKEN String Yes API authentication token
APPLICATION_PACKAGE String Yes LOB application package name
CALLBACK_RESPONSE PendingIntent Yes PendingIntent object that receives the response
PARCEL_ID String No ID of parcel


Response

A response is sent back to the app:

Key Type Description/Value
RESULT_CODE Integer 0: Success
1: Failure
2: Error
3: Cancelled
RESULT_MESSAGE String Success

• Dimension Complete

Failure

• Dimensioning Already In Use
• Failed to Get Dimension
• Insufficient Permissions

Error

• Access Denied
• Already Dimensioning

Cancelled

• User Cancelled
• User Inactivity

LENGTH BigDecimal Length of parcel
WIDTH BigDecimal Width of parcel
HEIGHT BigDecimal Height of parcel
LENGTH_STATUS String

• NoDim
• BelowRange
• InRange
• AboveRange

- No dimension result is provided
- Dimension result is below the certified range
- Dimension result is within the certified range
- Dimension result is above the certified range
WIDTH_STATUS String

• NoDim
• BelowRange
• InRange
• AboveRange

- No dimension result is provided
- Dimension result is below the certified range
- Dimension result is within the certified range
- Dimension result is above the certified range
HEIGHT_STATUS String

• NoDim
• BelowRange
• InRange
• AboveRange

- No dimension result is provided
- Dimension result is below the certified range
- Dimension result is within the certified range
- Dimension result is above the certified range
DIMENSIONING_UNIT String

• Inch
• CM

TIMESTAMP Instant Time when dimension took place
IMAGE Bitmap Bitmap Image (only reported if REPORT_IMAGE parameter is enabled)
PARCEL_ID String Parcel ID set by the app


Sample Code

    public static final String INTENT_ACTION_GET_DIMENSION = "com.zebra.parceldimensioning.GET_DIMENSION";
    public static final String PARCEL_ID = "PARCEL_ID";

    sendIntentApi(INTENT_ACTION_GET_DIMENSION, PARCEL_ID, boxID);

See sendIntentApi() for the function definition.


Best Practices

The following best practices provide guidance on Mobile Parcel app development:

  • Application life cycle - Enable dimensioning when the app activity is active and disable it when inactive to ensure the resources are freed when not in use.
  • Asynchronous errors - When asynchronous camera errors are encountered, a second failure response may be received from the ENABLE_DIMENSION API after the initial success response. If this occurs, try re-enabling the Dimensioning Framework.

Sample Code

The following sections provide code samples for developing a Mobile Parcel app.

SendIntentApi()

Definition for overloaded method sendIntentApi() to be used with any Mobile Parcel API - refer to the Sample Code section of the specific API above for more details:

    public static final String ZEBRA_DIMENSIONING_PACKAGE = "com.zebra.dimensioning";
    public static final String APPLICATION_PACKAGE = "APPLICATION_PACKAGE";
    public static final String TOKEN = "TOKEN";
    public static final String CALLBACK_RESPONSE = "CALLBACK_RESPONSE";
    public static final String INTENT_ACTION_ENABLE_DIMENSION = "com.zebra.dimensioning.ENABLE_DIMENSION";
    public static final String INTENT_ACTION_DISABLE_DIMENSION = "com.zebra.dimensioning.DISABLE_DIMENSION";

    /**
    * sendIntentApi Calling of each action is done in sendIntentApi.
    *
    * @param action Intent action to be performed
    * @param extras To be sent along with intent
    */

    public void sendIntentApi(String action, Bundle extras)
    {
        if (token == null || token.isEmpty())
        {
            Log.e(TAG, "Token is Null");
            return;
        }

        Log.d(TAG, "sendIntentApi " + action);
        Intent intent = new Intent();
        intent.setAction(action);
        intent.setPackage(ZEBRA_DIMENSIONING_PACKAGE);
        intent.putExtra(APPLICATION_PACKAGE, getPackageName());
        intent.putExtra(TOKEN, token);

        if (extras != null)
        {
            intent.putExtras(extras);
        }

        PendingIntent lobPendingIntent = createPendingResult(REQUEST_CODE, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);

        intent.putExtra(CALLBACK_RESPONSE, lobPendingIntent);

        if (intent.getAction().equals(INTENT_ACTION_ENABLE_DIMENSION))
        {
            startForegroundService(intent);
        }
        else
        {
            if (intent.getAction().equals(INTENT_ACTION_DISABLE_DIMENSION))
            {
                intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            }
            sendBroadcast(intent);
        }
    }

    /**
    * sendIntentApi Calling of each action is done in sendIntentApi.
    *
    * @param action     Intent action to be performed
    * @param extraKey   To be sent along with intent
    * @param extraValue To be sent along with intent
    */

    public void sendIntentApi(String action, String extraKey, String extraValue)
    {
        Bundle extras = new Bundle();
        extras.putString(extraKey, extraValue);
        sendIntentApi(action, extras);
    }

    /**
    * sendIntentApi Calling of each action is done in sendIntentApi.
    *
    * @param action     Intent action to be performed
    * @param extraKey   To be sent along with intent
    * @param extraValue To be sent along with intent
    */

    public void sendIntentApi(String action, String extraKey, boolean extraValue)
    {
        Bundle extras = new Bundle();
        extras.putBoolean(extraKey, extraValue);
        sendIntentApi(action, extras);
    }

onActivityResult()

Responses from the Mobile Parcel API are handled by the onActivityResult function. The sample code below demonstrates an outline of how to handle the responses.

    /**
    * onActivityResult handles the intent response from Mobile Parcel API
    *
    * @param requestCode is used as an identity for Client and API request and response intent communication.
    * @param resultCode  is a response result of each intent.
    * @param intent      Intent received from API.
    */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent)
    {
        super.onActivityResult(requestCode, resultCode, intent);
        try
        {
            if (requestCode == REQUEST_CODE)
            {
                if (intent != null)
                {
                    String actionName = intent.getAction();
                    int dimResultCode = intent.getIntExtra(RESULT_CODE, FAILURE);
                    String dimResultMessage = intent.getStringExtra(RESULT_MESSAGE);
                    if (dimResultMessage == null)
                        dimResultMessage = "";
                    Log.d(TAG, "onActivityResult: " + actionName + ", " + dimResultCode + ", " + dimResultMessage);

                    switch (actionName)
                    {
                        case INTENT_ACTION_ENABLE_DIMENSION:
                            // Add LOB logic
                            break;
                        case INTENT_ACTION_GET_DIMENSION:
                            // Add LOB logic
                            break;
                        case INTENT_ACTION_GET_DIMENSION_PARAMETER:
                            // Add LOB logic
                            break;
                        case INTENT_ACTION_SET_DIMENSION_PARAMETER:
                            // Add LOB logic
                            break;
                        case INTENT_ACTION_DISABLE_DIMENSION:
                            // Add LOB logic
                            break;
                    }
                }
            }
        }
        catch (Exception e)
        {
            Log.d(TAG, "Exception : " + e);
        }
    }

Exception Handling

Zebra highly recommends to disable the Dimensioning service if the app crashes for any reason, safely closing the session and freeing all Dimensioning service resources. This provides data security between apps and saves power consumption of the Mobile Parcel solution.

The following code informs the Dimensioning service about app crashes and resources released:

  • Make the following change to AndroidManifest.xml:

    <application>
        android:name=".ApplicationDimensioningClient"
    </application>
    
  • Make the following change to the JAVA file:


    public static final String ZEBRA_DIMENSIONING_PACKAGE = "com.zebra.dimensioning";
    public static final String APPLICATION_PACKAGE = "APPLICATION_PACKAGE";
    public static final String TOKEN = "TOKEN";
    public static final String INTENT_ACTION_DISABLE_DIMENSION = "com.zebra.dimensioning.DISABLE_DIMENSION";

    public class ApplicationDimensioningClient extends Application {
        private static final String TAG = ApplicationDimensioningClient.class.getSimpleName();

        @Override
        public void onCreate() {
            super.onCreate();
            Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread thread, Throwable ex) {
                    handleUncaughtException(thread, ex);
                } 
            });
        }

        public void handleUncaughtException (Thread thread, Throwable e) {

            if (token != null && !token.isEmpty())          // Validate application token
            {
                Intent intent = new Intent();
                intent.setAction(INTENT_ACTION_DISABLE_DIMENSION);
                intent.setPackage(ZEBRA_DIMENSIONING_PACKAGE);
                intent.putExtra(APPLICATION_PACKAGE, getPackageName());
                intent.putExtra(TOKEN, token);
                sendBroadcast(intent);
            }
        }
    }

Service Unavailable

If the Dimensioning service encounters a failure, a notification can be sent to the app so it can initiate app data cleanup and inform the user of the unavailability of the Dimensioning service.

The following code shows an example of how to detect when the Dimensioning service crashes:

    public static final String INTENT_ACTION_APPLICATION_CRASH = "com.zebra.dimensioning.APPLICATION_CRASH";

    public class DimensioningClientBroadcast extends BroadcastReceiver {
        private static final String TAG = DimensioningClientBroadcast.class.getSimpleName();

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "onReceive() called.");
            String actionName = intent.getAction();
            if (actionName != null) {
                if (actionName.equals(INTENT_ACTION_APPLICATION_CRASH)) {
                    Log.d(TAG, "onReceive() Dimensioning Service Unavailable");
                }
            }
        }
    }

See Also