Custom App Policies in Good Dynamics Applications

Code Samples

BlogTitleImage

Blog post written by: Mark Sohm & Chad Tetreault

In my previous blog post – Remote Configuration of a Good Dynamics App – I explained how your application could support basic remote configuration.  In that post I explained how an administrator could enter some textual information (server name, port and string) into the Good Control Console (GCC) that’s automatically delivered to a Good Dynamics (GD) application.  That works great for basic text input, but what if you want to support more advanced configuration options?  Requiring an administrator to enter complex configuration parameters as textual data would be inconvenient and error prone.  The solution?  App Policies!

If you want to jump straight to the samples, you can find “The Configurator” on GitHub:

By using an App Policy, you provide an administrator with a nice interface in the Good Control Console (GCC) to configure your application.  An example is shown in the screenshot below.  The App Policy definition that is loaded onto the GCC is defined in XML.  Anytime the policy settings are changed, they are automatically pushed to all devices on the Good Control (GC) server with the application installed.  Applications are alerted automatically when an updated policy arrives.

ColorSelect
Screenshot of custom App Policy shown in GCC

App Policies, if defined, are applied to a single application and can govern the specific features of that application. App Policies are always applied in addition to the built-in policies, which apply to all applications. For example, there is a built-in policy for the minimum length of the GD security password. This policy applies to all Good Dynamics applications.

Let’s first take a look at how the App Policy can be accessed in your application.  After that I’ll discuss the different elements you can use in a policy and show how you configure them on the server side and how you read them from within your application.

Reading the Policy on the Device (Android)

Your application can access the policy settings by calling the getApplicationPolicy and getApplicationPolicyString functions in the Good Dynamics Runtime object API.  These methods are found in the GDiOS class for iOS and GDAndroid for Android.  Note that these methods are only available for use after your application has been authorized, so you may not be able to read them as soon as your application starts up.  The appropriate place to read the App Policy after your application is launched is within the onAuthorized call back.

Here’s an Android example using the call backs from GDStateListener:

//Triggered after Good Dynamics has initialized and the user has //been authorized to use the app.
@Override
public void onAuthorized()
{
    //Get the App Policy, which is a java.util.Map.
    AppPolicy appPolicy = new 
 AppPolicy(GDAndroid.getInstance().getApplicationPolicy());
    //Do stuff here to apply the policy in your app.
}

This covers the scenario of application startup, but what about capturing changes made to the App Policy while the application is running? GDStateListener has that covered too, with its onUpdatePolicy method.  This gets called when the application receives an updated App Policy.

//Triggered when a new App Policy arrives.
@Override
public void onUpdatePolicy(Map<String, Object> map)
{
    //Get the new App Policy, which is a java.util.Map.
    appPolicy.setPolicy(map);
    //Do stuff here to apply the policy in your app.
}

Reading the Policy on the Device (Cordova)

To access the policy settings in a hybrid app (built with Apache Cordova) you simply just wait for the onDeviceReady event, and then call the updatePolicy function in the GDSpecificPolicies class.

When your app receives an updated policy, the callbacks you specified in the updatePolicy function will be called automatically.

window.plugins.GDSpecificPolicies.updatePolicy(
    function(appPolicy) {
        policy.updateAppPolicy(appPolicy);
    },
    function(error) {
        alert("Error getting app policy: " + error);
    }
);

Now that you can get the policy, we need to fill it with some interesting stuff that can be configured.  We’ve created a sample applications called The Configurator that demonstrates the various elements (check boxes, text fields, etc…) you can use to make up your policy.  The samples and its policy definition are both available on our GitHub site.

The sample reads the policy and configures various UI elements.  Here is a screenshot of what the policy looks like on the Good Control Console, and the corresponding UI of the application.

VehicleSpecification
App Policy viewed on Good Control Console

Screenshot_2016-06-17-10-58-17Android application with App Policy Applied

Installing your App Policy in a Good Control Server

As you are creating the XML file for your App Policy, you should try it out on your Good Control server to verify the policy is valid.  The GCC doesn’t give detailed errors if your policy is invalid, which can make it difficult to find that line you made the syntax error on.  An online XML validator can help in that regard.  You can use an online validator with the AppPolicySchema.xsd to validate both syntax and structure.  But if you test it out as you create it, you’ll know what areas are new, which will help you focus on a specific piece of XML to correct.

Once you have your application setup in GCC, you can upload a policy for it.  To do that click on Manage Apps in your GCC menu, click on your application and then choose the Configuration tab.  On this screen you’ll see an Upload button that can be used to upload your XML policy file.  If there is a problem with the policy file, you’ll get an error after the file was uploaded.

After uploading the app policy directly into your own GCC, the updated policy will be visible right away for your custom application.  If the policy is for an application up for sale in the Good Marketplace, it can take 12-24 hours before the updated policy is visible on your customers GCC.  A customer could restart their GCC to trigger the policy update immediately.

To view and configure your policy, choose Policy Sets from the GCC menu, click on the Pencil icon for the policy you wish to edit and then choose the Apps tab.  Expand App Specific Policies and look for your application in the list.  Expand the view for your application and you’ll see the UI for your policy elements.  Make any configuration changes you wish to try out and then click on the Update button to save your changes.  When you click Update, the policy is pushed to the device, triggering the onUpdatePolicy method that was explained in the previous section.

Policy Components

Top Level

Now let’s take a look at the XML used to create a policy.  The top level element in the policy is the AppPolicyDefinition tag.  Everything we want to use in our policy must be within this tag.

<?xml version="1.0" encoding="utf-8"?>
<apd:AppPolicyDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:apd="urn:AppPolicySchema1.good.com" xsi:schemaLocation="urn:AppPolicySchema1.good.com AppPolicySchema.xsd" >

</apd:AppPolicyDefinition>

Policy Views

Next we need to create one or more pview elements, standing for Policy View.  The policy view describes how policies are displayed in the GC console and how policy settings are grouped when accessed by the application.  The policy view can be hierarchical, with the pview element containing further pview instances as sub-elements.  There are 3 different types of pview, normal, collapsible and tabbed.

Normal is the default where contents are displayed in a simple inline style.  Collapsible displays the contents in a view that can be collapsed to a single line. The view’s title, if any, will be displayed in the collapsed line.  Tabbed displays the contents in a view that can be selected by selecting a tab, which is what I’m using in this sample.  The view’s title, if any, will be displayed in the tab.  Nesting of tabbed views is not supported.

Let’s have a look at the pviews used by The Configurator sample.

<pview>
	<pview type="tabbed">
		<title>Vehicle Specification</title>
		<pe ref="isConvertible" />
		<pe ref="exteriorColor" />
		<pe ref="visibleElements" />
		<pe ref="carName" />
		<pe ref="carDescription" />            
	</pview>
	<pview type="tabbed">
		<title>App Effects</title>
		<pe ref="enableSound" />
		<pe ref="autoPlaySound" depends="enableSound"/>
	</pview>
	<pview type="tabbed">
		<title>About</title>
		<desc>This sample application demonstrates how you can use App Policies to remotely configure an application.</desc>
	</pview>
	<pe ref="policyVersion" />
</pview>

This creates a view that contains 3 tabs, titled “Vehicle Specification”, “App Effects” and “About” as defined by their title elements.  The first tab contains 4 policy elements (pe), the second 2 elements and the final tab none.  The final tab contains only a textual description element and is shown in the screenshot below.  If you were reading closely you’ll notice that there is a policy element that is not within any tab.  The “policyVersion” is a hidden element that is not displayed.  This contains an internal policy version number that is not shown to the administrator.  You can increment this version as you release new versions of your policy so that your applications are aware which version is on the server and the elements the policy contains.

AboutTab policy view with just text, no policy elements.

The sendto attribute is not used in this example, but is important to point out.  You can define a sendto attribute to state the mobile operating systems the settings in the policy view pertain to.  Only those elements meant for the operating system your application is running on are delivered.  This allows you to have different options for iOS and Android applications.  By default, elements are sent to all operating systems.  For more details, refer to sendto on the Application Policies Definition page.

Policy Elements

Policy Elements refer to the actual configurable settings that an administrator can interact with (excluding the hidden element) and are delivered to your application.  Let’s have a look at how each setting in this sample policy is created, working from top to bottom.  For reference, here’s a screen shot again of the first tab of this policy.

VehicleSpecificationVehicle Specification Tab

Checkbox Element

The first policy element is a checkbox to choose whether to display a car image that is a coupe or convertible (or cabriolet if you prefer).  Here’s the XML that was used.

<setting name="isConvertible">
	<checkbox> 
		<key>isConvertible</key>
		<label>Convertible?</label>
		<value>false</value>
	</checkbox>
</setting>

This element is fairly basic, containing a name (that’s referenced in the policy view above), key (used as the key in the policy delivered to the application), label (displayed to the admin) and default value (false, meaning unchecked).  The name and key don’t need to match, but I find it easier to use the same value for the policy element name and key.

To facilitate easy access to the policy in my sample application, I created a wrapper class called AppPolicy, which parses the policy Map object to retrieve the value for each setting.  Let’s have a look at the method used to access the isConvertible value.

//Returns true if Convertible checkbox is checked in the app 
//policy, false if it is not.
public boolean isConvertible()
{
    //If the policy has been set (not null), extract the 
    //isConvertible value.
    if (policy != null)
    {
        return 
          ((Boolean)policy.get("isConvertible")).booleanValue();
    }
    else
    {
        return false;
    }
}

In this method I’m returning the boolean value in the Map for isConvertible, if it exists.  If it’s not present it defaults to false, or coupe (not a convertible).

The App Effects tab uses a checkbox feature where the second checkbox is only enabled if the first is checked.  This isn’t actually defined within the checkbox setting itself, but in the policy view (pview).  The depends attribute bolded in the XML sample below the screenshot highlights how to use this feature.

AppEffectsExample of one checkbox that depends on another

<pview type="tabbed">
	<title>App Effects</title>
	<pe ref="enableSound" />
	<pe ref="autoPlaySound" depends="enableSound"/>
</pview>

Select Element

The next policy element used is a select element.  This appears as a drop down when clicked on, allowing the administrator to choose the car colour.  One important thing to note about this element, is when the administrator first views the policy it’ll appear as if the first element is selected.  However, unless they’ve actually clicked on something in the list the element is not delivered to your application.  You could handle this one of two ways.  You could have the application assume the first value is the default if not set, which is what I’ve done in this sample.  You could also make the first entry in the select a dummy entry that says something like “Choose from this list”, forcing the admin to make a selection.

ColorSelectSelect policy element expanded

This setting policy element is made up of two elements.  First, there is the setting element, which shares some similar elements to the checkbox that were described above.  The new item here is the options tag.  The option tag refers to a descriptive list (dl) that defines the options available for selection in the select.  The description (desc) defines what is shown to the administrator, the value defines what is passed to the application.

<setting name="exteriorColor">
	<select>
		<key>exteriorColor</key>
		<label>Color:</label>
<options ref="colorValues" />
	</select>
</setting>



<dl name="colorValues" dtype="number">
	<dv> <desc>Black</desc> <value>0</value> </dv>
	<dv> <desc>Blue</desc> <value>1</value> </dv>
	<dv> <desc>Red</desc> <value>2</value> </dv>
	<dv> <desc>Silver</desc> <value>3</value> </dv>
	<dv> <desc>Turquoise</desc> <value>4</value> </dv>
	<dv> <desc>Yellow</desc> <value>5</value> </dv>
</dl>



Here is the Android code used to retrieve the colour value.  The key exteriorColor is used to reference the Integer stored in the policy map.  As explained above the value of 0 (for black) is returned if “exteriorColor” is not set, which could happen if the administrator did not actually click on the select box and choose a colour.

//Returns the numeric value corresponding to the color chosen in //the color select field in the app policy.
public int getCarColor()
{
    //If the policy has been set (not null), extract the 
    //exteriorColor value.
    if (policy != null)
    {
        Integer color = (Integer)policy.get("exteriorColor");

        if (color != null)
        {
            return color.intValue();
        }
        else
        {
            return 0;
        }
    }
    else
    {
        return 0;
    }
}

Multiselect Element

This sample also allows the administrator to choose the elements to display to the user.  They have the option of showing or hiding the car title, car image and car description.  This is done using a multiselect element.  The box in red encapsulates the entire multiselect element.

ElementsToDisplayMultiselect Element

The multiselect element includes some of the same tags as the select element, which were described in the previous section.  The new item here is the value tag in the multiselect, along with the data objects (do) list.  The do list is used to define the options that are checked by default.  If a value in the do list matches a value in the dl list, the option for that checkbox will be checked by default when the policy is first viewed in the GCC.

<setting name="visibleElements" >
		<multiselect>
				<key>visibleElements</key>
				<label>Elements to Display</label>
				<value ref="elementsChecked" />
<options ref="elementValues" />
		</multiselect>
</setting>



<dl name="elementValues" dtype="string">
	<dv> <desc>Car Name</desc> <value>name</value> </dv>
	<dv> <desc>Car Image</desc> <value>image</value> </dv>
	<dv> <desc>Car Description</desc><value>description</value> </dv>		
</dl>



<do name="elementsChecked" dtype="number">  
	<value>name</value>
	<value>image</value>
	<value>description</value>
</do>

On the mobile application, the App Policy will contain a Vector object called visibleElements.  The visibleElements vector will contain an entry that matches the value (from the do list) of each option in the multiselect that is checked.  In the sample, I created separate methods to check if the name, image and description should be displayed.  Here is the method that checks for the car name.  The other methods are nearly identical, the key difference being the String value they search for in the vector (name, image or description).

//Returns true if Car Name multiselect is checked in the app 
//policy, false if it is not.
public boolean displayCarName()
{
    //If the policy has been set (not null), extract the 
    //visibleElements value and check if it contains "name".  
    //This indicates "Car Name" was checked.
    if (policy != null)
    {
        Vector displayElements = 
            (Vector)policy.get("visibleElements");

        if (displayElements.contains("name"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }

}

Text & Textarea Elements

The text and textarea elements are nearly identical, so I’m going to cover them together there in the same section.  The only difference between the two is how the look visually in the GCC. The text element appears as a single line, while the textarea appears as multiple lines.  You can see examples used for the car name and car description.

VehicleSpecification

The use of name, key and label items follows similar usage patterns to the elements already described.  Maxlength is new, and specifies the maximum number of characters the administrator can enter.  Maxlength can be used in both text and textarea, but is optional.  In the examples below I only set a max length for the car name.

Text
<setting name="carName">
	<text>
		<key>carName</key>
		<label>Car Name</label>
		<maxlength>32</maxlength>
	</text>
</setting>	


Textarea
<setting name="carDescription">
	<textarea>
		<key>carDescription</key>
		<label>Car Description</label>
	</textarea>
</setting>

If the administrator has entered a value, it’ll be included in the policy map with its matching key.  Simply extract it as a string to retrieve the value.

//Returns the value entered into the Car Name text field in the 
//app policy.  If it wasn't set "Not set" is returned.
public String getCarName()
{
    //If the policy has been set (not null), extract the carName.
    if (policy != null)
    {
        return (String)policy.get("carName");
    }
    else
    {
        return "Not set";
    }
}

Hidden Element

The hidden element, as its name alludes to, is hidden from view in the GCC.  It’s useful to use for hard coded values that administrator shouldn’t change, such as the version number for this policy definition.  Although the element is not visible, it still does need to be referred to with a policy element (pe) tag that exists within a policy view (pview) tag.

<setting name="policyVersion" >
	<hidden>
		<key>version</key>
		<value>9.11</value>
	</hidden>
</setting>

Retrieval of hidden elements in an application is similar to what was done for the text and textarea elements.  We refer to the key called version in the policy Map to extract the value of the hidden element.

//Returns the version specified that is a hidden variable in the app policy.
public String getAppPolicyVersion()
{
    //If the policy has been set (not null), extract the version.
    if (policy != null)
    {
        return (String)policy.get("version");
    }
    else
    {
        return "unknown";
    }
}

Join the conversation

Show comments Hide comments
+ -
blog comments powered by Disqus