package com.koushikdutta.desktopsms;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import org.apache.http.client.methods.HttpGet;
import org.json.JSONObject;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import com.clockworkmod.billing.ClockworkModBillingClient;
import com.clockworkmod.billing.ThreadingRunnable;
public class MainActivity extends ActivityBase {
private static final String LOGTAG = MainActivity.class.getSimpleName();
private Handler mHandler = new Handler();
private void doLogin() {
mSettings.setString("account", null);
mSettings.setString("registration_id", null);
mSettings.setLong("last_sms_sync", 0);
mSettings.setLong("last_mms_sync", 0);
mSettings.setLong("last_calls_sync", 0);
mSettings.setBoolean("registered", false);
mAccountItem.setSummary(null);
mAccountItem.setTitle(null);
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(R.string.permission_request);
builder.setMessage(R.string.requesting_permissions);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
TickleServiceHelper.login(MainActivity.this, new Callback<Boolean>() {
@Override
public void onCallback(Boolean result) {
String account = mSettings.getString("account");
if (Helper.isJavaScriptNullOrEmpty(account)) {
finish();
return;
}
if (!result)
return;
mAccountItem.setTitle(account);
ListItem gmail = findItem(R.string.gmail);
ListItem gtalk = findItem(R.string.google_talk);
gmail.setEnabled(true);
gtalk.setEnabled(true);
ListItem testMessage = findItem(R.string.test_message);
testMessage.setEnabled(true);
mSettings.setBoolean("registered", true);
mSettings.setLong("last_sms_sync", 0);
mSettings.setLong("last_mms_sync", 0);
mSettings.setLong("last_calls_sync", 0);
SyncHelper.startSyncService(MainActivity.this, "sms");
refreshAccount();
}
});
}
});
builder.setCancelable(false);
builder.create().show();
}
private void addDeskSmsContactInfo(final boolean onlyRemove) {
final ProgressDialog dlg = new ProgressDialog(this);
dlg.setMessage(getString(R.string.please_wait_contact_list));
dlg.show();
final String account = mSettings.getString("account");
new Thread() {
public void run() {
try {
int deleted = getContentResolver().delete(ContactsContract.Data.CONTENT_URI, String.format("%s = '%s' and %s = 'DeskSMS'", Data.MIMETYPE, CommonDataKinds.Email.CONTENT_ITEM_TYPE, CommonDataKinds.Email.LABEL), null);
if (onlyRemove)
return;
HashSet<Long> rawContacts = new HashSet<Long>();
Cursor c = getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI, new String[] { RawContacts._ID }, String.format("%s = 'com.google' AND %s = '%s'", RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_NAME, account), null, null);
int idColumn = c.getColumnIndex(RawContacts._ID);
while (c.moveToNext()) {
long id = c.getLong(idColumn);
rawContacts.add(id);
}
c.close();
Hashtable<Long, String> numbers = new Hashtable<Long, String>();
c = getContentResolver().query(Data.CONTENT_URI, new String[] { Phone.NUMBER, Phone.TYPE, Data.RAW_CONTACT_ID }, String.format("%s = '%s' and (%s = '%s' or %s = '%s')", ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE, Phone.TYPE, Phone.TYPE_HOME, Phone.TYPE, Phone.TYPE_MOBILE), null, null);
int typeColumn = c.getColumnIndex(Phone.TYPE);
idColumn = c.getColumnIndex(Data.RAW_CONTACT_ID);
int numberColumn = c.getColumnIndex(Phone.NUMBER);
while (c.moveToNext()) {
long rawContact = c.getLong(idColumn);
if (!rawContacts.contains(rawContact))
continue;
int type = c.getInt(typeColumn);
String number = c.getString(numberColumn);
if (type == Phone.TYPE_MOBILE) {
numbers.put(rawContact, number);
}
else {
if (!numbers.containsKey(rawContact));
numbers.put(rawContact, number);
}
}
c.close();
ArrayList<ContentValues> cvs = new ArrayList<ContentValues>();
for (long rawContact: numbers.keySet()) {
String number = numbers.get(rawContact);
number = ServiceHelper.numbersOnly(number, false);
ContentValues cv = new ContentValues();
cv.put(Data.RAW_CONTACT_ID, rawContact);
cv.put(Data.MIMETYPE, CommonDataKinds.Email.CONTENT_ITEM_TYPE);
String email = String.format("%s@desksms.appspotmail.com", number);
cv.put(CommonDataKinds.Email.DATA, email);
cv.put(CommonDataKinds.Email.TYPE, CommonDataKinds.Email.TYPE_CUSTOM);
cv.put(CommonDataKinds.Email.LABEL, "DeskSMS");
cvs.add(cv);
cv = new ContentValues();
cv.put(Data.RAW_CONTACT_ID, rawContact);
cv.put(Data.MIMETYPE, CommonDataKinds.Email.CONTENT_ITEM_TYPE);
String xmpp = String.format("%s@desksms.appspotchat.com", number);
cv.put(CommonDataKinds.Email.DATA, xmpp);
cv.put(CommonDataKinds.Email.TYPE, CommonDataKinds.Email.TYPE_CUSTOM);
cv.put(CommonDataKinds.Email.LABEL, "DeskSMS");
cvs.add(cv);
}
ContentValues[] cvsArray = new ContentValues[cvs.size()];
cvs.toArray(cvsArray);
getContentResolver().bulkInsert(Data.CONTENT_URI, cvsArray);
}
catch (Exception ex) {
ex.printStackTrace();
}
finally {
dlg.dismiss();
}
};
}.start();
}
private void removeDeskSmsContactInfo() {
addDeskSmsContactInfo(true);
}
ListItem mAccountItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String account = mSettings.getString("account");
String registrationId = mSettings.getString("registration_id");
if (mSettings.getLong("last_missed_call", 0) == 0) {
mSettings.setLong("last_missed_call", System.currentTimeMillis());
}
mAccountItem = addItem(R.string.account, new ListItem(this, account, null) {
@Override
public void onClick(View view) {
super.onClick(view);
String account = mSettings.getString("account");
String registrationId = mSettings.getString("registration_id");
if (Helper.isJavaScriptNullOrEmpty(account) || Helper.isJavaScriptNullOrEmpty(registrationId)) {
doLogin();
}
else {
AlertDialog.Builder builder = new Builder(MainActivity.this);
builder.setTitle(R.string.account);
builder.setItems(new String[] { getString(R.string.buy_desksms), getString(R.string.switch_account) }, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
startBuy();
}
else if (which == 1){
doLogin();
}
}
});
builder.create().show();
}
}
});
final Runnable updateSettings = new Runnable() {
@Override
public void run() {
final ListItem gmail = findItem(R.string.gmail);
final ListItem gtalk = findItem(R.string.google_talk);
final ListItem web = findItem(R.string.web);
final ProgressDialog dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage(getString(R.string.updating_settings));
dialog.show();
dialog.setCancelable(false);
ServiceHelper.updateSettings(MainActivity.this, gtalk.getIsChecked(), gmail.getIsChecked(), web.getIsChecked(), new Callback<Boolean>() {
@Override
public void onCallback(final Boolean result) {
runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.dismiss();
if (!result) {
Helper.showAlertDialog(MainActivity.this, R.string.updating_settings_error);
gmail.setIsChecked(mSettings.getBoolean("forward_email", true));
gtalk.setIsChecked(mSettings.getBoolean("forward_xmpp", true));
web.setIsChecked(mSettings.getBoolean("forward_web", true));
}
}
});
}
});
}
};
addItem(R.string.notifications, new ListItem(this, R.string.gmail, 0) {
{
CheckboxVisible = true;
setIsChecked(mSettings.getBoolean("forward_email", false));
}
@Override
public void onClick(View view) {
super.onClick(view);
updateSettings.run();
}
});
addItem(R.string.notifications, new ListItem(this, R.string.google_talk, 0) {
{
CheckboxVisible = true;
setIsChecked(mSettings.getBoolean("forward_xmpp", true));
}
@Override
public void onClick(View view) {
super.onClick(view);
updateSettings.run();
}
});
addItem(R.string.notifications, new ListItem(this, R.string.web, 0) {
{
CheckboxVisible = true;
setIsChecked(mSettings.getBoolean("forward_web", true));
}
@Override
public void onClick(View view) {
super.onClick(view);
if (getIsChecked()) {
// reset the sync counter so it resends the sms history
mSettings.setLong("last_sms_sync", 0);
mSettings.setLong("last_mms_sync", 0);
mSettings.setLong("last_calls_sync", 0);
SyncHelper.startSyncService(MainActivity.this);
}
updateSettings.run();
}
});
addItem(R.string.contacts, new ListItem(this, R.string.manage_blacklist, R.string.blacklist_summary) {
@Override
public void onClick(View view) {
super.onClick(view);
MainActivity.this.startActivity(new Intent(MainActivity.this, BlackListActivity.class));
}
});
/*
addItem(R.string.contacts, new ListItem(this, R.string.add_desksms_contact_info, R.string.add_desksms_contact_info_summary) {
@Override
public void onClick(View view) {
super.onClick(view);
addDeskSmsContactInfo(false);
}
});
*/
addItem(R.string.contacts, new ListItem(this, R.string.remove_desksms_contact_info, 0) {
@Override
public void onClick(View view) {
super.onClick(view);
removeDeskSmsContactInfo();
}
});
addItem(R.string.troubleshooting, new ListItem(this, R.string.test_message, 0) {
@Override
public void onClick(View view) {
super.onClick(view);
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
final String number = tm.getLine1Number();
if (number == null || "".equals(number)) {
Helper.showAlertDialog(MainActivity.this, R.string.number_retrieval_error);
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(R.string.test_message);
builder.setMessage(R.string.test_message_info);
builder.setNegativeButton(android.R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String message = getString(R.string.test_message_content);
SmsManager sm = SmsManager.getDefault();
sm.sendTextMessage(number, null, message, null, null);
}
});
builder.setCancelable(true);
builder.create().show();
}
});
addItem(R.string.troubleshooting, new ListItem(this, getString(R.string.adjust_sms_date), getAdjustmentString() + "\n" + getString(R.string.adjust_sms_date_summary)) {
@Override
public void onClick(View view) {
super.onClick(view);
ArrayList<String> adjusts = new ArrayList<String>();
for (int adjust = -12; adjust < 13; adjust++) {
adjusts.add(getAdjustmentString(adjust));
}
String[] options = new String[adjusts.size()];
options = adjusts.toArray(options);
AlertDialog.Builder builder = new Builder(MainActivity.this);
builder.setTitle(R.string.adjust_sms_date);
builder.setItems(options, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, final int which) {
final ProgressDialog dlg = new ProgressDialog(MainActivity.this);
dlg.setMessage(getString(R.string.updating_settings));
dlg.show();
ThreadingRunnable.background(new ThreadingRunnable() {
@Override
public void run() {
try {
String account = mSettings.getString("account");
ServiceHelper.retryExecuteAndDisconnect(MainActivity.this, account, new URL(String.format(ServiceHelper.SMS_URL, account) + "?operation=DELETE"), null);
foreground(new Runnable() {
@Override
public void run() {
dlg.dismiss();
int adjust = -12 + which;
mSettings.setInt("adjust_sms_date", adjust);
setSummary(getAdjustmentString() + "\n" + getString(R.string.adjust_sms_date_summary));
mSettings.setLong("last_sms_sync", 0);
SyncHelper.startSyncService(MainActivity.this, "sms");
}
});
}
catch (Exception ex) {
ex.printStackTrace();
foreground(new Runnable() {
@Override
public void run() {
dlg.dismiss();
Helper.showAlertDialog(MainActivity.this, R.string.updating_settings_error);
}
});
}
}
});
}
});
builder.create().show();
}
});
SyncHelper.startSyncService(this);
Intent intent = getIntent();
if (Helper.isJavaScriptNullOrEmpty(account) || Helper.isJavaScriptNullOrEmpty(registrationId)) {
doLogin();
}
else if (intent != null && intent.getBooleanExtra("relogin", false)) {
intent.removeExtra("relogin");
doLogin();
}
else {
refreshAccount();
ClockworkModBillingClient.getInstance().refreshMarketPurchases();
}
ServiceHelper.getSettings(this, new Callback<JSONObject>() {
@Override
public void onCallback(JSONObject result) {
final boolean forward_xmpp = result.optBoolean("forward_xmpp", true);
final boolean forward_email = result.optBoolean("forward_email", true);
runOnUiThread(new Runnable() {
@Override
public void run() {
ListItem gmail = findItem(R.string.gmail);
ListItem gtalk = findItem(R.string.google_talk);
gmail.setIsChecked(forward_email);
gtalk.setIsChecked(forward_xmpp);
}
});
}
});
}
String getAdjustmentString() {
int adjust = mSettings.getInt("adjust_sms_date", 0);
return getAdjustmentString(adjust);
}
String getAdjustmentString(int adjust) {
if (adjust == 0)
return getString(R.string.disabled);
if (adjust == -1)
return getString(R.string.adjust_hour, "-1");
else if (adjust == 1)
return getString(R.string.adjust_hour, "+1");
else if (adjust < 0)
return getString(R.string.adjust_hours, adjust);
else
return getString(R.string.adjust_hours, "+" + adjust);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
refreshAccount();
}
}, 5000);
}
private void refreshAccount(long expiration) {
String account = mSettings.getString("account");
if (Helper.isJavaScriptNullOrEmpty(account)) {
finish();
return;
}
long daysLeft = (expiration - System.currentTimeMillis()) / 1000L / 60L / 60L / 24L;
daysLeft = Math.max(0, daysLeft);
mAccountItem.setSummary(getString(R.string.days_left, String.valueOf(daysLeft)));
}
private void refreshAccount() {
mAccountItem.setSummary(R.string.retrieving_status);
ThreadingRunnable.background(new ThreadingRunnable() {
@Override
public void run() {
try {
final JSONObject payload = ServiceHelper.retryExecuteAsJSONObject(MainActivity.this, mSettings.getString("account"), new URL(ServiceHelper.STATUS_URL), null);
final long expiration = payload.getLong("subscription_expiration");
foreground(new Runnable() {
@Override
public void run() {
refreshAccount(expiration);
}
});
}
catch (Exception ex) {
foreground(new Runnable() {
@Override
public void run() {
mAccountItem.setSummary(R.string.status_error);
}
});
ex.printStackTrace();
}
}
});
}
void startBuy() {
ClockworkModBillingClient.getInstance().refreshMarketPurchases();
final ProgressDialog dlg = new ProgressDialog(MainActivity.this);
dlg.setMessage(getString(R.string.retrieving_status));
dlg.show();
ThreadingRunnable.background(new ThreadingRunnable() {
@Override
public void run() {
try {
final HttpGet get = new HttpGet(ServiceHelper.STATUS_URL);
final JSONObject payload = ServiceHelper.retryExecuteAsJSONObject(MainActivity.this, mSettings.getString("account"), new URL(ServiceHelper.STATUS_URL), null);
final long expiration = payload.getLong("subscription_expiration");
foreground(new Runnable() {
@Override
public void run() {
refreshAccount(expiration);
dlg.dismiss();
Intent i = new Intent(MainActivity.this, BuyActivity.class);
i.putExtra("payload", payload.toString());
startActivityForResult(i, 2323);
}
});
}
catch (Exception ex) {
foreground(new Runnable() {
@Override
public void run() {
dlg.dismiss();
Helper.showAlertDialog(MainActivity.this, R.string.status_error);
}
});
ex.printStackTrace();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem buy = menu.add(R.string.buy_desksms);
buy.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
startBuy();
return true;
}
});
return super.onCreateOptionsMenu(menu);
}
}