Menu

Activate your Knox License

Your app activates your Knox license to authenticate API access. For more, see Knox licenses. The Any Knox version tab below describes a common method applicable to all the Knox versions. If your solution covers all the Knox versions, follow the instructions under this tab. However, if your solution is only for devices with Knox 3.8 or higher, follow the instructions under the Knox 3.8 or higher versions only tab as that code provides better performance compared to the generic code.

Create the License Receiver class

In your app, create a new class called SampleLicenseReceiver.java, which contains a license receiver for your KPE and backwards compatible keys.

The KnoxEnterpriseLicenseManager class is used to receive the KPE key, while the EnterpriseLicenseManager class is used to receive the backwards compatible key.

package com.samsung.knox.example.gettingstarted;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

import com.samsung.android.knox.license.KnoxEnterpriseLicenseManager;
import com.samsung.android.knox.license.EnterpriseLicenseManager;

public class SampleLicenseReceiver extends BroadcastReceiver {

  private static final int DEFAULT_ERROR_CODE = -1;

  private void showToast(Context context, String msg) {
      Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
  }

  @Override
  public void onReceive(Context context, Intent intent) {

      if (intent == null) {
          // No intent action is available
          showToast(context, context.getResources().getString(R.string.no_intent));
      } else {
          String action = intent.getAction();
          if (action == null) {
              // No intent action is available
              showToast(context, context.getResources().getString(R.string.no_intent_action));
          } else if (action.equals(KnoxEnterpriseLicenseManager.ACTION_LICENSE_STATUS)) {
              // KPE activation result Intent is obtained
              int errorCode = intent.getIntExtra(
                      KnoxEnterpriseLicenseManager.EXTRA_LICENSE_ERROR_CODE, DEFAULT_ERROR_CODE);

              if (errorCode == KnoxEnterpriseLicenseManager.ERROR_NONE) {
                  // KPE activated successfully
                  showToast(context, context.getResources().getString(R.string.kpe_activated_succesfully));
                  Log.d("SampleLicenseReceiver", context.getString(R.string.kpe_activated_succesfully));
              } else {
                  // KPE activation failed
                  // Display KPE error message
                  String errorMessage = getKPEErrorMessage(context, intent, errorCode);
                  showToast(context, errorMessage);
                  Log.d("SampleLicenseReceiver", errorMessage);
              }
          } else if (action.equals(EnterpriseLicenseManager.ACTION_LICENSE_STATUS)) {
              // Backwards compatible key activation result Intent is obtained
              int errorCode = intent.getIntExtra(
              EnterpriseLicenseManager.EXTRA_LICENSE_ERROR_CODE, DEFAULT_ERROR_CODE);

              if (errorCode == EnterpriseLicenseManager.ERROR_NONE) {
                  // Backwards compatible key activated successfully
                  showToast(context, context.getResources().getString(R.string.elm_action_successful));
                  Log.d("SampleLicenseReceiver", context.getString(R.string.elm_action_successful));
              } else {
                  // Backwards compatible key activation failed
                  // Display backwards compatible key error message
                  String errorMessage = getELMErrorMessage(context, intent, errorCode);
                  showToast(context, errorMessage);
                  Log.d("SampleLicenseReceiver", errorMessage);
              }
          }
      }
  }

  private String getELMErrorMessage(Context context, Intent intent, int errorCode) {
      String message;
      switch (errorCode) {
          case EnterpriseLicenseManager.ERROR_INTERNAL:
              message = context.getResources().getString(R.string.err_elm_internal);
              break;
          case EnterpriseLicenseManager.ERROR_INTERNAL_SERVER:
              message = context.getResources().getString(R.string.err_elm_internal_server);
              break;
          case EnterpriseLicenseManager.ERROR_INVALID_LICENSE:
              message = context.getResources().getString(R.string.err_elm_licence_invalid_license);
              break;
          case EnterpriseLicenseManager.ERROR_INVALID_PACKAGE_NAME:
              message = context.getResources().getString(R.string.err_elm_invalid_package_name);
              break;
          case EnterpriseLicenseManager.ERROR_LICENSE_TERMINATED:
              message = context.getResources().getString(R.string.err_elm_licence_terminated);
              break;
          case EnterpriseLicenseManager.ERROR_NETWORK_DISCONNECTED:
              message = context.getResources().getString(R.string.err_elm_network_disconnected);
              break;
          case EnterpriseLicenseManager.ERROR_NETWORK_GENERAL:
              message = context.getResources().getString(R.string.err_elm_network_general);
              break;
          case EnterpriseLicenseManager.ERROR_NOT_CURRENT_DATE:
              message = context.getResources().getString(R.string.err_elm_not_current_date);
              break;
          case EnterpriseLicenseManager.ERROR_NULL_PARAMS:
              message = context.getResources().getString(R.string.err_elm_null_params);
              break;
          case EnterpriseLicenseManager.ERROR_SIGNATURE_MISMATCH:
              message = context.getResources().getString(R.string.err_elm_sig_mismatch);
              break;
          case EnterpriseLicenseManager.ERROR_UNKNOWN:
              message = context.getResources().getString(R.string.err_elm_unknown);
              break;
          case EnterpriseLicenseManager.ERROR_USER_DISAGREES_LICENSE_AGREEMENT:
              message = context.getResources().getString(R.string.err_elm_user_disagrees_license_agreement);
              break;
          case EnterpriseLicenseManager.ERROR_VERSION_CODE_MISMATCH:
              message = context.getResources().getString(R.string.err_elm_ver_code_mismatch);
              break;

          default:
              // Unknown error code
              String errorStatus = intent.getStringExtra(
                      EnterpriseLicenseManager.EXTRA_LICENSE_STATUS);
              message = context.getResources()
                      .getString(R.string.err_elm_code_unknown, Integer.toString(errorCode), errorStatus);
      }
      return message;
  }

  private String getKPEErrorMessage(Context context, Intent intent, int errorCode) {
      String message;
      switch (errorCode) {
          case KnoxEnterpriseLicenseManager.ERROR_INTERNAL:
              message = context.getResources().getString(R.string.err_kpe_internal);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_INTERNAL_SERVER:
              message = context.getResources().getString(R.string.err_kpe_internal_server);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_INVALID_LICENSE:
              message = context.getResources().getString(R.string.err_kpe_licence_invalid_license);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_INVALID_PACKAGE_NAME:
              message = context.getResources().getString(R.string.err_kpe_invalid_package_name);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_LICENSE_TERMINATED:
              message = context.getResources().getString(R.string.err_kpe_licence_terminated);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_NETWORK_DISCONNECTED:
              message = context.getResources().getString(R.string.err_kpe_network_disconnected);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_NETWORK_GENERAL:
              message = context.getResources().getString(R.string.err_kpe_network_general);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_NOT_CURRENT_DATE:
              message = context.getResources().getString(R.string.err_kpe_not_current_date);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_NULL_PARAMS:
              message = context.getResources().getString(R.string.err_kpe_null_params);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_UNKNOWN:
              message = context.getResources().getString(R.string.err_kpe_unknown);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_USER_DISAGREES_LICENSE_AGREEMENT:
              message = context.getResources().getString(R.string.err_kpe_user_disagrees_license_agreement);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_LICENSE_DEACTIVATED:
              message = context.getResources().getString(R.string.err_kpe_license_deactivated);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_LICENSE_EXPIRED:
              message = context.getResources().getString(R.string.err_kpe_license_expired);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_LICENSE_QUANTITY_EXHAUSTED:
              message = context.getResources().getString(R.string.err_kpe_license_quantity_exhausted);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_LICENSE_ACTIVATION_NOT_FOUND:
              message = context.getResources().getString(R.string.err_kpe_license_activation_not_found);
              break;
          case KnoxEnterpriseLicenseManager.ERROR_LICENSE_QUANTITY_EXHAUSTED_ON_AUTO_RELEASE:
              message = context.getResources().getString(R.string.err_kpe_license_quantity_exhausted_on_auto_release);
              break;

          default:
              // Unknown error code
              String errorStatus = intent.getStringExtra(
                      KnoxEnterpriseLicenseManager.EXTRA_LICENSE_STATUS);
              message = context.getResources()
                      .getString(R.string.err_kpe_code_unknown, Integer.toString(errorCode), errorStatus);
      }
      return message;
  }
}
              

Register the License Receiver class

When the KPE license is activated, the com.samsung.android.knox.intent.action.KNOX_LICENSE_STATUS intent is emitted. Upon activation of the Backwards Compatible Key, the com.samsung.android.knox.intent.action.LICENSE_STATUS intent is emitted. The app uses the SampleLicenseReceiver class to intercept this intent. Paste this code in AndroidManifest.xml to define the receiver that will handle Knox license status broadcasts.

<receiver android:name=".SampleLicenseReceiver" >
  <intent-filter>
    <action android:name="com.samsung.android.knox.intent.action.KNOX_LICENSE_STATUS" />
    <action android:name="com.samsung.android.knox.intent.action.LICENSE_STATUS" />
  </intent-filter>
</receiver>
              

When your app receives the com.samsung.android.knox.intent.action.KNOX_LICENSE_STATUS and the com.samsung.android.knox.intent.action.LICENSE_STATUS intents, it passes the intents to SampleLicenseReceiver.onReceive(). Use this method to have your app respond to the license activation.

Activate the license

Use this method in your MainActivity to activate the license.

private void activateLicense() {
  // Instantiate the KnoxEnterpriseLicenseManager class to use the activateLicense method
  KnoxEnterpriseLicenseManager licenseManager = KnoxEnterpriseLicenseManager.getInstance(this);
  // License Activation TO DO - Modify Constants.KPE_LICENSE_KEY with license key to be activated
  licenseManager.activateLicense(Constants.KPE_LICENSE_KEY);
  mUtils.log(getResources().getString(R.string.license_progress));
}

// call backwards compatible key activation
//Backwards Compatible Key must be activated after KPE key activation.
private void activateBackwardsCompatibleKey() {
  // Get an instance of the License Manager
  EnterpriseLicenseManager backwardsCompatibleKeyManager = EnterpriseLicenseManager.getInstance(this);
  // Activate the backwards compatible license key TO DO - Modify Constants.BACKWARDS_COMPATIBLE_KEY with BCK key to be Activated
  backwardsCompatibleKeyManager.activateLicense(Constants.BACKWARDS_COMPATIBLE_KEY);
  mUtils.log(getResources().getString(R.string.backwards_compatible_key_activation));
}
              

When license activation is performed, a pop-up for a consent to use personal information might appear. This is displayed depending on the policy, and the license is activated only when confirmed. Please refer to the User agreements for Android device management page to find the conditions under which Konx license privacy policy pop-up is displayed.

For KLM, there are three terms that are important when it comes to licenses that you can receive in the KnoxEnterpriseLicenseManager.ACTION_LICENSE_STATUS broadcast:

  1. Activation - Initial license activation (Constant is integer 800)
  2. Deactivation - License deactivation (Constant is integer 802)
  3. Validation - Once or twice a day, the license agent checks to see if the license is still valid. For example, if it expires before a validation check is made, the license agent returns a value that indicates license expiration. (Constant is integer 801)

Following is the code from the broadcast receiver that catches the license activation:

if (action.equals(KnoxEnterpriseLicenseManager.ACTION_LICENSE_STATUS)) {
  String status = intent.getStringExtra(KnoxEnterpriseLicenseManager.EXTRA_LICENSE_STATUS);
  int errorCode = intent.getIntExtra(KnoxEnterpriseLicenseManager.EXTRA_LICENSE_ERROR_CODE, 1);
  int extraResult = intent.getIntExtra(KnoxEnterpriseLicenseManager.EXTRA_LICENSE_RESULT_TYPE, 1);
  toast.setText("KLM Status = " + status + ",  " + "Error Code= " + errorCode + ",  " + "Extra Result Type= " + extraResult);
  toast.show();
  Log.d(TAG, "KLM Status = " + status + ",  " + "Error Code= " + errorCode + ",  " + "Extra Result Type= " + extraResult);
}
              

For example, if a validation request is made and is successful, the following toast appears:

KLM Status = Success, Error Code = 0, Extra Result Type = 801

For BCK, there are two terms that are important when it comes to licenses that you can receive in the EnterpriseLicenseManager.ACTION_LICENSE_STATUS broadcast:

  1. Activation — Initial license activation (Constant is integer 800)
  2. Validation — Once a week, the license agent checks to see if the license is still valid. For example, if it expires before a validation check is made, the license agent returns a value that indicates license expiration. (Constant is integer 801)
  3. Following is the code from the broadcast receiver that catches the license activation:
if (action.equals(EnterpriseLicenseManager.ACTION_LICENSE_STATUS)) {
  String status = intent.getStringExtra(EnterpriseLicenseManager.EXTRA_LICENSE_STATUS);
  int errorCode = intent.getIntExtra(EnterpriseLicenseManager.EXTRA_LICENSE_ERROR_CODE, EnterpriseLicenseManager.ERROR_NONE);
  int resultType = intent.getIntExtra(EnterpriseLicenseManager.EXTRA_LICENSE_RESULT_TYPE, EnterpriseLicenseManager.LICENSE_RESULT_TYPE_ACTIVATION);
  toast.setText("BCK Status = " + status + ",  " + "Error Code= " + errorCode + ",  " + "Result Type= " + resultType);
  toast.show();
  Log.d(TAG, "BCK Status = " + status + ",  " + "Error Code= " + errorCode + ",  " + "Result Type= " + resultType);
}
              

For example, After a successful activation of a BCK key, the following toast appears:

BCK Status = success, Error Code = 0, Extra Result Type = 800

Until Knox 3.7, the only way to identify if a Knox license was activated/deactivated was through the use of Android Broadcast Receivers. However, due to platform system limitations this broadcast was time consuming to receive in some situations (like a phone reboot) as each broadcast was put in a queue.   So, from Knox SDK 3.8 onwards, a new API was included to activate/deactivate licenses in a faster way. The only difference from the current API's is the possibility of caller applications to specify a callback that will receive the result as soon as the activation/deactivation is completed.

Note — In the new APIs using callback, broadcasts with activation result are no longer sent. However, activation/deactivation APIs are still supported without a callback parameter.

Activate the license

Use the following methods in your MainActivity to activate a KPE/BCK license and to deactivate a KPE license:

//Use this method in your MainActivity to activate any KPE key.
private void activateKPELicense() {
    Log.i(TAG, "activateKPELicense");
    //TODO - Replace showLicenseProgressDialog with your custom loading implementation
    showLicenseProgressDialog();
    // Instantiate the KnoxEnterpriseLicenseManager class to use the activateLicense method
    KnoxEnterpriseLicenseManager licenseManager = KnoxEnterpriseLicenseManager.getInstance(this);
    // Instantiate LicenseResultCallback to handle activation result
    LicenseResultCallback kpeActivationResultCallback = new LicenseResultCallbackImpl();
    //TODO - Modify Constants.KPE_KEY with license key to be activated
    licenseManager.activateLicense(Constants.KPE_KEY, getPackageName(), kpeActivationResultCallback);
}

//Use this method in your MainActivity to deactivate any KPE key.
private void deactivateKPELicense() {
    Log.i(TAG, "deactivateKPELicense");
    //TODO - Replace showLicenseProgressDialog with your custom loading implementation
    showLicenseProgressDialog();
    // Instantiate the KnoxEnterpriseLicenseManager class to use the deActivateLicense method
    KnoxEnterpriseLicenseManager licenseManager = KnoxEnterpriseLicenseManager.getInstance(this);
    // Instantiate LicenseResultCallback to handle deactivation result
    LicenseResultCallback kpeDeactivationResultCallback = new LicenseResultCallbackImpl();
    //TODO - Modify Constants.KPE_KEY with license key to be deactivated
    licenseManager.deActivateLicense(Constants.KPE_KEY, getPackageName(), kpeDeactivationResultCallback);
}

//Use this method in your MainActivity to activate a BCK key.
//Backwards Compatible Key must be activated after KPE key activation.
private void activateBackwardsCompatibleKey() {
    Log.i(TAG, "activateBackwardsCompatibleKey");
    //TODO - Replace showLicenseProgressDialog with your custom loading implementation
    showLicenseProgressDialog();
    // Instantiate the EnterpriseLicenseManager class to use the activateLicense method
    EnterpriseLicenseManager licenseManager = EnterpriseLicenseManager.getInstance(this);
    // Instantiate LicenseResultCallback to handle activation result
    LicenseResultCallback bckActivationResultCallback = new LicenseResultCallbackImpl();
    //TODO - Modify Constants.BACKWARDS_COMPATIBLE_KEY with BCK key to be Activated
    licenseManager.activateLicense(Constants.BACKWARDS_COMPATIBLE_KEY, getPackageName(), bckActivationResultCallback);
}

//Following inner class receives the callback from KPE/BCK activation and KPE deactivation
private class LicenseResultCallbackImpl implements LicenseResultCallback {
    @Override
    public void onLicenseResult(LicenseResult licenseResult) {
        switch (licenseResult.getType()) {
            case ELM_ACTIVATION:
                Log.i(TAG, "BCK activation result");
                handleLicenseCallbackResponse(licenseResult);
                break;
            case KLM_ACTIVATION:
                Log.i(TAG, "KPE Activation result");
                handleLicenseCallbackResponse(licenseResult);
                break;
            case KLM_DEACTIVATION:
                Log.i(TAG, "KPE Deactivation result");
                handleLicenseCallbackResponse(licenseResult);
                break;
            case UNDEFINED:
            default:
                Log.e(TAG, "Unknown error during " + licenseResult.getType());
                break;

        }
    }
}

/**
 * This method will not be called from main thread so if you need to update the UI, be sure to use the appropriate component like Handler or Activity::runOnUiThread()
*/
private void handleLicenseCallbackResponse(LicenseResult licenseResult) {
    Log.i(TAG, "handleLicenseCallbackResponse");
    //TODO - Replace dismissLicenseProgressDialog with your custom loading implementation
    dismissLicenseProgressDialog();
    if (licenseResult.isSuccess()) {
        if (licenseResult.isActivation()) {
            //TODO - Modify following code to handle KPE/BCK activation case
            Log.i(TAG, licenseResult.getLicenseKey() +
                    " activated successfully");
            //permissions granted can be check using following code
            List<String> permissionsGranted = licenseResult.getGrantedPermissions();
            for (String permission : permissionsGranted) {
                Log.i(TAG, permission);
            }
        } else {
            //TODO - Modify following code to handle KPE deactivation case
            Log.i(TAG, licenseResult.getLicenseKey() +
                    " deactivated successfully");
        }
    } else {
        //TODO - Modify following code to handle error during activation/deactivation flow
        Log.e(TAG, "Error during " + licenseResult.getType() + " of license key " +
                licenseResult.getLicenseKey() + " with error code: " + licenseResult.getErrorCode());
    }
}
                

When license activation is performed, a pop-up for a consent to use personal information might appear. This is displayed depending on the policy, and the license is activated only when confirmed. Please refer to the User agreements for Android device management page to find the conditions under which Konx license privacy policy pop-up is displayed.

Backwards Compatible Key (BCK)

In the following cases, you need to activate a backwards compatible key:

KLM Type BCK
Knox 2.8 or higher Knox 2.7.1 or lower
KPE Standard (KLM09) BCK not required BCK required
Legacy KPE Premium (KLM03, KLM06) BCK required BCK required
KPE Premium (KLM09) BCK not required BCK required
Note 1 — If EMM server activates both KPE Standard key and BCK key , It works well for all version devices even IT Admin inserts any KPE premium KLM09 key or KLM03. To get more information about the backwards compatible key, see What is the backwards compatible key?, Do I need to associate my app with a backwards compatible key?, When do I need to use the backwards compatible key?, and Licensing FAQ section.
Note 2 — Apps can no longer activate ELM licenses on devices to call Knox APIs. Existing ELM key activated devices will remain activated, even after a factory reset. For more information on ELM see ELM License End of Service FAQ section.
Note 3 — Backwards Compatible Key must be activated after KPE key activation.

See also: