Moxtra Clip SDK for Android

This guide outlines the stpes for you to get started quickly with the Moxtra Clip SDK for Android that will enable adding visual and voice annotations on top of your Android App or Documents.

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

Step 1: Workspace Setup

Download Clip 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 Clip

To create a clip, you need to first get an instance of MXClipManager. With this instance you will be able to make the calls related to clip as mentioned in this section:

 

Get Instance

static publicMXClipManagergetInstance();

Get an instance of Moxtra Clip Manager.

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

 

Create Clip on your App View

public void recordClipWithView(Activity activity, final OnMXClipListener listener);

Capture the content from your app screen, add voice to it and let the users share the clip as video from your app.

Parameters:

      activity - The activity to be recorded, if set to null recording will be on the app screen. Otherwise, it will only record the specified activity. When activity is destroyed, recording will stop, and fire record failed callback with error code: MXClipError.MXCLIP_ERROR_CLIPPED_VIEW_HAS_DESTROYED.
      listener - Callback to notify about the events of clip. Please check OnMXClipListener for details.

Exceptions:

      Unauthorized - User not not initialized successfully.
      ClipIsInProgress - Another clip recording is already in progress.
      InvalidParameter - The input parameters are invalid.

Example:

try {
    MXClipManager.getInstance().recordClipWithView(this, this);
} catch (ClipIsInProgress e) {
    clipInProgress();
} catch (Unauthorized e) {
    unauthorized();
}

 

Create Clip on Documents and Images

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

Annotate, add voice to the content (documents, images etc...) and let users share the clip as video from your app.

Note: Single file size has limit for 100M.

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.
      ClipIsInProgress - Another clip recording is already in progress.
      InvalidParameter - The input parameters are invalid.

Example:

try {
    MXClipManager.getInstance().recordClipWithLocalFiles(Arrays.asList(path1), this);
} catch (IOException e) {
    e.printStackTrace();
} catch (InvalidParameter e) {
    e.printStackTrace();
} catch (ClipIsInProgress e) {
    clipInProgress();
} catch (Unauthorized e) {
    unauthorized();
}

 

Create Clip on remote files

Recording video clip for remote files with annotation on. To start Moxtra clip for remote files, it need get MXClipManager instance, and call the API:

public void recordClipWithRemoteFiles (final OnMXClipListener listener)

Example:

try {
    MXClipManager.getInstance().recordClipWithRemoteFiles(this);
} catch (ClipIsInProgress e) {
    clipInProgress();
} catch (Unauthorized e) {
    unauthorized();
}

Then listen the callback:

public void onClipPrepareSuccess(String binderID, String token)

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

public void setRecordClipRemoteFileIDs(List<String> fileUniqueIDArray)

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

Example:

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().setRecordClipRemoteFileIDs(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 uploadRecordClipRemoteFilesFailed()

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

 

Other Clip API References

OnMXClipListener

public interface OnMXClipListener {
    public void onError(int errorCode);
    public void onClipPrepareSuccess(String binderID, String token);
    public void onAnnotatePrepareSuccess(String binderID, String token);
}

MXClipError

public class MXClipError {
    public final static int MXCLIP_ERROR_UNKNOWN = -1000;
    public final static int MXCLIP_ERROR_CLIP_OR_ANNOTATION_ALREADY_STARTED = 100;
    public final static int MXCLIP_ERROR_NETWORK_OFFLINE = 101;
    public final static int MXCLIP_ERROR_CLIPPED_VIEW_HAS_DESTROYED = 102;
    public final static int MXCLIP_ERROR_USER_CANCEL = 103;
    public final static int MXCLIP_ERROR_CLIP_ANNOTATION_FAILED = 104;
}