ShareApiManager.java

/**
 * Copyright (c) 2013 Nokia Corporation. All rights reserved.
 * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. 
 * Oracle and Java are trademarks or registered trademarks of Oracle and/or its
 * affiliates. Other product and company names mentioned herein may be trademarks
 * or trade names of their respective owners. 
 * See license text file delivered with this project for more information.
 */

package com.nokia.example.statusshout.engine;

import java.util.Hashtable;
import java.util.Vector;

import javax.microedition.content.ContentHandlerException;
import javax.microedition.content.ContentHandlerServer;
import javax.microedition.content.Invocation;
import javax.microedition.content.Registry;
import javax.microedition.content.RequestListener;
import javax.microedition.midlet.MIDlet;

/**
 * Provides a simple interface for sharing images and message via Share API.
 * In addition, contains the logic for managing invocations i.e. if the app was
 * launched via share UI of the platform.
 */
public class ShareApiManager implements RequestListener {
    // Constants
    private static final String TAG = "ShareApiManager.";
    private static final String MIME_TYPE_TEXT = "text/plain";
    private static final String MIME_TYPE_WILD_CARD = "*/*";
    private static final String ARGS_PREFIX_URL = "url=";
    private static final String ARGS_PREFIX_TEXT = "text=";

    // Members
    private static ShareApiManager instance;
    private MIDlet midlet;
    private ContentHandlerServer contentHandlerServer;
    private Invocation invocation;
    private ShareListener listener;
    private String imageUriFromInvocation;
    private boolean wasLaunchedAsSharingDestination;

    /**
     * Returns the singleton instance of this class.
     * 
     * @param midlet The app MIDlet instance.
     * @return The singleton instance.
     * @throws NullPointerException If the given MIDlet instance is null.
     * @throws IllegalArgumentException If the given MIDlet does not match the
     * previously set one.
     */
    public static ShareApiManager getInstance(MIDlet midlet)
        throws NullPointerException, IllegalArgumentException
    {
        if (midlet == null) {
            throw new NullPointerException("MIDlet is null!");
        }
        
        if (instance == null) {
            instance = new ShareApiManager(midlet);
        }
        else if (midlet != instance.midlet) {
            throw new IllegalArgumentException("The MIDlet instance does not match!");
        }
        
        return instance;
    }

    /**
     * Constructor.
     * 
     * @param listener The listener for events.
     */
    private ShareApiManager(MIDlet midlet) {
        this.midlet = midlet;
    }

    /**
     * Starts listening to the given ContentHandlerServer and handles the
     * invocation, if handler has one.
     * 
     * @see javax.microedition.content.RequestListener#invocationRequestNotify(
     * javax.microedition.content.ContentHandlerServer)
     */
    public void invocationRequestNotify(ContentHandlerServer handler) {
        System.out.println(TAG + "invocationRequestNotify()");
        
        contentHandlerServer = handler;
        contentHandlerServer.setListener(this);
        
        // If there is an existing invocation, finish it so that the next
        // invocation can be handled
        finishInvocation(Invocation.CANCELLED);
        
        invocation = contentHandlerServer.getRequest(false);
        
        if (invocation != null) {
            wasLaunchedAsSharingDestination = true;
            
            if (listener != null) {
                listener.onLaunchedWithInvocation(invocation);
            }
            
            handleInvocation();
        }
    }

    /** 
     * @return True if the app was launched as a sharing destination (via
     * platform share UI).
     */
    public boolean getWasLaunchedAsSharingDestination() {
        return wasLaunchedAsSharingDestination;
    }

    /** 
     * @param listener The listener for this class.
     */
    public void setListener(ShareListener listener) {
        this.listener = listener;
    }

    /** 
     * @return The image URI parsed from the invocation.
     */
    public String getImageUriFromInvocation() {
        return imageUriFromInvocation;
    }

    /**
     * Gets the ContentHandlerServer instance and check if the app was launched
     * with invocation.
     * 
     * @see ShareApiManager#invocationRequestNotify(ContentHandlerServer)
     */
    public void checkForInvocation() {
        System.out.println(TAG + "checkForInvocation()");
        ContentHandlerServer handler = null;
        
        try {
            handler = Registry.getServer(midlet.getClass().getName());
        }
        catch (ContentHandlerException e) {
            // We have used static registration, so this exception should not
            // happen
        }
        
        invocationRequestNotify(handler);
    }

    /**
     * Finishes the existing invocation with the given result.
     * 
     * @param result The result to use to finish the existing invocation, e.g.
     * Invocation.OK or Invocation.CANCEL. 
     */
    public void finishInvocation(int result) {
        if (contentHandlerServer != null && invocation != null) {
            System.out.println(TAG + "finishInvocation(): " + result);
            contentHandlerServer.finish(invocation, result);
            invocation = null;
        }
        else if (invocation == null) {
            System.out.println(TAG + "finishInvocation(): No invocation to finish.");
        }
        else if (contentHandlerServer == null) {
            System.out.println(TAG + "finishInvocation(): Error: No handler!");
        }
    }

    /**
     * Shares an image.
     * 
     * @param imageUri The URI of the image to share.
     * @param mimeType The mime type of the image to share.
     */
    public void shareImage(final String imageUri, final String mimeType) {
        System.out.println("ShareApiManager.shareImage(): " + imageUri + ", " + mimeType);
        
        if (imageUri != null && imageUri.length() > 0) {
            String[] args = new String[] { ARGS_PREFIX_URL + imageUri };
            doInvocation(args, mimeType);
        }
        else {
            System.out.println("ShareApiManager.shareImage(): No image to share!");
        }
    }

    /**
     * Shares text.
     * 
     * @param text The text to share.
     */
    public void shareText(final String text) {
        System.out.println("ShareApiManager.shareText(): \"" + text + "\"");
        
        if (text != null && text.length() > 0) {
            String[] args = new String[] { ARGS_PREFIX_TEXT + text };
            doInvocation(args, MIME_TYPE_TEXT);
        }
        else {
            System.out.println("ShareApiManager.shareText(): No text to share!");
        }
    }

    /**
     * Launches the Share UI with the given arguments.
     * 
     * @param args Contains the information about the content to be shared.
     * @param mimeType The mime type of the content to share.
     */
    private void doInvocation(String[] args, String mimeType) {
        System.out.println("ShareApiManager.doInvocation(): ->");
        
        if (args == null || args[0] == null) {
            System.out.println("ShareApiManager.doInvocation(): Invalid arguments!");
            return;
        }
        
        if (mimeType == null || mimeType.length() == 0) {
            mimeType = MIME_TYPE_WILD_CARD;
        }
        
        System.out.println("ShareApiManager.doInvocation(): " + args[0] + ", "
                + ((args.length > 1 && args[1] != null) ? (args[1] + ", ") : "")
                + mimeType);
        
        try {
            final Registry registry = Registry.getRegistry(midlet.getClass().getName());
            Invocation invocation = new Invocation(null, mimeType, "com.nokia.share");
            invocation.setResponseRequired(false);
            invocation.setAction("share");
            invocation.setArgs(args);
            
            if (registry.invoke(invocation)) {
                // If application must be closed before invocation
                //notifyDestroyed();
            }
        }
        catch (Exception e) {
            System.out.println("ShareApiManager.doInvocation(): " + e.toString());
            
            if (listener != null) {
                listener.onError(e.toString());
            }
        }
        
        System.out.println("ShareApiManager.doInvocation(): <-");
    }

    /**
     * Handles the invocation: Parses the data provided with the invocation.
     */
    private void handleInvocation() {
        if (invocation == null) {
            return;
        }
        
        System.out.println(TAG + "handleInvocation(): "
                + "Action: " + invocation.getAction()
                + ", Response required: " + invocation.getResponseRequired());
        
        Hashtable argsTable = parseArgs(invocation.getArgs());
        
        /*
         * In case you want to share text content in your application, implement
         * this part. 
         */
        /*Vector texts = (Vector) argsTable.get("text");
        
        if (texts != null) {
            // TODO
        }*/
        
        Vector urls = (Vector) argsTable.get("url");
        
        if (urls != null) {
            // Share API is capable of sharing multiple images at once but this
            // application only shares the first one in the array
            if (urls.elementAt(0) != null) {
                imageUriFromInvocation = (String)urls.elementAt(0);
                System.out.println(TAG + "handleInvocation(): Setting image URI to "
                        + imageUriFromInvocation);
            }
        }
    }

    /**
     * Parses the <code>Invocation</code> arguments to <code>HashTable</code>.
     * 
     * @param args The argument list as an array of Strings.
     * @return The arguments in HashTable.
     */
    private static Hashtable parseArgs(String[] args) {
        Hashtable argsTable = new Hashtable();
        
        for (int i = 0; i < args.length; ++i) {
            String arg = args[i];
            int j = arg.indexOf("=");
            
            if (j > 0) {
                String key = arg.substring(0, j);
                String value = arg.substring(j + 1);
                Vector valueVector;
                
                if (argsTable.get(key) == null) {
                    valueVector = new Vector();
                }
                else {
                    valueVector = (Vector) argsTable.get(key);
                }
                
                valueVector.addElement(value);
                argsTable.put(key, valueVector);
            }
        }
        
        return argsTable;
    }
}