/*
* Copyright 2014 Bevbot LLC <info@bevbot.com>
*
* This file is part of the Kegtab package from the Kegbot project. For
* more information on Kegtab or Kegbot, see <http://kegbot.org/>.
*
* Kegtab 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, version 2.
*
* Kegtab 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 Kegtab. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kegbot.app.util;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.util.Log;
import com.github.kevinsawicki.http.HttpRequest;
import com.github.kevinsawicki.http.HttpRequest.HttpRequestException;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.kegbot.app.KegbotApplication;
import org.kegbot.app.config.AppConfiguration;
import java.io.File;
import java.io.IOException;
public class CheckinClient {
private static final String TAG = CheckinClient.class.getSimpleName();
private static final String CHECKIN_URL = "https://kegbotcheckin.appspot.com/checkin";
private static final String BUGREPORT_URL = "https://kegbotcheckin.appspot.com/bugreport";
private final AppConfiguration mConfig;
private final PackageInfo mPackageInfo;
private final String mUserAgent;
public CheckinClient(final AppConfiguration config, final PackageInfo packageInfo,
final String userAgent) {
mConfig = config;
mPackageInfo = packageInfo;
mUserAgent = userAgent;
//HttpRequest.setConnectionFactory(new OkConnectionFactory());
}
public static CheckinClient fromContext(final Context context) {
final AppConfiguration config =
((KegbotApplication) context.getApplicationContext()).getConfig();
final PackageInfo pinfo = Utils.getOwnPackageInfo(context);
final String userAgent = Utils.getUserAgent(context);
return new CheckinClient(config, pinfo, userAgent);
}
public JsonNode checkin() throws IOException {
Log.d(TAG, "Performing checkin: " + CHECKIN_URL);
final long now = System.currentTimeMillis();
mConfig.setLastCheckinAttempt(now);
try {
final HttpRequest request = new HttpRequest(CHECKIN_URL, "POST");
request.header("User-Agent", mUserAgent);
final ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
builder.put("product", "kegtab-android");
builder.put("reg_id", mConfig.getRegistrationId());
builder.put("android_version", String.valueOf(Build.VERSION.SDK_INT));
builder.put("android_device", Build.DEVICE);
builder.put("gcm_reg_id", mConfig.getGcmRegistrationId());
if (mPackageInfo != null) {
if (mPackageInfo.signatures != null && mPackageInfo.signatures.length > 0) {
builder.put("android_build_fingerprint",
Utils.getFingerprintForSignature(mPackageInfo.signatures[0]));
}
builder.put("version", String.valueOf(mPackageInfo.versionCode));
}
request.form(builder.build());
final int statusCode = request.code();
if (statusCode != 200) {
Log.w(TAG, "Checkin failed, code: " + statusCode);
throw new IOException("Remote server returned HTTP error " + statusCode);
}
final String responseBody = request.body();
final ObjectMapper mapper = new ObjectMapper();
final JsonNode rootNode = mapper.readValue(responseBody, JsonNode.class);
processLastCheckinResponse(rootNode);
return rootNode;
} catch (HttpRequestException e) {
throw e.getCause();
}
}
public void submitBugreport(String message, File reportData, String email) throws IOException {
final HttpRequest request = new HttpRequest(BUGREPORT_URL, "POST");
request.header("User-Agent", mUserAgent);
request.part("product", "kegtab-android");
request.part("reg_id", mConfig.getRegistrationId());
request.part("message", message);
request.part("email_address", Strings.nullToEmpty(email));
request.part("data", reportData);
if (mPackageInfo != null) {
if (mPackageInfo.signatures != null && mPackageInfo.signatures.length > 0) {
request.part("android_build_fingerprint",
Utils.getFingerprintForSignature(mPackageInfo.signatures[0]));
}
request.part("version", String.valueOf(mPackageInfo.versionCode));
}
final int code;
try {
code = request.code();
} catch (HttpRequestException e) {
throw e.getCause();
}
if (code != 200) {
throw new IOException("Response code: " + code);
}
}
private void processLastCheckinResponse(JsonNode response) {
Log.d(TAG, "Checkin response: " + response);
// Sanity check: "status" must be "ok".
final JsonNode statusNode = response.get("status");
if (statusNode == null || !statusNode.isTextual()) {
Log.d(TAG, "Invalid checkin response: no status.");
return;
}
final String status = statusNode.getTextValue();
if ("ok".equals(status)) {
Log.d(TAG, "Checkin status: " + status);
} else {
Log.d(TAG, "Invalid checkin response: unknown status: " + status);
return;
}
// Ensure "reg_id" field exists.
final JsonNode regIdNode = response.get("reg_id");
if (regIdNode == null || !regIdNode.isTextual()) {
Log.d(TAG, "Invalid checkin response: no status.");
return;
}
// Update saved registration ID if necessary.
final String existingRegistrationId = mConfig.getRegistrationId();
final String regId = regIdNode.getTextValue();
if (existingRegistrationId == null || !existingRegistrationId.equals(regId)) {
Log.d(TAG, "Updating registration id: " + regId);
mConfig.setRegistrationId(regId);
}
boolean updateAvailable = false;
final JsonNode updateNeededNode = response.get("update_available");
if (updateNeededNode != null && updateNeededNode.isBoolean()
&& updateNeededNode.getBooleanValue()) {
updateAvailable = true;
}
boolean updateRequired = false;
final JsonNode updateRequiredNode = response.get("update_required");
if (updateRequiredNode != null && updateRequiredNode.isBoolean()
&& updateRequiredNode.getBooleanValue()) {
updateRequired = true;
}
mConfig.setLastCheckinStatus(status);
mConfig.setUpdateAvailable(updateAvailable);
mConfig.setUpdateRequired(updateRequired);
}
}