package com.koushikdutta.desktopsms; 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.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.params.HttpClientParams; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; 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.text.TextUtils; import android.util.Log; import com.clockworkmod.billing.ThreadingRunnable; import com.google.android.gms.gcm.GoogleCloudMessaging; 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 { registerWithServer(context, false); } static void registerWithServer(final Context context, boolean sendEmail) throws Exception { String ascidCookie = getCookie(context); Settings settings = Settings.getInstance(context); final String registration = settings.getString("registration_id"); DefaultHttpClient client = new DefaultHttpClient(); // Make POST request URI uri = new URI(ServiceHelper.REGISTER_URL); HttpPost post = new HttpPost(uri); ArrayList<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("device_id", Helper.getSafeDeviceId(context))); params.add(new BasicNameValuePair("registration_id", "gcm:" + registration)); params.add(new BasicNameValuePair("version_code", String.valueOf(DesktopSMSApplication.mVersionCode))); params.add(new BasicNameValuePair("send_email", String.valueOf(sendEmail))); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8"); post.setEntity(entity); post.setHeader("X-Same-Domain", "1"); // XSRF post.setHeader("Cookie", ascidCookie); HttpResponse res = client.execute(post); Log.i(LOGTAG, "Status code from register: " + res.getStatusLine().getStatusCode()); if (res.getStatusLine().getStatusCode() != 200) throw new Exception("status from server: " + res.getStatusLine().getStatusCode()); } 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 String[] accounts = getGoogleAccounts(context); 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.registering_with_server)); new Thread() { boolean pushReceived = false; public void run() { try { registerWithServer(context, true); context.runOnUiThread(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.PING_URL), null); } Thread.sleep(10000); if (!pushReceived) { context.runOnUiThread(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) { emailSent.run(); } }); } }); } } catch (Exception ex) { ex.printStackTrace(); context.runOnUiThread(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); } }); } }); } }; }.start(); } catch (Exception e) { e.printStackTrace(); dlg.dismiss(); Helper.showAlertDialog(context, R.string.signin_failure); callback.onCallback(false); } } }); } }); } }); builder.setCancelable(true); builder.create().show(); } static void registerForPush(final Context context, final Callback<Void> callback) { ThreadingRunnable.background(new ThreadingRunnable() { @Override public void run() { try { GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context); String registration = gcm.register("960629859371"); Log.i(LOGTAG, registration); Settings settings = Settings.getInstance(context); settings.setString("registration_id", registration); String oldRegistrationId = settings.getString("registration_id"); if (!TextUtils.equals(registration, oldRegistrationId)) { Log.i(LOGTAG, oldRegistrationId); Log.i(LOGTAG, "Registration change detected!"); TickleServiceHelper.registerWithServer(context); } } catch (Exception e) { } foreground(new Runnable() { @Override public void run() { if (callback != null) callback.onCallback(null); } }); } }); } 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); } }