Integrating Applications with Concierge Management

Version 1

    Developing for Concierge management

     

     

    Who is this overview for?

    • Developers wishing to integrate Concierge management features into new or existing applications
    • Enthusiasts wanting to learn more about creating management features of Concierge

     

     

    Key components of managing applications for Concierge

    Management for Concierge consists solely of the following two components:

    • Managed preferences
    • Management services

     

     

    Using managed preferences

    Managed preferences in Concierge applications are exposed as a different mode flag for SharedPreferences. Use them exactly as if they were SharedPreferences. If you expect the values of these preferences will change while in use, you should still register them with an OnSharedPreferenceChangeListener.

    An example of their usage:

     

    import android.app.Activity;

    import android.content.Context;

    import android.content.SharedPreferences;

    import concierge.content.ContextExtension;

     

    public class SampleActivity extends Activity {

         // ...

         public void foo() {

             SharedPreferences prefs = getSharedPreferences("foo_set", Context.MODE_PRIVATE |

                                                                      ContextExtension.MODE_MANAGED);

             String bar = prefs.getString("bar", "");

             bar += "baz";

             prefs.edit().putString("bar", bar).commit();

         }

         // ...

    }


     

    Defining management services

    Management services were created to allow a developer to extend the functionality of management on their devices. A management service is, in Android terms, an IntentService that accepts a single file from a management provider. It is started by the management subsystem of Concierge when it detects a new file is available for it to process.

    Consider the use case of an IntentService as per the Android developer documentation:

    "A base class for services that handle asynchronous requests on demand."

     

    A management service is invoked exactly as the onHandleIntent(Intent) method of an IntentService. For each file that Concierge's management system encounters, a request is passed to the IntentService. Management services by default will process requests for each file found by management one at a time. If any code is executed in the service after its doPerformAction(Intent) method returns, the behavior of that code is undefined. A proper management service will only execute code when its doPerformAction(Intent) method is running.

     

    Requirements for a management service:

    • Must require the permission concierge.management.permission.MANAGE to call it.
    • Must require a file to be passed to it (more on this later).
    • Must specify an intent filter as follows:

       <intent-filter>

              <action android:name="some.unique.action.name" />

              <category android:name="concierge.intent.category.MANAGEMENT" />

              <data

                  android:host="concierge.management"

                  android:scheme="content"

                  />

          </intent-filter>

     

    To create a management service, your service must extend ManagementUpdateService. Here is an example management service:

     

    import java.io.FileNotFoundException;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.StringWriter;

    import java.io.UnsupportedEncodingException;

    import org.apache.commons.io.IOUtils;

    import android.content.Intent;

    import android.net.Uri;

    import android.util.Log;

    import concierge.managementupdate.ManagementUpdateService;

    public class SampleManagementService extends ManagementUpdateService {

         private static final String LOG_TAG = "SampleManagementService";

         private static final String UPDATE_CONFIG_ACTION  = "concierge.management.intent.action.UPDATE_SAMPLE";

         private static final String UPDATE_CONFIG_ACTION_HUMAN_READABLE  = "Updating Sample Managed Service";

         public static final String UPDATE_COMPLETE = "concierge.management.intent.action.UPDATE_COMPLETE";

     

         public SampleManagementService() {

             super("SampleManagementService");

         }

     

         @Override

         public String getActionText(Intent intent) {

             return UPDATE_CONFIG_ACTION_HUMAN_READABLE;

         }


         @Override

         public String getCompletedActionString() {

             return UPDATE_COMPLETE;

         }


         @Override

         public void doPerformAction(Intent intent) {

             if (intent != null) {

                 if (UPDATE_CONFIG_ACTION.equals(intent.getAction())) {

                     InputStream input = null;

                     StringWriter writer = new StringWriter();

                     String encoding = "UTF-8";

                     try {

                         input = getContentResolver().openInputStream(intent.getData());

                         IOUtils.copy(input, writer, encoding);

                         Log.i(LOG_TAG, writer.toString());

                         // Now that it's been processed, delete the file

                         // from management.

                         getContentResolver().delete(intent.getData(),

                                                     null, null);

                     } catch (FileNotFoundException fnfe) {

                         Log.e(LOG_TAG, "Couldn't find file for processing: "

                             + intent.getData(), fnfe);

                     } catch (IOException ioe) {

                         Log.e(LOG_TAG, "Error reading file", ioe);

                     } catch (UnsupportedEncodingException uee) {

                         Log.e(LOG_TAG, String.format("%s not supported",

                             encoding));

                     } finally {

                         if(input != null) {

                             IOUtils.closeQuietly(input);

                         }

                     }

                 }

             }

        }

    }


    This example management service only copies a file's contents to logcat. The getActionText(Intent) method presents a human readable label for the Concierge management system to display progress to a user of Concierge. Management calls the doPerformAction(Intent) method when a file is to be handled by this service. When this method completes, management marks the management service as complete and moves onto the next file in its queue.

     

    Managed services exist to process management configuration files one at a time. A managed service requires a file to be provided to it as a content uri. If a single managed service should process multiple files for one task, put them in a container format such as zip or tar. The file will be passed as such into the managed service. Management does not treat container files any differently from other files.

     

    On the other hand, if a managed service does not need files for its action, consider using the AlarmManager contained in Android as an alternative. As management updates are often applied at a regular scheduled interval, Concierge management could appear ideal for performing regular tasks such as restarting services, but the AlarmManager is much better suited for regularly scheduled tasks within Android. The management system was written to provide remote configuration from a central management authority. If a service can run without configuration, it can run without a management system calling it as well.

     

    If this recommendation is unacceptable, consider Concierge management must only tell the managed service there is a file at a given uri. The file could be empty. Management does not require the managed services to read the files.