org.runnerup.export.MapMyRunUploader.java Source code

Java tutorial

Introduction

Here is the source code for org.runnerup.export.MapMyRunUploader.java

Source

/*
 * Copyright (C) 2013 jonas.oreland@gmail.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.runnerup.export;

import android.annotation.TargetApi;
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.util.Pair;

import org.json.JSONException;
import org.json.JSONObject;
import org.runnerup.export.format.TCX;
import org.runnerup.common.util.Constants.DB;
import org.runnerup.util.Encryption;
import org.runnerup.workout.Sport;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

@TargetApi(Build.VERSION_CODES.FROYO)
public class MapMyRunUploader extends FormCrawler implements Uploader {

    public static final String NAME = "MapMyRun";
    private static String CONSUMER_KEY;
    private static final String BASE_URL = "https://api.mapmyfitness.com/3.1";
    private static final String GET_USER_URL = BASE_URL + "/users/get_user";
    private static final String IMPORT_URL = BASE_URL + "/workouts/import_tcx";
    private static final String UPDATE_URL = BASE_URL + "/workouts/edit_workout";

    long id = 0;
    private String username = null;
    private String password = null;
    private String md5pass = null;
    private String user_id = null;
    private String user_key = null;

    static final Map<Integer, Sport> mapmyrun2sportMap = new HashMap<Integer, Sport>();
    static final Map<Sport, Integer> sport2mapmyrunMap = new HashMap<Sport, Integer>();
    static {
        // V3 API (what we use): 16 is Walking (specifically a long walk)
        // V7 API is different: 11: Biking, 16: Running, 9: Walk
        mapmyrun2sportMap.put(1, Sport.RUNNING);
        mapmyrun2sportMap.put(3, Sport.BIKING);
        for (Integer i : mapmyrun2sportMap.keySet()) {
            sport2mapmyrunMap.put(mapmyrun2sportMap.get(i), i);
        }
    }

    MapMyRunUploader(UploadManager uploadManager) {
        if (CONSUMER_KEY == null) {
            try {
                JSONObject tmp = new JSONObject(uploadManager.loadData(this));
                CONSUMER_KEY = tmp.getString("CONSUMER_KEY");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    @Override
    public long getId() {
        return id;
    }

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    public void init(ContentValues config) {
        id = config.getAsLong("_id");
        String authToken = config.getAsString(DB.ACCOUNT.AUTH_CONFIG);
        if (authToken != null) {
            try {
                JSONObject tmp = new JSONObject(authToken);
                username = tmp.optString("username", null);
                password = tmp.optString("password", null);
                md5pass = tmp.optString("md5pass", null);
                user_id = tmp.optString("user_id", null);
                user_key = tmp.optString("user_key", null);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public boolean isConfigured() {
        if (username != null && md5pass != null && user_id != null && user_key != null) {
            return true;
        }
        return false;
    }

    @Override
    public String getAuthConfig() {
        JSONObject tmp = new JSONObject();
        try {
            tmp.put("username", username);
            tmp.put("password", password);
            tmp.put("md5pass", md5pass);
            tmp.put("user_id", user_id);
            tmp.put("user_key", user_key);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return tmp.toString();
    }

    @Override
    public void reset() {
        username = null;
        password = null;
        md5pass = null;
        user_id = null;
        user_key = null;
    }

    private String toHexString(byte messageDigest[]) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : messageDigest) {
            String h = Integer.toHexString(0xFF & b);
            while (h.length() < 2)
                h = "0" + h;
            hexString.append(h);
        }
        return hexString.toString();

    }

    @Override
    public Status connect() {
        if (isConfigured()) {
            return Status.OK;
        }

        Status s = Status.NEED_AUTH;
        s.authMethod = Uploader.AuthMethod.USER_PASS;
        if (username == null || password == null) {
            return s;
        }

        Exception ex = null;
        HttpURLConnection conn = null;
        try {
            String pass = md5pass;
            if (pass == null) {
                pass = toHexString(Encryption.md5(password));
            }

            /**
             * get user id/key
             */
            conn = (HttpURLConnection) new URL(GET_USER_URL).openConnection();
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            FormValues kv = new FormValues();
            kv.put("consumer_key", CONSUMER_KEY);
            kv.put("u", username);
            kv.put("p", pass);

            {
                OutputStream wr = new BufferedOutputStream(conn.getOutputStream());
                kv.write(wr);
                wr.flush();
                wr.close();

                InputStream in = new BufferedInputStream(conn.getInputStream());
                JSONObject obj = parse(in);
                conn.disconnect();

                try {
                    JSONObject user = obj.getJSONObject("result").getJSONObject("output").getJSONObject("user");
                    user_id = user.getString("user_id");
                    user_key = user.getString("user_key");
                    md5pass = pass;
                    return Uploader.Status.OK;
                } catch (JSONException e) {
                    System.err.println("obj: " + obj);
                    throw e;
                }
            }
        } catch (MalformedURLException e) {
            ex = e;
        } catch (IOException e) {
            ex = e;
        } catch (JSONException e) {
            ex = e;
        } catch (NoSuchAlgorithmException e) {
            ex = e;
        }

        if (conn != null)
            conn.disconnect();

        s.ex = ex;
        if (ex != null) {
            ex.printStackTrace();
        }
        return s;
    }

    @Override
    public Status upload(SQLiteDatabase db, long mID) {
        Status s;
        if ((s = connect()) != Status.OK) {
            return s;
        }

        TCX tcx = new TCX(db);
        HttpURLConnection conn = null;
        Exception ex = null;
        try {
            StringWriter writer = new StringWriter();
            Pair<String, Sport> res = tcx.exportWithSport(mID, writer);
            Sport sport = res.second;

            conn = (HttpURLConnection) new URL(IMPORT_URL).openConnection();
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            FormValues kv = new FormValues();
            kv.put("consumer_key", CONSUMER_KEY);
            kv.put("u", username);
            kv.put("p", md5pass);
            kv.put("o", "json");
            kv.put("baretcx", "1");
            kv.put("tcx", writer.toString());

            {
                OutputStream wr = new BufferedOutputStream(conn.getOutputStream());
                kv.write(wr);
                wr.flush();
                wr.close();

                InputStream in = new BufferedInputStream(conn.getInputStream());
                JSONObject obj = parse(in);
                conn.disconnect();

                JSONObject result = obj.getJSONObject("result").getJSONObject("output").getJSONObject("result");
                final String workout_id = result.getString("workout_id");
                final String workout_key = result.getString("workout_key");
                final JSONObject workout = result.getJSONObject("workout");
                final String raw_workout_date = workout.getString("raw_workout_date");
                String workout_type_id = workout.getString("workout_type_id");
                if (sport != null && sport2mapmyrunMap.containsKey(sport))
                    workout_type_id = sport2mapmyrunMap.get(sport).toString();

                kv.clear();
                kv.put("consumer_key", CONSUMER_KEY);
                kv.put("u", username);
                kv.put("p", md5pass);
                kv.put("o", "json");
                kv.put("workout_id", workout_id);
                kv.put("workout_key", workout_key);
                kv.put("workout_type_id", workout_type_id);
                kv.put("workout_description", "RunnerUp - " + raw_workout_date);
                kv.put("notes", tcx.getNotes());
                kv.put("privacy_setting", "1"); // friends

                conn = (HttpURLConnection) new URL(UPDATE_URL).openConnection();
                conn.setDoOutput(true);
                conn.setRequestMethod("POST");
                conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                wr = new BufferedOutputStream(conn.getOutputStream());
                kv.write(wr);
                wr.flush();
                wr.close();

                in = new BufferedInputStream(conn.getInputStream());
                obj = parse(in);
                conn.disconnect();

                return Uploader.Status.OK;
            }
        } catch (IOException e) {
            ex = e;
        } catch (JSONException e) {
            ex = e;
        }

        s = Uploader.Status.ERROR;
        s.ex = ex;
        if (ex != null) {
            ex.printStackTrace();
        }
        return s;
    }

    @Override
    public void logout() {
        super.logout();
    }

    @Override
    public Status refreshToken() {
        return Status.OK;
    }
}