package com.mixpanel.example.hello; import android.app.Activity; import android.content.ContentResolver; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.Bundle; import android.util.Base64; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.EditText; import com.mixpanel.android.mpmetrics.MixpanelAPI; import com.mixpanel.android.mpmetrics.OnMixpanelUpdatesReceivedListener; import org.json.JSONException; import org.json.JSONObject; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Calendar; import java.util.Date; import java.util.Random; /** * A little application that allows people to update their Mixpanel information, * and receive push notifications from a Mixpanel project. * * For more information about integrating Mixpanel with your Android application, * please check out: * * https://mixpanel.com/docs/integration-libraries/android * * For instructions on enabling push notifications from Mixpanel, please see * * https://mixpanel.com/docs/people-analytics/android-push * * @author mixpanel * */ public class MainActivity extends Activity { /* * You will use a Mixpanel API token to allow your app to send data to Mixpanel. To get your token * - Log in to Mixpanel, and select the project you want to use for this application * - Click the gear icon in the lower left corner of the screen to view the settings dialog * - In the settings dialog, you will see the label "Token", and a string that looks something like this: * * 2ef3c08e8466df98e67ea0cfa1512e9f * * Paste it below (where you see "YOUR API TOKEN") */ public static final String MIXPANEL_API_TOKEN = "NOT A REAL TOKEN"; /* * In order for your app to receive push notifications, you will need to enable * the Google Cloud Messaging for Android service in your Google APIs console. To do this: * * - Navigate to https://code.google.com/apis/console * - Select "Services" from the menu on the left side of the screen * - Scroll down until you see the row labeled "Google Cloud Messaging for Android" * - Make sure the switch next to the service name says "On" * * To identify this application with your Google API account, you'll also need your sender id from Google. * You can get yours by logging in to the Google APIs Console at https://code.google.com/apis/console * Once you have logged in, your sender id will appear as part of the URL in your browser's address bar. * The URL will look something like this: * * https://code.google.com/apis/console/b/0/#project:256660625236 * ^^^^^^^^^^^^ * * The twelve-digit number after 'project:' is your sender id. Paste it below (where you see "YOUR SENDER ID") * * There are also some changes you will need to make to your AndroidManifest.xml file to * declare the permissions and receiver capabilities you'll need to get your push notifications working. * You can take a look at this application's AndroidManifest.xml file for an example of what is needed. */ public static final String ANDROID_PUSH_SENDER_ID = "YOUR SENDER ID"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final String trackingDistinctId = getTrackingDistinctId(); // Initialize the Mixpanel library for tracking and push notifications. mMixpanel = MixpanelAPI.getInstance(this, MIXPANEL_API_TOKEN); // We also identify the current user with a distinct ID, and // register ourselves for push notifications from Mixpanel. mMixpanel.identify(trackingDistinctId); //this is the distinct_id value that // will be sent with events. If you choose not to set this, // the SDK will generate one for you mMixpanel.getPeople().identify(trackingDistinctId); //this is the distinct_id // that will be used for people analytics. You must set this explicitly in order // to dispatch people data. // People analytics must be identified separately from event analytics. // The data-sets are separate, and may have different unique keys (distinct_id). // We recommend using the same distinct_id value for a given user in both, // and identifying the user with that id as early as possible. mMixpanel.getPeople().initPushHandling(ANDROID_PUSH_SENDER_ID); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override protected void onResume() { super.onResume(); final long nowInHours = hoursSinceEpoch(); final int hourOfTheDay = hourOfTheDay(); // For our simple test app, we're interested tracking // when the user views our application. // It will be interesting to segment our data by the date that they // first viewed our app. We use a // superProperty (so the value will always be sent with the // remainder of our events) and register it with // registerSuperPropertiesOnce (so no matter how many times // the code below is run, the events will always be sent // with the value of the first ever call for this user.) // all the change we make below are LOCAL. No API requests are made. try { final JSONObject properties = new JSONObject(); properties.put("first viewed on", nowInHours); properties.put("user domain", "(unknown)"); // default value mMixpanel.registerSuperPropertiesOnce(properties); } catch (final JSONException e) { throw new RuntimeException("Could not encode hour first viewed as JSON"); } // Now we send an event to Mixpanel. We want to send a new // "App Resumed" event every time we are resumed, and // we want to send a current value of "hour of the day" for every event. // As usual,all of the user's super properties will be appended onto this event. try { final JSONObject properties = new JSONObject(); properties.put("hour of the day", hourOfTheDay); mMixpanel.track("App Resumed", properties); } catch(final JSONException e) { throw new RuntimeException("Could not encode hour of the day in JSON"); } // If you have notifications and you have set AutoShowMixpanelUpdates set to false, // the onResume function is a good place to call the functions to display // in app notifications. It is safe to call both these methods right after each other. mMixpanel.getPeople().showNotificationIfAvailable(this); OnMixpanelUpdatesReceivedListener listener = new OnMixpanelUpdatesReceivedListener() { @Override public void onMixpanelUpdatesReceived() { mMixpanel.getPeople().joinExperimentIfAvailable(); } }; mMixpanel.getPeople().addOnMixpanelUpdatesReceivedListener(listener); } // Associated with the "Send to Mixpanel" button in activity_main.xml // In this method, we update a Mixpanel people profile using MixpanelAPI.People.set() // and set some persistent properties that will be sent with // all future track() calls using MixpanelAPI.registerSuperProperties() public void sendToMixpanel(final View view) { final EditText firstNameEdit = (EditText) findViewById(R.id.edit_first_name); final EditText lastNameEdit = (EditText) findViewById(R.id.edit_last_name); final EditText emailEdit = (EditText) findViewById(R.id.edit_email_address); final String firstName = firstNameEdit.getText().toString(); final String lastName = lastNameEdit.getText().toString(); final String email = emailEdit.getText().toString(); final MixpanelAPI.People people = mMixpanel.getPeople(); // Update the basic data in the user's People Analytics record. // Unlike events, People Analytics always stores the most recent value // provided. people.set("$first_name", firstName); people.set("$last_name", lastName); people.set("$email", email); // We also want to keep track of how many times the user // has updated their info. people.increment("Update Count", 1L); // Mixpanel events are separate from Mixpanel people records, // but it might be valuable to be able to query events by // user domain (for example, if they represent customer organizations). // // We use the user domain as a superProperty here, but we call registerSuperProperties // instead of registerSuperPropertiesOnce so we can overwrite old values // as we get new information. try { final JSONObject domainProperty = new JSONObject(); domainProperty.put("user domain", domainFromEmailAddress(email)); mMixpanel.registerSuperProperties(domainProperty); } catch (final JSONException e) { throw new RuntimeException("Cannot write user email address domain as a super property"); } // In addition to viewing the updated record in mixpanel's UI, it might // be interesting to see when and how many and what types of users // are updating their information, so we'll send an event as well. // You can call track with null if you don't have any properties to add // to an event (remember all the established superProperties will be added // before the event is dispatched to Mixpanel) mMixpanel.track("update info button clicked", null); } // This is an example of how you can use Mixpanel's revenue tracking features from Android. public void recordRevenue(final View view) { final MixpanelAPI.People people = mMixpanel.getPeople(); // Call trackCharge() with a floating point amount // (for example, the amount of money the user has just spent on a purchase) // and an optional set of properties describing the purchase. people.trackCharge(1.50, null); } @Override protected void onDestroy() { super.onDestroy(); // To preserve battery life, the Mixpanel library will store // events rather than send them immediately. This means it // is important to call flush() to send any unsent events // before your application is taken out of memory. mMixpanel.flush(); } //////////////////////////////////////////////////// public void setBackgroundImage(final View view) { final Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); photoPickerIntent.setType("image/*"); startActivityForResult(photoPickerIntent, PHOTO_WAS_PICKED); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (PHOTO_WAS_PICKED == requestCode && null != data) { final Uri imageUri = data.getData(); if (null != imageUri) { // AsyncTask, please... final ContentResolver contentResolver = getContentResolver(); try { final InputStream imageStream = contentResolver.openInputStream(imageUri); System.out.println("DRAWING IMAGE FROM URI " + imageUri); final Bitmap background = BitmapFactory.decodeStream(imageStream); getWindow().setBackgroundDrawable(new BitmapDrawable(getResources(), background)); } catch (final FileNotFoundException e) { Log.e(LOGTAG, "Image apparently has gone away", e); } } } } private String getTrackingDistinctId() { final SharedPreferences prefs = getPreferences(MODE_PRIVATE); String ret = prefs.getString(MIXPANEL_DISTINCT_ID_NAME, null); if (ret == null) { ret = generateDistinctId(); final SharedPreferences.Editor prefsEditor = prefs.edit(); prefsEditor.putString(MIXPANEL_DISTINCT_ID_NAME, ret); prefsEditor.commit(); } return ret; } // These disinct ids are here for the purposes of illustration. // In practice, there are great advantages to using distinct ids that // are easily associated with user identity, either from server-side // sources, or user logins. A common best practice is to maintain a field // in your users table to store mixpanel distinct_id, so it is easily // accesible for use in attributing cross platform or server side events. private String generateDistinctId() { final Random random = new Random(); final byte[] randomBytes = new byte[32]; random.nextBytes(randomBytes); return Base64.encodeToString(randomBytes, Base64.NO_WRAP | Base64.NO_PADDING); } /////////////////////////////////////////////////////// // conveniences private int hourOfTheDay() { final Calendar calendar = Calendar.getInstance(); return calendar.get(Calendar.HOUR_OF_DAY); } private long hoursSinceEpoch() { final Date now = new Date(); final long nowMillis = now.getTime(); return nowMillis / 1000 * 60 * 60; } private String domainFromEmailAddress(String email) { String ret = ""; final int atSymbolIndex = email.indexOf('@'); if ((atSymbolIndex > -1) && (email.length() > atSymbolIndex)) { ret = email.substring(atSymbolIndex + 1); } return ret; } private MixpanelAPI mMixpanel; private static final String MIXPANEL_DISTINCT_ID_NAME = "Mixpanel Example $distinctid"; private static final int PHOTO_WAS_PICKED = 2; private static final String LOGTAG = "Mixpanel Example Application"; }