Moxtra Draw SDK for Android

This guide outlines the stpes for you to get started quickly with the Moxtra Draw SDK for Android that will enable adding visual annotations on top of Documents & Images.

Before proceeding further, ensure you have registered your app with Moxtra.

Step 1: Workspace Setup

Download Draw SDK for Android, unzip the downloaded file and follow the steps below.

Android Studio Setup

Now Android Studio is the official IDE for Android, and other IDEs should be migrated to Android Studio to get new features support. So we strongly recommend using Android Studio. If using eclipse or other IDE Moxtra SDK may not work as expected.

Start a new empty project or open your existing project and click "Import Module"

  • Android Studio v1.2 or higher: File -> New -> Import Module
     


     
  • Android Studio v1.1 or lower: File -> New -> Import Module
     


     

Select Moxtra SDK directory location, and click OK to import the Moxtra SDK into the project. NOTE: Moxtra SDK is contained in Moxtra SDK demo project, so import moxtra directory as module and do not need to import the whole demo project.

Moxtra Android SDK

Click on "Finish" to import Moxtra SDK module as shown below:

Moxtra Android SDK

Now, let's add the Moxtra SDK as a dependency to your project as shown below:

  • Select your Project -> Right Click on it -> Click on Open Module Settings
     


     
  • Select your project's app module(default module name) -> Open Dependencies tab -> Click Add (+) -> Choose Module dependency
     


     
  • Select "moxtra" SDK module -> Click OK
     


     

Now, define the following variables in the gradle.properties file as shown below. You may need to change the variables according to your dev environment and requirements.

ANDROID_BUILD_MIN_SDK_VERSION=14
ANDROID_BUILD_TARGET_SDK_VERSION=21
ANDROID_BUILD_TOOLS_VERSION=21.1
ANDROID_BUILD_SDK_VERSION=21

Step 2: Update AndroidMaifest.xml

There are some changes you need to make in AndroidManifest.xml to grant permissions and specify the required application components.

To enable the required features please add the following:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>

You must register your App in Moxtra developer website to get the client id and secret. Moxtra SDK can not work correctly if you do not do this. Do declare this part in AndroidManifest.xml.

<meta-data android:name="com.moxtra.sdk.ClientId" android:value="your_client_id" />
<meta-data android:name="com.moxtra.sdk.ClientSecret" android:value="your_client_secret" />

Set sandbox to "true" before your app go into production. After your app go to production, you should set it to "false".

<meta-data android:name="com.moxtra.sdk.SandboxEnv" android:value="true" />

To declare the required activities please add the following:

<activity
    android:name="com.moxtra.binder.activity.DialogFragmentActivity"
    android:theme="@style/MoxtraTheme"
    android:windowSoftInputMode="stateHidden|adjustResize" >
</activity>
<activity
    android:name="com.moxtra.binder.meet.MXLiveShareViewActivity"
    android:launchMode="singleTask"
    android:theme="@style/MoxtraTheme"
    android:windowSoftInputMode="stateHidden|adjustPan" >
</activity>
<activity
    android:name="com.moxtra.binder.MXTransparentActivity"
    android:launchMode="singleTask"
    android:theme="@style/MoxFullTranslucentActivity"
    android:windowSoftInputMode="stateHidden|adjustPan" >
</activity>
<activity
    android:name="com.moxtra.binder.livemeet.MXSDKMeetActivity"
    android:launchMode="singleTask"
    android:theme="@style/MoxtraTheme">
</activity>
<service android:name="com.moxtra.sdk.MoxtraMeetSdkService" />
<activity
    android:name="com.moxtra.binder.activity.MXStackActivity"
    android:theme="@style/MXActivityDialog"
    android:windowSoftInputMode="stateHidden|adjustResize" >
</activity>
<activity
    android:name="com.moxtra.binder.member.MXInviteActivity"
    android:theme="@style/MXActivityDialog"
    android:windowSoftInputMode="stateHidden" >
</activity>
<activity
    android:name="com.moxtra.binder.conversation.MXConversationActivity"
    android:launchMode="singleTask"
    android:windowSoftInputMode="stateHidden|adjustResize"
    android:theme="@style/MoxtraTheme" >
</activity>
<activity 
    android:name="com.moxtra.binder.pageview.PageViewActivity"
    android:launchMode="singleTask"
    android:windowSoftInputMode="stateHidden|adjustPan"
    android:theme="@style/MoxtraTheme" >
</activity>
<activity 
    android:name="com.moxtra.binder.livemeet.LiveMeetActivity"
    android:launchMode="singleTask"
    android:theme="@style/MoxtraTheme" >
</activity>
<activity 
    android:name="com.moxtra.binder.multiimagepicker.MultiImagePickerActivity"
    android:theme="@style/MoxtraTheme" >
</activity>
<activity
    android:name="com.moxtra.binder.util.MXAlertDialog"
    android:theme="@style/MoxFullTranslucentActivity"
    android:windowSoftInputMode="stateHidden" >
</activity>
<activity android:name="com.moxtra.binder.search.MXSearchActivity" android:theme="@style/MoxtraTheme"/>
<activity android:name="com.moxtra.binder.webnote.MXWebNoteActivity" android:theme="@style/MoxtraTheme"/>
<activity android:name="com.moxtra.binder.webclip.MXWebClipActivity" android:theme="@style/MoxtraTheme"/>
<activity android:name="com.moxtra.binder.livemeet.MeetRingActivity" android:theme="@style/MoxtraTheme"/>
<service android:name=".service.AudioPlayerService" />

For better user expierence, defined the below-mentioned theme or use MoxtraTheme (in res/values/styles.xml):

<style name="MoxtraTheme" parent="AppBaseTheme">
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowAnimationStyle">@style/MoxActivityAnimation</item>
    <item name="android:textViewStyle">@style/MoxTextViewBase</item>
    <item name="android:listViewStyle">@style/MoxListViewBase</item>
</style>

For more information on the AndroidManifest.xml file see this link.

Step 3: Implement the login/logout function

We will not have signup in our demo app but using the dummy data we created in step 3.

Also, we will not cover everything about the login but only the Moxtra Chat SDK related part. All the user management should be done in your app. The Moxtra Chat SDK could not help on the part.

What we need to do for login is:

Login Flow

First, let's initialize the MXAccountManager. We recommend to initialize the MXAccountManager very first when starting the app. So it's a good place to init it in your Application. In our app, we init it in the MoxieChatApplication. Here is the code:

@Override
public void onCreate() {
    super.onCreate();
    try {
        MXAccountManager.createInstance(this);
    } catch (MXSDKException.InvalidParameter invalidParameter) {
        Log.e(TAG, "Error when creating MXAccountManager instance.", invalidParameter);
    }
}

After login success on the app, we need to setup the user in Moxtra so we can use the moxtra service.

We will add it in the LoginActivity.

// Login success and then setup user on Moxtra
User user = PreferenceUtil.getUser(LoginActivity.this);
try {
    Bitmap avatar = BitmapFactory.decodeStream(LoginActivity.this.getAssets().open(user.avatarPath));
    MXSDKConfig.MXUserInfo mxUserInfo = new MXSDKConfig.MXUserInfo(user.email, MXSDKConfig.MXUserIdentityType.IdentityUniqueId);
    MXSDKConfig.MXProfileInfo mxProfileInfo = new MXSDKConfig.MXProfileInfo(user.firstName, user.lastName, avatar);
    MXAccountManager.getInstance().setupUser(mxUserInfo, mxProfileInfo, null, null, LoginActivity.this);
} catch (IOException e) {
    Log.e(TAG, "Can't decode avatar.", e);
}

The setupUser is an async operation and we have to pass a callback to it. In our code, the callback the the LoginActivity which means we have to implement the callback interface. Here is the code:

@Override
public void onLinkAccountDone(boolean success) {
    if (success) {
        Log.i(TAG, "Linked to moxtra account successfully.");
        startConferenceListActivity();
    } else {
        Toast.makeText(this, "Failed to setup moxtra user.", Toast.LENGTH_LONG).show();
        Log.e(TAG, "Failed to setup moxtra user.");
        showProgress(false);
    }
}

For the logout, you should unlink the Moxtra account after user successfully logout from your app. In our demo app, it was implemented in the BaseActivity Action Toolbar so user can logout from any activity that extends from BaseActivity.

MXAccountManager.getInstance().unlinkAccount(this);

Step 4: Create Annotation

To use the Draw APIs for annotations, you need to first get an instance of MXClipManager. With this instance you will be able to make the calls mentioned in this section:

 

Get Instance

static publicMXClipManagergetInstance();

Get an instance of Moxtra Clip Manager.

Sample code:
MXClipManager clipMgr = MXClipManager.getInstance();

 

Create Annotation on Documents and Images

Public void annotateOnLocalFiles(final List<String> filePath, final OnMXClipListener listener);

Annotate on top of the content (documents, images etc...) and let users save and share the annotated file from your app.

Parameters:

      filePath - Local device path to the file(s).
      listener - Callback to notify about the events of clip. Please check OnMXClipListener for details.

Exceptions:

      Unauthorized - User not not initialized successfully.
      AnnotationIsInProgress - Another annotation session is already in progress.
      InvalidParameter - The input parameters are invalid.

Example:

try {
    MXClipManager.getInstance().annotateOnLocalFiles(Arrays.asList(path1), this);
} catch (IOException e) {
    e.printStackTrace();
} catch (InvalidParameter e) {
    e.printStackTrace();
} catch (AnnotationIsInProgress e) {
    annotationInProgress();
} catch (Unauthorized e) {
    unauthorized();
}

Note: Single file size has limit for 100M.

 

Create Annotation on remote files

To start Moxtra annotation for remote files, it need get MXClipManager instance, and call the API.

public void annotateWithRemoteFiles (final OnMXClipListener listener)

Example:

try {
    MXClipManager.getInstance().annotateWithRemoteFiles(this);
} catch (AnnotationIsInProgress e) {
    annotationInProgress();
} catch (Unauthorized e) {
    unauthorized();
}

Then listen the callback:

public void onAnnotatePrepareSuccess(String binderID, String token)

If you get this callback, please call this API to set remote fileIDs:

void setAnnotateRemoteFileIDs (List<String> fileUniqueIDArray)

And next to upload files to our Moxtra server by REST API.

String path1 = f1.getAbsolutePath();
String path2 = f2.getAbsolutePath();
String uuid1 = UUID.randomUUID().toString();
String uuid2 = UUID.randomUUID().toString();

String url1 = String.format("https://www.moxtra.com/board/%s/%s?type=original&client_uuid=%s&t=%s", binderID, "file1.pdf", uuid1, path1);
String url2 = String.format("https://www.moxtra.com/board/%s/%s?type=original&client_uuid=%s&t=%s", binderID, "file2.pdf", uuid2, path2);

MXClipManager.getInstance().setAnnotateRemoteFileIDs(Arrays.asList(uuid1, uuid2));

// Upload the file via rest API

If there are some errors for uploading, please call this API to reset UI.

public void uploadAnnotateRemoteFilesFilesFailed()

And next to upload files to our Moxtra server by REST API.

Note:
1. Single file size has limit for 100M.
2. setAnnotateRemoteFileIDs() should be called before upload, otherwise, it may miss some server progress and has an error upload state, that cannot record.