com.microsoft.rightsmanagement.sampleapp.MsipcTaskFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.rightsmanagement.sampleapp.MsipcTaskFragment.java

Source

/**
 * Copyright  Microsoft Corporation, All Rights Reserved
 *
 * Licensed under MICROSOFT SOFTWARE LICENSE TERMS, 
 * MICROSOFT RIGHTS MANAGEMENT SERVICE SDK UI LIBRARIES;
 * You may not use this file except in compliance with the License.
 * See the license for specific language governing permissions and limitations.
 * You may obtain a copy of the license (RMS SDK UI libraries - EULA.DOCX) at the 
 * root directory of this project.
 *
 * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A
 * PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
 */

package com.microsoft.rightsmanagement.sampleapp;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.Fragment;

import com.microsoft.rightsmanagement.AuthenticationRequestCallback;
import com.microsoft.rightsmanagement.CommonRights;
import com.microsoft.rightsmanagement.Consent;
import com.microsoft.rightsmanagement.ConsentCallback;
import com.microsoft.rightsmanagement.ConsentCompletionCallback;
import com.microsoft.rightsmanagement.CreationCallback;
import com.microsoft.rightsmanagement.CustomProtectedInputStream;
import com.microsoft.rightsmanagement.CustomProtectedOutputStream;
import com.microsoft.rightsmanagement.EditableDocumentRights;
import com.microsoft.rightsmanagement.IAsyncControl;
import com.microsoft.rightsmanagement.PolicyAcquisitionFlags;
import com.microsoft.rightsmanagement.PolicyDescriptor;
import com.microsoft.rightsmanagement.ProtectedFileInputStream;
import com.microsoft.rightsmanagement.ProtectedFileOutputStream;
import com.microsoft.rightsmanagement.TemplateDescriptor;
import com.microsoft.rightsmanagement.UserPolicy;
import com.microsoft.rightsmanagement.UserPolicy.UserPolicyCreationFlags;
import com.microsoft.rightsmanagement.UserPolicyType;
import com.microsoft.rightsmanagement.UserRights;
import com.microsoft.rightsmanagement.exceptions.InvalidParameterException;
import com.microsoft.rightsmanagement.exceptions.ProtectionException;
import com.microsoft.rightsmanagement.ui.CompletionCallback;
import com.microsoft.rightsmanagement.ui.ConsentActivity;
import com.microsoft.rightsmanagement.ui.EmailActivity;
import com.microsoft.rightsmanagement.ui.PolicyPickerActivity;
import com.microsoft.rightsmanagement.ui.PolicyPickerActivityResult;
import com.microsoft.rightsmanagement.ui.UserPolicyViewerActivity;
import com.microsoft.rightsmanagement.ui.UserPolicyViewerActivity.UserPolicyViewerActivityRequestOption;
import com.microsoft.rightsmanagement.ui.UserPolicyViewerActivity.UserPolicyViewerActivityResult;
import com.microsoft.rightsmanagement.ui.utils.Logger;

/**
 * A persisting fragment holding async controls of MSIPC SDK.
 */
public class MsipcTaskFragment extends Fragment {
    /**
     * The Enum Signal.
     */
    public enum Signal {
        ContentConsumed, ContentProtected, None;
    }

    /**
     * The Interface TaskEventCallback.
     */
    public interface TaskEventCallback {
        /**
         * On msipc task update.
         * 
         * @param taskStatus the task status
         */
        public void onMsipcTaskUpdate(TaskStatus taskStatus);
    }

    /**
     * Represents state of a task inside this fragment. An operation can contain sequence of multiple tasks.
     */
    public enum TaskState {
        NotStarted, Starting, Running, Completed, Cancelled, Faulted;
    }

    /**
     * The Class TaskStatus.
     */
    public class TaskStatus {
        private String mMessage;
        private boolean mPostToCaller;
        private Signal mSignal;
        private TaskState mTaskState;

        /**
         * Instantiates a new task status.
         * 
         * @param state the state
         * @param message the message
         * @param postToCaller the post to caller
         */
        public TaskStatus(TaskState state, String message, boolean postToCaller) {
            this(state, message, postToCaller, Signal.None);
        }

        /**
         * Instantiates a new task status.
         * 
         * @param state the state
         * @param message the message
         * @param postToCaller the post to caller
         * @param signal the signal
         */
        public TaskStatus(TaskState state, String message, boolean postToCaller, Signal signal) {
            mTaskState = state;
            mMessage = message;
            mPostToCaller = postToCaller;
            mSignal = signal;
        }

        /**
         * Gets the message.
         * 
         * @return the message
         */
        public String getMessage() {
            return mMessage;
        }

        /**
         * Gets the signal.
         * 
         * @return the signal
         */
        public Signal getSignal() {
            return mSignal;
        }

        /**
         * Gets the task state.
         * 
         * @return the task state
         */
        public TaskState getTaskState() {
            return mTaskState;
        }
    }

    // Request codes for MSIPC UI Activities
    public static final int EMAIL_INPUT_REQUEST = 0x1;
    public static final int POLICY_VIEW_REQUEST = 0x3;
    public static final int POLICY_PICK_REQUEST = 0x2;
    public static final int CONSENT_REQUEST = 0x4;
    public static final String TAG = "MsipcTaskFragment";
    protected TaskStatus mLatestUnpostedTaskStatus;
    protected Object mLockOnLatestUnpostedTaskStatus = new Object();
    private Context mApplicationContext;
    private String mDecryptedContent;
    private String mEmailId;
    private IAsyncControl mIAsyncControl;
    private String mProtectedContentFilePath;
    private AuthenticationRequestCallback mRmsAuthCallback;
    private ConsentCallback mConsentCallback;
    private TaskEventCallback mTaskEventCallback;
    private UserPolicy mUserPolicy;
    private LinkedHashSet<String> sSupportedRights = new LinkedHashSet<String>(
            Arrays.asList(new String[] { CommonRights.Owner, CommonRights.View, EditableDocumentRights.Edit,
                    EditableDocumentRights.Extract, EditableDocumentRights.Print }));

    /**
     * Handle msipc ui activity result.
     * 
     * @param requestCode the request code
     * @param resultCode the result code
     * @param data the data
     */
    public static void handleMsipcUIActivityResult(int requestCode, int resultCode, Intent data) {
        // handle MSIPC Results
        switch (requestCode) {
        case POLICY_PICK_REQUEST:
            PolicyPickerActivity.onActivityResult(resultCode, data);
            break;
        case POLICY_VIEW_REQUEST:
            UserPolicyViewerActivity.onActivityResult(resultCode, data);
            break;
        case EMAIL_INPUT_REQUEST:
            EmailActivity.onActivityResult(resultCode, data);
            break;
        case CONSENT_REQUEST:
            ConsentActivity.onActivityResult(resultCode, data);
            break;
        default:
            // handle invalid request error
        }
    }

    /**
     * cancels the current in-progress async task.
     */
    public void cancelTask() {
        if (mIAsyncControl != null) {
            mIAsyncControl.cancel();
        }
    }

    /**
     * Gets the decrypted content.
     * 
     * @return the decrypted content
     */
    public String getDecryptedContent() {
        return mDecryptedContent;
    }

    /**
     * Gets the latest unposted task status.
     * 
     * @return the latest unposted task status
     */
    public TaskStatus getLatestUnpostedTaskStatus() {
        TaskStatus latestUnpostedTaskStatus = null;
        synchronized (mLockOnLatestUnpostedTaskStatus) {
            latestUnpostedTaskStatus = mLatestUnpostedTaskStatus;
            mLatestUnpostedTaskStatus = null;
        }
        return latestUnpostedTaskStatus;
    }

    /**
     * Gets the protected content file path.
     * 
     * @return the protected content file path
     */
    public String getProtectedContentFilePath() {
        return mProtectedContentFilePath;
    }

    /**
     * Gets the current User Policy.
     * 
     * @return current User Policy
     */
    public UserPolicy getUserPolicy() {
        return mUserPolicy;
    }

    /**
     * Invalidate user policy.
     */
    public void invalidateUserPolicy() {
        mUserPolicy = null;
    }

    /*
     * (non-Javadoc)
     * @see android.support.v4.app.Fragment#onAttach(android.app.Activity)
     */
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mTaskEventCallback = (TaskEventCallback) activity;
    }

    /*
     * (non-Javadoc)
     * @see android.support.v4.app.Fragment#onCreate(android.os.Bundle)
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mApplicationContext = getActivity().getApplicationContext();
        // Retain this fragment across configuration changes.
        setRetainInstance(true);
        updateTaskStatus(new TaskStatus(TaskState.NotStarted, null, false));
        mConsentCallback = getConsentCallback();
        try {
            mRmsAuthCallback = App.getInstance().getRmsAuthenticationCallback(getActivity());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            Logger.ie(TAG, e.getMessage());
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
            Logger.ie(TAG, e.getMessage());
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            Logger.ie(TAG, e.getMessage());
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        }
    }

    /*
     * (non-Javadoc)
     * @see android.support.v4.app.Fragment#onDetach()
     */
    @Override
    public void onDetach() {
        super.onDetach();
        mTaskEventCallback = null;
    }

    /**
     * Shows MSIPC user policy on the screen using MSIPC UI library.
     */
    public void showUserPolicy() {
        CompletionCallback<Integer> userPolicyViewerActivityCompletionCallback = new CompletionCallback<Integer>() {
            @Override
            public void onCancel() {
                // Do nothing
            }

            @Override
            public void onSuccess(Integer result) {
                switch (result) {
                case UserPolicyViewerActivityResult.EDIT_POLICY:
                    startMsipcPolicyCreation(true);
                    break;
                }
            }
        };
        UserPolicy userPolicy = mUserPolicy;
        if (userPolicy != null) {
            UserPolicyViewerActivity.show(POLICY_VIEW_REQUEST, getActivity(), userPolicy, sSupportedRights,
                    mUserPolicy.isIssuedToOwner() ? UserPolicyViewerActivityRequestOption.EDIT_ALLOWED
                            : UserPolicyViewerActivityRequestOption.NONE,
                    userPolicyViewerActivityCompletionCallback);
        }
    }

    // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // /////////////////////////////////////////MSIPC OPERATIONS////////////////////////////////////////////////////////
    // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * Start content consumption and read protected content from ptxt file format
     * 
     * @param inputStream the input stream
     */
    public void startContentConsumptionFromPtxtFileFormat(InputStream inputStream) {
        CreationCallback<ProtectedFileInputStream> protectedFileInputStreamCreationCallback = new CreationCallback<ProtectedFileInputStream>() {
            @Override
            public Context getContext() {
                return mApplicationContext;
            }

            @Override
            public void onCancel() {
                updateTaskStatus(new TaskStatus(TaskState.Cancelled,
                        "ProtectedFileInputStream creation was cancelled", true));
            }

            @Override
            public void onFailure(ProtectionException e) {
                updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
            }

            @Override
            public void onSuccess(ProtectedFileInputStream protectedFileInputStream) {
                mUserPolicy = protectedFileInputStream.getUserPolicy();
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                int nRead;
                byte[] dataChunk = new byte[16384];
                try {
                    while ((nRead = protectedFileInputStream.read(dataChunk, 0, dataChunk.length)) != -1) {
                        buffer.write(dataChunk, 0, nRead);
                    }
                    buffer.flush();
                    mDecryptedContent = new String(buffer.toByteArray(), Charset.forName("UTF-8"));
                    buffer.close();
                    protectedFileInputStream.close();
                } catch (IOException e) {
                    updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
                    return;
                }
                updateTaskStatus(
                        new TaskStatus(TaskState.Completed, "Content was consumed", true, Signal.ContentConsumed));
            }
        };

        try {
            updateTaskStatus(new TaskStatus(TaskState.Starting, "Consuming content", true));

            ProtectedFileInputStream.create(inputStream, null, mRmsAuthCallback, mConsentCallback,
                    PolicyAcquisitionFlags.NONE, protectedFileInputStreamCreationCallback);
        } catch (com.microsoft.rightsmanagement.exceptions.InvalidParameterException e) {
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        }
    }

    /**
     * Start content consumption and read protected content from my own text file format 
     * 
     * My own File format:
     * serializedContentPolicy Length | serializedContentPolicy | Encrypted Content length | Encrypted Content
     * 
     * @param inputStream the input stream
     */
    public void startContentConsumptionFromMyOwnProtectedTextFileFormat(final InputStream inputStream) {
        // This is a 2 step process
        // 1. Create a UserPolicy from serializedContentPolicy
        // 2. Create a CustomProtectedInputStream using UserPolicy and read content from it.
        CreationCallback<UserPolicy> userPolicyCreationCallbackFromSerializedContentPolicy = new CreationCallback<UserPolicy>() {
            @Override
            public void onSuccess(UserPolicy userPolicy) {
                CreationCallback<CustomProtectedInputStream> customProtectedInputStreamCreationCallback = new CreationCallback<CustomProtectedInputStream>() {
                    @Override
                    public Context getContext() {
                        return mApplicationContext;
                    }

                    @Override
                    public void onCancel() {
                        updateTaskStatus(new TaskStatus(TaskState.Cancelled,
                                "CustomProtectedInputStream creation was cancelled", true));
                    }

                    @Override
                    public void onFailure(ProtectionException e) {
                        updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
                    }

                    @Override
                    public void onSuccess(CustomProtectedInputStream customProtectedInputStream) {
                        mUserPolicy = customProtectedInputStream.getUserPolicy();
                        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                        int nRead;
                        byte[] dataChunk = new byte[16384];
                        try {
                            while ((nRead = customProtectedInputStream.read(dataChunk, 0,
                                    dataChunk.length)) != -1) {
                                buffer.write(dataChunk, 0, nRead);
                            }
                            buffer.flush();
                            mDecryptedContent = new String(buffer.toByteArray(), Charset.forName("UTF-8"));
                            buffer.close();
                            customProtectedInputStream.close();
                        } catch (IOException e) {
                            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
                            return;
                        }
                        updateTaskStatus(new TaskStatus(TaskState.Completed, "Content was consumed", true,
                                Signal.ContentConsumed));
                    }
                };
                try {
                    // Step 2: Create a CustomProtectedInputStream using UserPolicy and read content from it.
                    // Retrieve the encrypted content size.
                    long encryptedContentLength = readUnsignedInt(inputStream);
                    updateTaskStatus(new TaskStatus(TaskState.Starting, "Consuming content", true));
                    CustomProtectedInputStream.create(userPolicy, inputStream, encryptedContentLength,
                            customProtectedInputStreamCreationCallback);
                } catch (com.microsoft.rightsmanagement.exceptions.InvalidParameterException e) {
                    updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
                } catch (IOException e) {
                    updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
                }
            }

            @Override
            public void onFailure(ProtectionException e) {
                updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
            }

            @Override
            public void onCancel() {
                updateTaskStatus(new TaskStatus(TaskState.Cancelled, "User policy aquisition was cancelled", true));
            }

            @Override
            public Context getContext() {
                return mApplicationContext;
            }
        };

        try {
            // Step 1: Create a UserPolicy from serializedContentPolicy
            // Read the serializedContentPolicyLength from the inputStream.
            long serializedContentPolicyLength = readUnsignedInt(inputStream);
            // Read the PL bytes from the input stream using the PL size.
            byte[] serializedContentPolicy = new byte[(int) serializedContentPolicyLength];
            inputStream.read(serializedContentPolicy);
            updateTaskStatus(new TaskStatus(TaskState.Starting,
                    "Acquring user policy to consume content from my own file format", true));

            UserPolicy.acquire(serializedContentPolicy, null, mRmsAuthCallback, mConsentCallback,
                    PolicyAcquisitionFlags.NONE, userPolicyCreationCallbackFromSerializedContentPolicy);
        } catch (com.microsoft.rightsmanagement.exceptions.InvalidParameterException e) {
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        } catch (IOException e) {
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        }
    }

    /**
     * Start content protection and serialize protected content to ptxt file format
     * 
     * @param contentToProtect the content to protect
     */
    public void startContentProtectionToPtxtFileFormat(final byte[] contentToProtect) {
        if (mUserPolicy == null) {
            Runnable onPolicyCreationCallback = new Runnable() {
                @Override
                public void run() {
                    createPTxt(contentToProtect);
                }
            };
            startMsipcPolicyCreationByTakingEmailId(false, onPolicyCreationCallback);
        } else {
            createPTxt(contentToProtect);
        }
    }

    /**
     * Start content protection and serialize protected content to my own file format.
     * 
     * @param contentToProtect the content to protect
     */
    public void startContentProtectionToMyOwnProtectedTextFileFormat(final byte[] contentToProtect) {
        if (mUserPolicy == null) {
            Runnable onPolicyCreationCallback = new Runnable() {
                @Override
                public void run() {
                    try {
                        createMyOwnFormatFileForProtectedText(contentToProtect);
                    } catch (FileNotFoundException e) {
                        updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
                    }
                }
            };
            startMsipcPolicyCreationByTakingEmailId(false, onPolicyCreationCallback);
        } else {
            try {
                createMyOwnFormatFileForProtectedText(contentToProtect);
            } catch (FileNotFoundException e) {
                updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
            }
        }
    }

    /**
     * MSIPC Create Policy as part of protection Operation.
     * 
     * @param showUserPolicyViewerOnPolicyCreation the show user policy viewer on policy creation
     */
    public void startMsipcPolicyCreation(final boolean showUserPolicyViewerOnPolicyCreation) {
        startMsipcPolicyCreationByTakingEmailId(showUserPolicyViewerOnPolicyCreation, null);
    }

    /**
     * # 1 Take user email
     * 
     * @param showUserPolicyViewerOnPolicyCreation the show user policy viewer on policy creation
     * @param onPolicyCreationCallback the on policy creation callback
     */
    private void startMsipcPolicyCreationByTakingEmailId(final boolean showUserPolicyViewerOnPolicyCreation,
            final Runnable onPolicyCreationCallback) {
        final UserPolicy originalUserPolicy = mUserPolicy;
        CompletionCallback<String> emailActivityCompletionCallback = new CompletionCallback<String>() {
            @Override
            public void onCancel() {
                updateTaskStatus(new TaskStatus(TaskState.Cancelled, "Email Activity was cancelled", false));
            }

            @Override
            public void onSuccess(String item) {
                updateTaskStatus(new TaskStatus(TaskState.Completed, "Email id was recieved", false));
                continueMsipcPolicyCreationWithEmailId(item, originalUserPolicy,
                        showUserPolicyViewerOnPolicyCreation, onPolicyCreationCallback);
            }
        };
        if (mEmailId == null || mEmailId.isEmpty()) {
            updateTaskStatus(new TaskStatus(TaskState.Starting, "Getting user's email id", false));
            EmailActivity.show(EMAIL_INPUT_REQUEST, getActivity(), emailActivityCompletionCallback);
        } else {
            continueMsipcPolicyCreationWithEmailId(mEmailId, originalUserPolicy,
                    showUserPolicyViewerOnPolicyCreation, onPolicyCreationCallback);
        }
    }

    /**
     * # 2.
     * 
     * @param emailId the email id
     * @param originalUserPolicy the original user policy
     * @param showUserPolicyViewerOnPolicyCreation the show user policy viewer on policy creation
     * @param onPolicyCreationCallback the on policy creation callback
     */
    private void continueMsipcPolicyCreationWithEmailId(final String emailId, final UserPolicy originalUserPolicy,
            boolean showUserPolicyViewerOnPolicyCreation, final Runnable onPolicyCreationCallback) {
        if (originalUserPolicy == null
                || (originalUserPolicy != null && originalUserPolicy.getType() == UserPolicyType.TemplateBased)) {
            // continue Template based Msipc Policy Creation
            continueMsipcPolicyCreationWithGettingTemplates(emailId, originalUserPolicy,
                    showUserPolicyViewerOnPolicyCreation, onPolicyCreationCallback);
        } else {
            // continue Customized Msipc Policy Creation

            // Note: Below code is a sample for Custom Policy Creation.
            // It's not invoked by this application.
            // A UserPolicy can be created either using templates or in a Customized way.
            // This code path creates a UserPolicy in a customized way.
            // Ideally following objects - UserRights, PolicyDescriptor would be created by using user inputs from a UI

            // create userRights list
            UserRights userRights = new UserRights(Arrays.asList("consumer@domain.com"),
                    Arrays.asList(CommonRights.View, EditableDocumentRights.Print));
            ArrayList<UserRights> usersRigthsList = new ArrayList<UserRights>();
            usersRigthsList.add(userRights);
            // Create PolicyDescriptor using userRights list
            PolicyDescriptor policyDescriptor = PolicyDescriptor
                    .createPolicyDescriptorFromUserRights(usersRigthsList);
            policyDescriptor.setOfflineCacheLifetimeInDays(10);
            policyDescriptor.setContentValidUntil(new Date());
            // Jump directly to #6 now.
            continueMsipcPolicyCreationByCreatingUserPolicy(policyDescriptor, showUserPolicyViewerOnPolicyCreation,
                    onPolicyCreationCallback);
        }
    }

    /**
     * # 3
     * 
     * @param emailId the email id
     * @param originalUserPolicy original User policy if re-publishing, else null
     * @param showUserPolicyViewerOnPolicyCreation the show user policy viewer on policy creation
     * @param onPolicyCreationCallback the on policy creation callback
     */
    private void continueMsipcPolicyCreationWithGettingTemplates(final String emailId,
            final UserPolicy originalUserPolicy, final boolean showUserPolicyViewerOnPolicyCreation,
            final Runnable onPolicyCreationCallback) {
        CreationCallback<List<TemplateDescriptor>> getTemplatesCreationCallback = new CreationCallback<List<TemplateDescriptor>>() {
            @Override
            public Context getContext() {
                return mApplicationContext;
            }

            @Override
            public void onCancel() {
                updateTaskStatus(new TaskStatus(TaskState.Cancelled, "Get Templates was cancelled", true));
            }

            @Override
            public void onFailure(ProtectionException e) {
                updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
            }

            @Override
            public void onSuccess(List<TemplateDescriptor> templateDescriptors) {
                mEmailId = emailId;// store email id after a successful msipc operation
                updateTaskStatus(new TaskStatus(TaskState.Completed, "Templates were recieved", true));
                TemplateDescriptor originalTemplateDescriptor = null;
                if (originalUserPolicy != null && originalUserPolicy.getType() == UserPolicyType.TemplateBased) {
                    originalTemplateDescriptor = originalUserPolicy.getTemplateDescriptor();
                }
                continueMsipcPolicyCreationByPickingAPolicy(templateDescriptors, originalTemplateDescriptor,
                        showUserPolicyViewerOnPolicyCreation, onPolicyCreationCallback);
            }
        };
        try {
            updateTaskStatus(new TaskStatus(TaskState.Starting, "Getting Templates", true));
            mIAsyncControl = TemplateDescriptor.getTemplates(emailId, mRmsAuthCallback,
                    getTemplatesCreationCallback);
        } catch (com.microsoft.rightsmanagement.exceptions.InvalidParameterException e) {
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        }
    }

    /**
     * # 4.
     * 
     * @param templateDescriptors the template descriptors
     * @param originalTemplateDescriptor the original template descriptor
     * @param showUserPolicyViewerOnPolicyCreation the show user policy viewer on policy creation
     * @param onPolicyCreationCallback the on policy creation callback
     */
    private void continueMsipcPolicyCreationByPickingAPolicy(List<TemplateDescriptor> templateDescriptors,
            TemplateDescriptor originalTemplateDescriptor, final boolean showUserPolicyViewerOnPolicyCreation,
            final Runnable onPolicyCreationCallback) {
        CompletionCallback<PolicyPickerActivityResult> policyPickerActivityCompletionCallback = new CompletionCallback<PolicyPickerActivityResult>() {
            @Override
            public void onCancel() {
                updateTaskStatus(new TaskStatus(TaskState.Cancelled,
                        "Template Descriptor Picker Activity was cancelled", false));
            }

            @Override
            public void onSuccess(PolicyPickerActivityResult policyPickerResult) {
                switch (policyPickerResult.mResultType) {
                case Template:
                    if (policyPickerResult.mTemplateDescriptor == null) {
                        updateTaskStatus(new TaskStatus(TaskState.Completed, "No protection was chosen", false));
                        mUserPolicy = null;
                    } else {
                        updateTaskStatus(new TaskStatus(TaskState.Completed, "A template was chosen", false));
                        continueMsipcPolicyCreationByCreatingUserPolicy(policyPickerResult.mTemplateDescriptor,
                                showUserPolicyViewerOnPolicyCreation, onPolicyCreationCallback);
                    }
                    break;
                case Custom:
                    if (policyPickerResult.mPolicyDescriptor == null) {
                        updateTaskStatus(new TaskStatus(TaskState.Completed, "No protection was chosen", false));
                        mUserPolicy = null;
                    } else {
                        updateTaskStatus(
                                new TaskStatus(TaskState.Completed, "Custom Permission was chosen", false));
                        continueMsipcPolicyCreationByCreatingUserPolicy(policyPickerResult.mPolicyDescriptor,
                                showUserPolicyViewerOnPolicyCreation, onPolicyCreationCallback);
                    }
                    break;
                }
            }
        };
        PolicyPickerActivity.show(POLICY_PICK_REQUEST, getActivity(), templateDescriptors,
                originalTemplateDescriptor, policyPickerActivityCompletionCallback);
    }

    /**
     * # 5.
     * 
     * @param selectedDescriptor the selected descriptor
     * @param showUserPolicyViewerOnPolicyCreation the show user policy viewer on policy creation
     * @param onPolicyCreationCallback the on policy creation callback
     */
    private void continueMsipcPolicyCreationByCreatingUserPolicy(Object selectedDescriptor,
            final boolean showUserPolicyViewerOnPolicyCreation, final Runnable onPolicyCreationCallback) {
        CreationCallback<UserPolicy> userPolicyCreationCallback = new CreationCallback<UserPolicy>() {
            @Override
            public Context getContext() {
                return mApplicationContext;
            }

            @Override
            public void onCancel() {
                updateTaskStatus(new TaskStatus(TaskState.Cancelled, "User Policy creation was cancelled", true));
            }

            @Override
            public void onFailure(ProtectionException e) {
                updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
            }

            @Override
            public void onSuccess(final UserPolicy item) {
                updateTaskStatus(new TaskStatus(TaskState.Completed, "User Policy Created", true));
                // # 6
                mUserPolicy = item;
                // # 7
                if (showUserPolicyViewerOnPolicyCreation) {
                    showUserPolicy();
                }
                if (onPolicyCreationCallback != null) {
                    onPolicyCreationCallback.run();
                }
            }
        };
        try {
            if (selectedDescriptor.getClass().equals(TemplateDescriptor.class)) {
                updateTaskStatus(new TaskStatus(TaskState.Starting, "Creating template based user policy", true));
                mIAsyncControl = UserPolicy.create((TemplateDescriptor) selectedDescriptor, mEmailId,
                        mRmsAuthCallback, UserPolicyCreationFlags.NONE, null, userPolicyCreationCallback);
            } else if (selectedDescriptor.getClass().equals(PolicyDescriptor.class)) {
                updateTaskStatus(new TaskStatus(TaskState.Starting, "Creating custom user policy", true));
                mIAsyncControl = UserPolicy.create((PolicyDescriptor) selectedDescriptor, mEmailId,
                        mRmsAuthCallback, UserPolicyCreationFlags.NONE, userPolicyCreationCallback);
            } else {
                Logger.ie(TAG, "invalid selectedDescriptor");
            }
        } catch (InvalidParameterException e) {
            Logger.e(TAG, "Invalid Parameter", "", e);
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        }
    }

    // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // /////////////////////////////////////////END OF MSIPC OPERATIONS/////////////////////////////////////////////////
    // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * Creates the p txt.
     * 
     * @param contentToProtect the content to protect
     */
    private void createPTxt(final byte[] contentToProtect) {
        OutputStream outputStream = null;
        String originalFileExtension = App.PLAIN_TEXT_FILE_SUFFIX;
        String originalFileName = "sample" + originalFileExtension;
        final String filePath = App.getInstance().getStorageDirectory() + "/"
                + originalFileName.substring(0, originalFileName.lastIndexOf('.')) + ".ptxt";
        CreationCallback<ProtectedFileOutputStream> protectedFileOutputStreamCreationCallback = new CreationCallback<ProtectedFileOutputStream>() {
            @Override
            public Context getContext() {
                return mApplicationContext;
            }

            @Override
            public void onCancel() {
                invalidateUserPolicy();
                updateTaskStatus(new TaskStatus(TaskState.Cancelled,
                        "ProtectedFileOutputStream creation was cancelled", true));
            }

            @Override
            public void onFailure(ProtectionException e) {
                updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
            }

            @Override
            public void onSuccess(ProtectedFileOutputStream item) {
                try {
                    // write to this stream
                    item.write(contentToProtect);
                    item.flush();
                    item.close();
                    mProtectedContentFilePath = filePath;
                    updateTaskStatus(new TaskStatus(TaskState.Completed, "Content protected", true,
                            Signal.ContentProtected));
                } catch (IOException e) {
                    updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
                }
            }
        };
        try {
            File file = new File(filePath);
            outputStream = new FileOutputStream(file);
            mIAsyncControl = ProtectedFileOutputStream.create(outputStream, mUserPolicy, originalFileExtension,
                    protectedFileOutputStreamCreationCallback);
        } catch (FileNotFoundException e) {
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        } catch (InvalidParameterException e) {
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        }
    }

    /**
     * Serialized protected content to a txt2 file format. My own File format: serializedContentPolicy Length |
     * serializedContentPolicy | Encrypted Content length | Encrypted Content
     * 
     * @param contentToProtect the content to protect
     * @throws FileNotFoundException
     */
    private void createMyOwnFormatFileForProtectedText(final byte[] contentToProtect) throws FileNotFoundException {
        final String filePath = App.getInstance().getStorageDirectory() + "/" + "sample.txt2";
        File file = new File(filePath);
        final OutputStream outputStream = new FileOutputStream(file);
        CreationCallback<CustomProtectedOutputStream> customProtectedOutputStreamCreationCallback = new CreationCallback<CustomProtectedOutputStream>() {
            @Override
            public Context getContext() {
                return mApplicationContext;
            }

            @Override
            public void onCancel() {
                invalidateUserPolicy();
                updateTaskStatus(new TaskStatus(TaskState.Cancelled,
                        "CustomProtectedOutputStream creation was cancelled", true));
            }

            @Override
            public void onFailure(ProtectionException e) {
                updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
            }

            @Override
            public void onSuccess(CustomProtectedOutputStream protectedOutputStream) {
                try {
                    // write serializedContentPolicy
                    byte[] serializedContentPolicy = mUserPolicy.getSerializedContentPolicy();
                    writeLongAsUnsignedIntToStream(outputStream, serializedContentPolicy.length);
                    outputStream.write(serializedContentPolicy);
                    // write encrypted content
                    if (contentToProtect != null) {
                        writeLongAsUnsignedIntToStream(outputStream,
                                CustomProtectedOutputStream.getEncryptedContentLength(contentToProtect.length,
                                        protectedOutputStream.getUserPolicy()));
                        protectedOutputStream.write(contentToProtect);
                        protectedOutputStream.flush();
                        protectedOutputStream.close();
                    } else {
                        outputStream.flush();
                        outputStream.close();
                    }
                    mProtectedContentFilePath = filePath;
                    updateTaskStatus(new TaskStatus(TaskState.Completed,
                            "Content protected into my own file format", true, Signal.ContentProtected));
                } catch (IOException e) {
                    updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
                }
            }
        };
        try {
            mIAsyncControl = CustomProtectedOutputStream.create(outputStream, mUserPolicy,
                    customProtectedOutputStreamCreationCallback);
        } catch (InvalidParameterException e) {
            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
        }
    }

    /**
     * helper method to create consentCallback
     * 
     * @return consentCallback
     */
    private ConsentCallback getConsentCallback() {
        return new ConsentCallback() {
            @Override
            public void consents(Collection<Consent> consents,
                    final ConsentCompletionCallback consentCompletionCallback) {
                // create callback to process result from consent screen
                CompletionCallback<Collection<Consent>> consentActivityCompletionCallback = new CompletionCallback<Collection<Consent>>() {
                    @Override
                    public void onCancel() {
                        updateTaskStatus(
                                new TaskStatus(TaskState.Cancelled, "Consent Activity was cancelled", false));
                    }

                    @Override
                    public void onSuccess(Collection<Consent> item) {
                        try {
                            consentCompletionCallback.submitConsentsWithConsentResults(item);
                        } catch (ProtectionException e) {
                            updateTaskStatus(new TaskStatus(TaskState.Faulted, e.getLocalizedMessage(), true));
                            return;
                        }
                    }
                };
                // show the consent page
                ConsentActivity.show(CONSENT_REQUEST, getActivity(), consents, consentActivityCompletionCallback);
            }
        };
    }

    /**
     * Update task status.
     * 
     * @param taskStatus the task status
     */
    private void updateTaskStatus(final TaskStatus taskStatus) {
        if (taskStatus.mPostToCaller) {
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(new Runnable() {
                @Override
                public void run() {
                    if (mTaskEventCallback != null) {
                        mLatestUnpostedTaskStatus = null;
                        mTaskEventCallback.onMsipcTaskUpdate(taskStatus);
                    } else {
                        mLatestUnpostedTaskStatus = taskStatus;
                    }
                }
            });
        }
    }

    /**
     * Read an unsigned Integer from an input stream. This method is used for the IRM file structure.
     * 
     * @param input the Input stream.
     * @return the unsigned integer as a signed long.
     * @throws IOException signals that a general IOException has occurred.
     */
    private static long readUnsignedInt(InputStream input) throws IOException {
        byte[] fourBytes = new byte[4];
        if (input.read(fourBytes) != fourBytes.length) {
            throw new IOException("Failed to read " + fourBytes.length + " Bytes of data");
        }
        return toLongChangeOrder(fourBytes);
    }

    /**
     * Write long as unsigned Integer to output stream.
     * 
     * @param outputStream The output stream to write the value.
     * @param value The value being written.
     * @throws IOException signals that an I/O exception has occurred.
     */
    private static void writeLongAsUnsignedIntToStream(OutputStream outputStream, long value) throws IOException {
        outputStream.write((byte) (value & 0x00000000000000FF));
        outputStream.write((byte) ((value & 0x000000000000FF00) >>> 8));
        outputStream.write((byte) ((value & 0x0000000000FF0000) >>> 16));
        outputStream.write((byte) ((value & 0x00000000FF000000) >>> 24));
    }

    /**
     * Change byte order and convert to long.
     * 
     * @param uintArray the UINT array
     * @return the Integer.
     * @throws IOException signals that a general IOException has occurred.
     */
    private static long toLongChangeOrder(byte[] uintArray) throws IOException {
        if (uintArray.length != 4) {
            throw new IOException("Byte array cannot be converted to UINT");
        }
        // The ONE_BYTE_MASK is used to prevent errors that are due to byte being singed and << being a signed operator.
        long res = (0x00000000000000FFL & uintArray[0]);
        res |= ((0x00000000000000FFL & uintArray[1]) << 8);
        res |= ((0x00000000000000FFL & uintArray[2]) << 16);
        res |= ((0x00000000000000FFL & uintArray[3]) << 24);
        return res;
    }
}