package com.koushikdutta.tabletsms;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.json.JSONObject;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gcm.GCMRegistrar;
public class TickleServiceHelper {
private static final String LOGTAG = TickleServiceHelper.class.getSimpleName();
private TickleServiceHelper() {
}
static String getCookie(final Context context) throws ClientProtocolException, IOException, URISyntaxException {
Settings settings = Settings.getInstance(context);
final String authToken = settings.getString("web_connect_auth_token");
if (authToken == null)
return null;
Log.i(LOGTAG, authToken);
Log.i(LOGTAG, "getting cookie");
// Get ACSID cookie
DefaultHttpClient client = new DefaultHttpClient();
String continueURL = ServiceHelper.BASE_URL;
URI uri = new URI(ServiceHelper.AUTH_URL + "?continue=" + URLEncoder.encode(continueURL, "UTF-8") + "&auth=" + authToken);
HttpGet method = new HttpGet(uri);
final HttpParams getParams = new BasicHttpParams();
HttpClientParams.setRedirecting(getParams, false); // continue is not
// used
method.setParams(getParams);
HttpResponse res = client.execute(method);
Header[] headers = res.getHeaders("Set-Cookie");
if (res.getStatusLine().getStatusCode() != 302 || headers.length == 0) {
//throw new Exception("failure getting cookie: " + res.getStatusLine().getStatusCode() + " " + res.getStatusLine().getReasonPhrase());
return null;
}
String ascidCookie = null;
for (Header header : headers) {
if (header.getValue().indexOf("ACSID=") >= 0) {
// let's parse it
String value = header.getValue();
String[] pairs = value.split(";");
ascidCookie = pairs[0];
}
}
settings.setString("Cookie", ascidCookie);
return ascidCookie;
}
static void registerWithServer(final Context context) throws Exception {
Settings settings = Settings.getInstance(context);
final String registration = settings.getString("registration_id");
final String account = settings.getString("account");
URL url = new URL(ServiceHelper.PUSH_URL + "?type=register-device&data.registration=" + URLEncoder.encode("gcm:" + registration) + "&data.device=" + Helper.getSafeDeviceId(context));
ServiceHelper.retryExecuteAndDisconnect(context, account, url, null);
}
public static String[] getGoogleAccounts(Context context) {
ArrayList<String> googleAccounts = new ArrayList<String>();
Account[] accounts = AccountManager.get(context).getAccounts();
for (Account account : accounts) {
if (account.type.equals("com.google")) {
googleAccounts.add(account.name);
}
}
String[] result = new String[googleAccounts.size()];
googleAccounts.toArray(result);
return result;
}
public static void login(final Activity context, final Callback<Boolean> callback) {
final Settings settings = Settings.getInstance(context);
final String[] accounts = getGoogleAccounts(context);
if (accounts.length == 0) {
Helper.showAlertDialog(context, R.string.no_accounts, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
context.startActivity(new Intent(android.provider.Settings.ACTION_SYNC_SETTINGS));
callback.onCallback(false);
}
});
return;
}
AlertDialog.Builder builder = new Builder(context);
builder.setCancelable(false);
builder.setTitle(R.string.accounts);
builder.setItems(accounts, new OnClickListener() {
public void onClick(DialogInterface dialog, final int which) {
final String accountName = accounts[which];
Log.i(LOGTAG, accountName);
final ProgressDialog dlg = new ProgressDialog(context);
dlg.setMessage(context.getString(R.string.setting_up_push));
dlg.show();
registerForPush(context, new Callback<Void>() {
@Override
public void onCallback(Void result) {
dlg.setMessage(context.getString(R.string.retrieving_authentication));
tryAuth(context, accountName, new Callback<String>() {
public void onCallback(String authToken) {
try {
if (authToken == null)
throw new Exception();
dlg.setMessage(context.getString(R.string.checking_desksms));
ThreadingRunnable.background(new ThreadingRunnable() {
boolean mOutDated;
public void run() {
try {
// check to see what version of the client app is running... if push fails,
// we can provide this as a possible reason.
JSONObject whoami = ServiceHelper.retryExecuteAsJSONObject(context, accountName, new URL(ServiceHelper.WHOAMI_URL), null);
mOutDated = whoami.optInt("version_code", 0) < 1110;
Log.i(LOGTAG, "DeskSMS may be outdated... " + mOutDated);
try {
// check to see if web forwarding is enabled, if not, enable it and force a sync.
JSONObject settings = ServiceHelper.retryExecuteAsJSONObject(context, accountName, new URL(ServiceHelper.SETTINGS_URL), null);
if (!settings.optBoolean("forward_web", false)) {
// enable web forwarding
JSONObject forwardResult = ServiceHelper.retryExecuteAsJSONObject(context, accountName, new URL(ServiceHelper.SETTINGS_URL), new ServiceHelper.StringPoster("forward_web=true&tickle=true"));
Log.i(LOGTAG, "forward result:");
Log.i(LOGTAG, forwardResult.toString());
// // this will reset the sync counter
JSONObject resetResult = ServiceHelper.retryExecuteAsJSONObject(context, accountName, new URL(ServiceHelper.PUSH_URL + "?type=settings&data.last_sms_sync=0&data.last_mms_sync=0&forward_web=true"), null);
Log.i(LOGTAG, "reset result:");
Log.i(LOGTAG, resetResult.toString());
// and this will trigger the sync
JSONObject syncResult = ServiceHelper.retryExecuteAsJSONObject(context, accountName, new URL(ServiceHelper.PUSH_URL + "?type=outbox"), null);
Log.i(LOGTAG, "forced sync result:");
Log.i(LOGTAG, syncResult.toString());
}
}
catch (Exception ex) {
ex.printStackTrace();
}
foreground(new Runnable() {
@Override
public void run() {
dlg.setMessage(context.getString(R.string.registering_with_server));
background(new Runnable() {
boolean pushReceived = false;
@Override
public void run() {
try {
registerWithServer(context);
foreground(new Runnable() {
@Override
public void run() {
dlg.setMessage(context.getString(R.string.testing_push));
}
});
final Runnable emailSent = new Runnable() {
@Override
public void run() {
Helper.showAlertDialog(context, R.string.signin_complete, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onCallback(true);
}
});
}
};
final BroadcastReceiver pushReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
context.unregisterReceiver(this);
}
catch (Exception ex) {
ex.printStackTrace();
}
pushReceived = true;
dlg.dismiss();
Helper.showAlertDialog(context, R.string.signin_success,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
emailSent.run();
}
});
}
};
IntentFilter filter = new IntentFilter(GCMIntentService.PING);
context.registerReceiver(pushReceiver, filter);
ServiceHelper.retryExecuteAndDisconnect(context, accountName, new URL(
ServiceHelper.PUSH_URL + "?type=echo"), null);
Thread.sleep(15000);
if (!pushReceived) {
settings.setString("account", null);
foreground(new Runnable() {
@Override
public void run() {
dlg.dismiss();
Helper.showAlertDialog(context, R.string.push_failed,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onCallback(false);
}
});
}
});
}
}
catch (Exception ex) {
settings.setString("account", null);
ex.printStackTrace();
foreground(new Runnable() {
@Override
public void run() {
dlg.dismiss();
Helper.showAlertDialog(context, R.string.signin_failure,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onCallback(false);
}
});
}
});
}
}
});
}
});
}
catch (Exception ex) {
settings.setString("account", null);
ex.printStackTrace();
foreground(new Runnable() {
@Override
public void run() {
dlg.dismiss();
Helper.showAlertDialog(context, R.string.signin_failure);
callback.onCallback(false);
}
});
}
};
});
}
catch (Exception e) {
settings.setString("account", null);
e.printStackTrace();
dlg.dismiss();
Helper.showAlertDialog(context, R.string.signin_failure);
callback.onCallback(false);
}
}
});
}
});
}
});
builder.create().show();
}
static void registerForPush(final Context context, final Callback<Void> callback) {
if (callback != null) {
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
context.unregisterReceiver(this);
callback.onCallback(null);
}
};
IntentFilter filter = new IntentFilter(GCMIntentService.ACTION_REGISTRATION_RECEIVED);
context.registerReceiver(receiver, filter);
}
GCMRegistrar.unregister(context);
GCMRegistrar.register(context, "960629859371");
}
static final String AUTH_TOKEN_TYPE = "ah";
private static void tryAuth(final Activity context, final String accountName, final Callback<String> callback) {
AccountManager accountManager = AccountManager.get(context);
Account account = new Account(accountName, "com.google");
String curAuthToken = Settings.getInstance(context).getString("web_connect_auth_token");
if (!Helper.isJavaScriptNullOrEmpty(curAuthToken))
accountManager.invalidateAuthToken(account.type, curAuthToken);
accountManager.getAuthToken(account, AUTH_TOKEN_TYPE, null, context, new AccountManagerCallback<Bundle>() {
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle bundle = future.getResult();
final String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
if (authToken != null) {
Settings settings = Settings.getInstance(context);
settings.setString("web_connect_auth_token", authToken);
settings.setString("account", accountName.toLowerCase());
}
callback.onCallback(authToken);
}
catch (Exception ex) {
callback.onCallback(null);
ex.printStackTrace();
}
}
}, null);
}
}