Android Documentation

Last updated: Oct 25th, 2016

Getting Started

A library that gives you access to the powerful Mesosfer cloud platform from your Android app. For more information about Mesosfer and the features, see Mesosfer Website. You can also check out our API Reference for more detailed information about our SDK. Let's get started to setup your first mesosfer project for Android.

Download

  1. Download the latest AAR and copy it on libs directory.
  2. Define in your app module build.gradle this code below before dependencies.
    
    repositories{
        flatDir {
            dirs 'libs'
        }
    }
    
    

    Then add this code below on dependencies :
    
    compile 'com.eyro.mesosfer:MesosferSDK-Android:0.1.0@aar'
    
    

Setup

  1. Register first to Mesosfer Cloud.
  2. Create an application to get applicationId and clientKey.
  3. Add this line below to your Application class to initialize Mesosfer SDK
    
    Mesosfer.initialize(this, "YOUR-APPLICATION-ID-HERE", "YOUR-CLIENT-KEY-HERE");
    
    

    Don't forget to initialize your application class to AndroidManifest.xml
    (Optional) You can add some custom setup :
    • Enable Mesosfer SDK debug logging by calling Mesosfer.setLogLevel(int); before initialize SDK
    • Mesosfer Log Level Mode : LOG_LEVEL_VERBOSE, LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_WARNING, LOG_LEVEL_ERROR, LOG_LEVEL_NONE

Managing Users

Mesosfer provide a specialized bucket User that automatically handles much of the functionality required for user management. With this bucket, you’ll be able to manage user account functionality in your app.

Register

The first thing your app will do is probably ask the user to register. The following code illustrates a typical register:


// create new instance of Mesosfer User
MesosferUser newUser = MesosferUser.createUser();

// set default field
newUser.setEmail("user.one@mesosfer.com");
newUser.setPassword("user1234");
newUser.setFirstName("User");
newUser.setLastName("One");

// set custom field
newUser.setData("dateOfBirth", new Date());
newUser.setData("height", 177.5);
newUser.setData("weight", 78);
newUser.setData("isMarried", true);
newUser.setData("myObject", new JSONObject());
newUser.setData("myArray", new JSONArray());

// execute register user asynchronous
newUser.registerAsync(new RegisterCallback() {
    @Override
    public void done(MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // register succeeded
    }
}); 

This call will asynchronously create a new user in your Mesosfer App. Before it starts, the call will checks to make sure that the email are unique. Also, it also securely hashes the password in the cloud using bcrypt. We never store passwords in plaintext, nor transmit passwords back to the client in plaintext.

If a register isn’t successful, you should read the MesosferException that is returned. The most likely case is that the email has already been taken by another user. You should communicate this to your user clearly, and ask them to try a different email.

Login

After you allow users to register, you need be able to let them log in to their account in the future. To do this you can use several method for handling action in login process.

Session User

It would be bothersome if the user had to login every time they open your app. You can avoid this by using the cached currentUser object.

Whenever you use any register or login methods, the user is cached on disk. You can treat this cache as a session, and automatically assume the user is logged in:


MesosferUser user = MesosferUser.getCurrentUser();
if (user != null) {
    // user logged in, open main activity
} else {
    // session not found, open login activity
}

Log In User

After you allow users to register, you need be able to let them login to their account in the future. To do this, you can use the class method logInAsync.


MesosferUser.logInAsync("myUsername", "myPlainPassword", new LogInCallback() {
    @Override
    public void done(MesosferUser user, MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // log in succeeded
    }
});

Log Out User

You can clear the current user by logging them out:


MesosferUser.logOutAsync(new LogOutCallback() {
    @Override
    public void done(MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // log out succeeded
    }
});

Retreive Current User

Mesosfer allow you to retreive current user attributes and update all of them.

Fetch User

If you need to fetch data on a current user with the latest data that is in the cloud, you can call the fetchAsync method like so:


MesosferUser user = MesosferUser.getCurrentUser();
user.fetchAsync(new GetCallback() {
    @Override
    public void done(MesosferUser mesosferUser, MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // fetch user data succeeded
    }
});

This will automatically update currentUser with the latest data from cloud.

Update User

After logged in, you can update your data that stored in cloud using method updateDataAsync.


MesosferUser user = MesosferUser.getCurrentUser();
// set default field
user.setFirstName("updatedFirstname");
user.setLastName("updatedLastname");
// set custom field
user.setData("dateOfBirth", new Date());
user.setData("height", 180.5);
user.setData("weight", 85);
user.setData("isMarried", false);
// execute update user
user.updateDataAsync(new SaveCallback() {
    @Override
    public void done(MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // update user data succeeded
    }
});

Change Password

If you want to change your current password, use method changePasswordAsync:


MesosferUser user = MesosferUser.getCurrentUser();
user.changePasswordAsync("oldPassword", "newPassword", new ChangePasswordCallback() {
    @Override
    public void done(MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // change password succeeded
    }
});

Query User

Mesosfer allow you to retreive users data using special query. There are serveral types of Mesosfer Query : Basic Query, Query Constraint, and Query on String, and Counting.

Basic Query User

In many cases, there is a condition that need to specify which user you want to retrieve. The MesosferQuery offers different ways to retrieve a list of users. The general pattern is to create a MesosferQuery, put conditions on it, and then retrieve a List of matching MesosferUsers using the findAsync method with a FindCallback. For example, to retrieve users with a firstname, use the whereEqualTo method to constrain the value for a key:


MesosferQuery query = MesosferUser.getQuery();
query.whereEqualTo("firstname", "John");
query.findAsync(new FindCallback() {
    @Override
    public void done(List list, MesosferException e) {
        if (e != null) {
            // exception happen, handle the message
            return;
        } 

        // found the users, show in listview
    }
});

Query Constraint

There are several ways to put constraints on the objects found by a MesosferQuery. You can filter out users with a particular key-value pair with whereNotEqualTo:


query.whereNotEqualTo("firstname", "John");

You can give multiple constraints, and users will only be in the results if they match all of the constraints. In other words, it’s like an AND of constraints.


query.whereNotEqualTo("firstname", "John");
query.whereGreaterThan("height", 170);

You can limit the number of results with setLimit. By default, results are limited to 100, but anything from 1 to 1000 is a valid limit:


query.setLimit(20); // limit to at most 20 results

You can skip the first results with setSkip. This can be useful for pagination:


query.setSkip(10); // skip the first 10 results

For sortable types like numbers and strings, you can control the order in which results are returned:


// Sorts the results in ascending order by the user height
query.orderByAscending("height");

// Sorts the results in descending order by the user height
query.orderByDescending("height");

You can add more sort keys to the query as follows:


// Sorts the results in ascending order by the user height field if the previous sort keys are equal.
query.addAscendingOrder("height");

// Sorts the results in descending order by the user weight field if the previous sort keys are equal.
query.addDescendingOrder("weight");

For sortable types, you can also use comparisons in queries:


// Restricts to height < 170
query.whereLessThan("height", 170);

// Restricts to height <= 170
query.whereLessThanOrEqualTo("height", 170);

// Restricts to height > 170
query.whereGreaterThan("height", 170);

// Restricts to height >= 170
query.whereGreaterThanOrEqualTo("height", 170);

Query on String

Use whereStartsWith to restrict to string values that start with a particular string. Similar to a MySQL LIKE operator, this is indexed so it is efficient for large datasets:


// Finds user email that start with 'john'.
MesosferQuery query = MesosferUser.getQuery();
query.whereStartsWith("email", "john");

The example above will match any MesosferUser where the value in the email String key starts with “john”. For example, both “john.doe@nomail.com” and “john.cena@nomail.com” will match, but “big.john@okmail.com” or “little.john@okmail.com” will not.

Use whereEndsWith to restrict to string values that end with a particular string.


// Finds user email that end with '@okmail.com'.
MesosferQuery query = MesosferUser.getQuery();
query.whereEndsWith("email", "@okmail.com");

The above example will match any MesosferUser where the value in the email String key ends with “@okmail.com”. For example, both “big.john@okmail.com” and “little.john@okmail.com” will match, but “john.doe@nomail.com” or “john.cena@nomail.com” will not.

Counting

If you only need to count how many objects match a query, but you do not need to retrieve all the objects that match, you can use count instead of find. For example, to count how many users have height greater than 170 centimetres:


MesosferQuery query = MesosferUser.getQuery();
query.whereGreaterThan("height", 170);
query.countAsync(new CountCallback() {
    @Override
    public void done(int count, MesosferException e) {
        if (e != null) {
            // exception happen, handle the message
            return;
        } 

        // counting succeeded, show users count
    }
});

Managing Data

Storing data on Mesosfer is built around the MesosferData. Each MesosferData contains key-value pairs of JSON-compatible data. This data is using schema, which means that you need to specify ahead of time what keys exist on each MesosferData from our Mesosfer Cloud. Then you can simply set a key-value pairs you want to save, and our backend will store it.

For example, let's say you set a Beacon parameters. A single MesosferData could contain :


"isActive":true, "major":1, "name":"Beacon One", "minor":284, "proximityUUID":"CB10023F-A318-3394-4199-A8730C7C1AEC"

Keys must be alphanumeric strings. Values can be Strings, Numbers, Dates, Booleans, or even Arrays and Objects - anything that can be JSON-encoded.

Saving Data

Let’s say you want to save the Beacon described above to the Mesosfer Cloud. The interface is similar to a Map, plus the saveAsync method:


MesosferData data = MesosferData.createData("Beacon");
// set data
data.setData("name", "Beacon One");
data.setData("proximityUUID", "CB10023F-A318-3394-4199-A8730C7C1AEC");
data.setData("major", 1);
data.setData("minor", 284);
data.setData("isActive", true);
data.setData("timestamp", new Date());
// execute save data
data.saveAsync(new SaveCallback() {
    @Override
    public void done(MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // data saved, show success message
    }
});

Retrieve a Data

If you need to fetch a data with the latest data that is in the cloud, you can call the fetchAsync method like so:


// create data from existing objecId
MesosferData data = MesosferData.createWithObjectId("objectId");
// fetching the data
user.fetchAsync(new GetCallback() {
    @Override
    public void done(MesosferData data, MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // fetch data succeeded
    }
});

This will automatically update data with the latest data from cloud.

Querying Data

There are many other ways to retrieve data with Mesosfer Query. You can retrieve many data at once, put conditions on the data you wish to retrieve.

Basic Query

In many cases, there is a condition that need to specify which datas you want to retrieve. The MesosferQuery offers different ways to retrieve a list of datas. The general pattern is to create a MesosferQuery, put conditions on it, and then retrieve a List of matching MesosferDatas using the findAsync method with a FindCallback. For example, to retrieve Beacons data with a name, use the whereEqualTo method to constrain the value for a key:


MesosferQuery query = MesosferData.getQuery("Beacon");
query.whereEqualTo("name", "Beacon One");
query.findAsync(new FindCallback() {
    @Override
    public void done(List list, MesosferException e) {
        if (e != null) {
            // exception happen, handle the message
            return;
        } 

        // found the beacons, show in listview
    }
});

Query Constraint

There are several ways to put constraints on the datas found by a MesosferQuery. You can filter out datas with a particular key-value pair with whereNotEqualTo:


query. whereNotEqualTo("name", "Beacon One");

You can give multiple constraints, and datas will only be in the results if they match all of the constraints. In other words, it’s like an AND of constraints.


query.whereNotEqualTo("name", "Beacon One");
query.whereGreaterThan("major", 1);

You can limit the number of results with setLimit. By default, results are limited to 100, but anything from 1 to 1000 is a valid limit:


query.setLimit(20); // limit to at most 20 results

You can skip the first results with setSkip. This can be useful for pagination:


query.setSkip(10); // skip the first 10 results

For sortable types like numbers and strings, you can control the order in which results are returned:


// Sorts the results in ascending order by the beacon's major
query.orderByAscending("major");

// Sorts the results in descending order by the beacon's minor
query.orderByDescending("minor");

You can add more sort keys to the query as follows:


// Sorts the results in ascending order by the beacon's major field if the previous sort keys are equal.
query.addAscendingOrder("major");

// Sorts the results in descending order by the beacon's minor field if the previous sort keys are equal.
query.addDescendingOrder("minor");

For sortable types, you can also use comparisons in queries:


// Restricts to major < 123
query.whereLessThan("major", 123);

// Restricts to major <= 123
query.whereLessThanOrEqualTo("major", 123);

// Restricts to major > 123
query.whereGreaterThan("major", 123);

// Restricts to major >= 123
query.whereGreaterThanOrEqualTo("major", 123);

Query on String

Use whereStartsWith to restrict to string values that start with a particular string. Similar to a MySQL LIKE operator, this is indexed so it is efficient for large datasets:


// Finds beacon's name that start with 'Beacon'.
MesosferQuery query = MesosferData.getQuery("Beacon");
query.whereStartsWith("name", "Beacon");

The above example will match any MesosferData where the value in the name String key starts with “Beacon”. For example, both “Beacon One” and “Beacon Two” will match, but “First Beacon” or “Second Beacon” will not.

Use whereEndsWith to restrict to string values that end with a particular string.


// Finds beacon's name that end with 'One'.
MesosferQuery query = MesosferData.getQuery("Beacon");
query.whereEndsWith("name", "One");

The above example will match any MesosferData where the value in the name String key ends with “One”. For example, “Beacon One” will match, but “One Beacon” will not.

Counting

If you just need to count how many datas match a query, but you do not need to retrieve all the datas that match, you can use count instead of find. For example, to count how many beacons have major greater than 123:


MesosferQuery query = MesosferData.getQuery("Beacon");
query.whereGreaterThan("major", 123);
query.countAsync(new CountCallback() {
    @Override
    public void done(int count, MesosferException e) {
        if (e != null) {
            // exception happen, handle the message
            return;
        } 

        // counting succeeded, show beacons count
    }
});

Update Data

After getting the data, you can update your data that stored in cloud using method saveAsync.


MesosferData data; // fetched data
// set data
data.setData("name", "Beacon Two");
data.setData("proximityUUID", "CB10023F-A318-3394-4199-A8730C7C1AEC");
data.setData("major", 2);
data.setData("minor", 284);
data.setData("isActive", false);
data.setData("timestamp", new Date());
// execute save data
data.saveAsync(new SaveCallback() {
    @Override
    public void done(MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // data updated, show success message
    }
});

Delete Data

To delete a data from the Mesosfer Cloud, use method deleteAsync:


MesosferData data;
data.deleteAsync(new DeleteCallback() {
    @Override
    public void done(MesosferException e) {
        // check if there is an exception happen
        if (e != null) {
            // handle the exception
            return;
        }

        // data deleted successfully
    }
});

Push Notification

Push notifications is a great way to keep your users engaged and informed about your app. You can reach your entire user base quickly and effectively. This guide will help you through the setup process and the general usage of Mesosfer to send push notifications.

Setting Up Push

The Mesosfer library provides push notifications using Google Cloud Messaging (GCM) now Firebase Cloud Messaging (FCM) if Google Play Services are available. Learn more about Google Play Services here.

When sending pushes to Android devices with GCM, there are several pieces of information that Mesosfer keeps track of automatically:

  • Registration ID: The GCM registration ID uniquely identifies an app/device pairing for push purposes.
  • Sender ID: The GCM sender ID is a public number that identifies the sender of a push notification.
  • API key: The GCM API key is a server secret that allows a server to send pushes to a registration ID on behalf of a particular sender ID.

The Mesosfer Android SDK chooses a reasonable default configuration so that you do not have to worry about GCM registration ids, sender ids, or API keys. In particular, the SDK will automatically register your app for push at startup time using Mesosfer’s sender ID (523325046971) and will store the resulting registration ID in the deviceToken field of the app’s current MesosferInstallation.

Receiving Pushes

When a push notification is received, the “title” is displayed in the status bar and the “alert” is displayed alongside the “title” when the user expands the notification drawer.

USES PERMISSION


<permission
android:protectionLevel="signature"
android:name="com.eyro.mesosfer.sample.permission.C2D_MESSAGE" />
<uses-permission
android:name="com.eyro.mesosfer.sample.permission.C2D_MESSAGE" />

IMPORTANT! Change com.eyro.mesosfer.sample.permission.C2D_MESSAGE in the lines above to match your app's package name + .permission.C2D_MESSAGE

RECEIVER


<receiver android:name="com.eyro.mesosfer.PushBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.eyro.mesosfer.push.intent.RECEIVE" />
<action android:name="com.eyro.mesosfer.push.intent.DELETE" />
<action android:name="com.eyro.mesosfer.push.intent.OPEN" />
</intent-filter>
</receiver>

<receiver android:name="com.eyro.mesosfer.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />

<category android:name="com.eyro.mesosfer.sample" />
</intent-filter>
</receiver>

IMPORTANT!

  • If you choose to subclass com.eyro.mesosfer.PushBroadcastReceiver, be sure to replace that name with your class name in the registration.
  • Change com.eyro.mesosfer.sample in category tag to match your app's package name.

Note that some Android emulators (the ones without Google API support) don’t support GCM, so if you test your app in an emulator make sure to select an emulator image that has Google APIs installed.

CUSTOMIZING NOTIFICATIONS

Now that your app is all set up to receive push notifications, you can start customizing the display of these notifications.

CUSTOMIZING NOTIFICATION ICONS

The Android style guide recommends apps use a push icon that is monochromatic and flat. The default push icon is your application’s launcher icon, which is unlikely to conform to the style guide. To provide a custom push icon, add the following metadata tag to your app’s AndroidManifest.xml:


<meta-data 
android:name="com.eyro.mesosfer.push.notification_icon"
android:resource="@drawable/push_icon"/>

…where push_icon is the name of a drawable resource in your package. If your application needs more than one small icon, you can override getSmallIconId in your PushBroadcastReceiver subclass.

If your push has a unique context associated with an image, such as the avatar of the user who sent a message, you can use a large push icon to call attention to the notification. When a notification has a large push icon, your app’s static (small) push icon is moved to the lower right corner of the notification and the large icon takes its place. See the Android UI documentation for examples. To provide a large icon, you can override getLargeIcon in your PushBroadcastReceiver subclass.

RESPONDING WITH A CUSTOM ACTIVITY

If your push has no uri parameter, onPushOpen will invoke your application’s launcher activity. To customize this behavior, you can override getActivity in your PushBroadcastReceiver subclass.

RESPONDING WITH A URI

If you provide a “uri” field in your push, the PushBroadcastReceiver will open that URI when the notification is opened. If there are multiple apps capable of opening the URI, a dialog will displayed for the user. The PushBroadcastReceiver will manage your back stack and ensure that clicking back from the Activity handling URI will navigate the user back to the activity returned by getActivity.

MANAGING THE PUSH LIFECYCLE

The push lifecycle has three phases:

  1. A notification is received and the com.eyro.mesosfer.push.intent.OPEN Intent is fired, causing the PushBroadcastReceiver to call onPushReceive. If either “alert” or “title” are specified in the push, then a Notification is constructed using getNotification. This Notification uses a small icon generated using getSmallIconId, which defaults to the icon specified by the com.eyro.mesosfer.push.notification_icon metadata in your AndroidManifest.xml. The Notification’s large icon is generated from getLargeIcon which defaults to null. The notification’s contentIntent and deleteIntent are com.eyro.mesosfer.push.intent.OPEN and com.eyro.mesosfer.push.intent.DELETE respectively.
  2. If the user taps on a Notification, the com.eyro.mesosfer.push.intent.OPEN Intent is fired. The PushBroadcastReceiver calls onPushOpen. If the push contains a “uri” parameter, an activity is launched to navigate to that URI, otherwise the activity returned by getActivity is launched.
  3. If the user dismisses a Notification, the com.eyro.mesosfer.push.intent.DELETE Intent is fired. The PushBroadcastReceiver calls onPushDismiss, which does nothing by default.

All of the above methods may be subclassed to customize the way your application handles push notifications. When subclassing the methods onPushReceive, onPushOpen, onPushDismiss, or getNotification, consider delegating to super where appropriate. For example, one might override onPushReceive to trigger a background operation for “silent” pushes and then delegate to super for all other pushes. This provides the most benefit from Mesosfer Push and makes your code forward-compatible.