Remove non-themed theme madness.

master
Moxie Marlinspike 2012-07-16 19:56:10 -07:00
parent 647c41bf66
commit 44c221c9f1
4 changed files with 270 additions and 360 deletions

Binary file not shown.

View File

@ -1,102 +1,51 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical"> android:orientation="vertical">
<RelativeLayout android:id="@+id/title_bar_container" <EditText android:id="@+id/search_text"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_height="43dip" android:capitalize="sentences"
android:background="@drawable/iphone_bar_top" android:autoText="true"
android:layout_alignParentTop="true"> android:singleLine="true"
<TextView android:hint="Search"
android:textSize="18.0dip" android:paddingRight="50dip"
android:textStyle="bold" android:layout_margin="10dip"
android:textColor="#ffffffff" android:layout_width="fill_parent"
android:singleLine="true" android:layout_alignParentBottom="true"
style="?android:windowTitleStyle" android:visibility="gone"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextSecure"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center" />
<!-- <ImageView-->
<!-- android:id="@+id/settings_button"-->
<!-- android:paddingLeft="2.0dip" -->
<!-- android:paddingRight="5.0dip" -->
<!-- android:layout_width="wrap_content" -->
<!-- android:layout_height="wrap_content" -->
<!-- android:src="@drawable/ic_settings_iphone" -->
<!-- android:adjustViewBounds="false" -->
<!-- android:layout_alignParentRight="true" -->
<!-- android:layout_centerVertical="true" />-->
</RelativeLayout>
<EditText android:id="@+id/search_text"
android:layout_height="wrap_content"
android:capitalize="sentences"
android:autoText="true"
android:singleLine="true"
android:hint="Search"
android:paddingRight="50dip"
android:layout_margin="10dip"
android:layout_width="fill_parent"
android:layout_alignParentBottom="true"
android:visibility="gone"/>
<ImageView android:id="@+id/search_close" <ImageView android:id="@+id/search_close"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:layout_marginRight="16dip" android:layout_marginRight="16dip"
android:layout_marginBottom="20dip" android:layout_marginBottom="20dip"
android:src="@android:drawable/btn_dialog" android:src="@android:drawable/btn_dialog"
android:visibility="gone" android:visibility="gone"
/> />
<ListView android:id="@android:id/list" <ListView android:id="@android:id/list"
style="?android:attr/listViewWhiteStyle" style="?android:attr/listViewWhiteStyle"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:drawSelectorOnTop="false" android:drawSelectorOnTop="false"
android:scrollbarStyle="insideOverlay" android:scrollbarStyle="insideOverlay"
android:fadingEdgeLength="16dip" android:fadingEdgeLength="16dip"
android:background="@android:color/white" android:background="@android:color/white"
android:cacheColorHint="@android:color/white" android:cacheColorHint="@android:color/white"
android:layout_below="@id/title_bar_container" android:layout_alignParentTop="true"
android:layout_above="@id/search_text" /> android:layout_above="@id/search_text" />
<ProgressBar android:id="@+id/search_progress" <ProgressBar android:id="@+id/search_progress"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:indeterminate="true" android:indeterminate="true"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:visibility="gone" /> android:visibility="gone" />
<!-- <LinearLayout android:orientation="horizontal"-->
<!-- android:layout_width="fill_parent"-->
<!-- android:layout_height="wrap_content">-->
<!-- <TextView android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_margin="10dip"-->
<!-- android:textAppearance="?android:attr/textAppearanceMedium"-->
<!-- android:singleLine="true" -->
<!-- android:text="Search:" />-->
<!-- -->
<!-- <EditText android:layout_width="fill_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_margin="10dip"-->
<!-- android:id="@+id/search_text" />-->
<!-- </LinearLayout>-->
</RelativeLayout> </RelativeLayout>

View File

@ -1,6 +1,6 @@
/** /**
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -10,17 +10,12 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import java.util.Set;
import org.thoughtcrime.securesms.database.MessageRecord;
import org.thoughtcrime.securesms.recipients.Recipients;
import android.content.Context; import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
@ -36,6 +31,11 @@ import android.widget.ImageView;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import org.thoughtcrime.securesms.database.MessageRecord;
import org.thoughtcrime.securesms.recipients.Recipients;
import java.util.Set;
/** /**
* A view that displays the element in a list of multiple conversation threads. * A view that displays the element in a list of multiple conversation threads.
* Used by SecureSMS's ListActivity via a ConversationListAdapter. * Used by SecureSMS's ListActivity via a ConversationListAdapter.
@ -47,7 +47,7 @@ public class ConversationHeaderView extends RelativeLayout {
private final Context context; private final Context context;
private Set<Long> selectedThreads; private Set<Long> selectedThreads;
private Recipients recipients; private Recipients recipients;
private long threadId; private long threadId;
private boolean first; private boolean first;
@ -58,21 +58,21 @@ public class ConversationHeaderView extends RelativeLayout {
private View keyIndicator; private View keyIndicator;
private CheckBox checkbox; private CheckBox checkbox;
private ImageView contactPhoto; private ImageView contactPhoto;
public ConversationHeaderView(Context context, boolean first) { public ConversationHeaderView(Context context, boolean first) {
this(context, (Set<Long>)null); this(context, (Set<Long>)null);
this.first = true; this.first = true;
contactPhoto.setVisibility(View.GONE); contactPhoto.setVisibility(View.GONE);
this.setBackgroundColor(Color.TRANSPARENT); this.setBackgroundColor(Color.TRANSPARENT);
} }
public ConversationHeaderView(Context context, Set<Long> selectedThreads) { public ConversationHeaderView(Context context, Set<Long> selectedThreads) {
super(context); super(context);
LayoutInflater li = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); LayoutInflater li = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
li.inflate(R.layout.conversation_header_view, this, true); li.inflate(R.layout.conversation_header_view, this, true);
this.context = context; this.context = context;
this.selectedThreads = selectedThreads; this.selectedThreads = selectedThreads;
this.subjectView = (TextView)findViewById(R.id.subject); this.subjectView = (TextView)findViewById(R.id.subject);
@ -80,13 +80,12 @@ public class ConversationHeaderView extends RelativeLayout {
this.dateView = (TextView)findViewById(R.id.date); this.dateView = (TextView)findViewById(R.id.date);
this.unreadIndicator = findViewById(R.id.unread_indicator); this.unreadIndicator = findViewById(R.id.unread_indicator);
this.keyIndicator = findViewById(R.id.key_indicator); this.keyIndicator = findViewById(R.id.key_indicator);
this.contactPhoto = (ImageView)findViewById(R.id.contact_photo); this.contactPhoto = (ImageView)findViewById(R.id.contact_photo);
this.checkbox = (CheckBox)findViewById(R.id.checkbox); this.checkbox = (CheckBox)findViewById(R.id.checkbox);
intializeListeners(); intializeListeners();
initializeColors();
} }
public ConversationHeaderView(Context context, AttributeSet attrs) { public ConversationHeaderView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
this.context = context; this.context = context;
@ -96,78 +95,64 @@ public class ConversationHeaderView extends RelativeLayout {
this.recipients = message.getRecipients(); this.recipients = message.getRecipients();
this.threadId = message.getThreadId(); this.threadId = message.getThreadId();
this.fromView.setText(formatFrom(recipients, message.getCount())); this.fromView.setText(formatFrom(recipients, message.getCount()));
if (message.isKeyExchange()) if (message.isKeyExchange())
this.subjectView.setText("Key exchange message...", TextView.BufferType.SPANNABLE); this.subjectView.setText("Key exchange message...", TextView.BufferType.SPANNABLE);
else else
this.subjectView.setText(message.getBody(), TextView.BufferType.SPANNABLE); this.subjectView.setText(message.getBody(), TextView.BufferType.SPANNABLE);
if (message.getEmphasis()) if (message.getEmphasis())
((Spannable)this.subjectView.getText()).setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, this.subjectView.getText().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); ((Spannable)this.subjectView.getText()).setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, this.subjectView.getText().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
if (message.getDate() > 0) if (message.getDate() > 0)
this.dateView.setText(DateUtils.getRelativeTimeSpanString(getContext(), message.getDate(), false)); this.dateView.setText(DateUtils.getRelativeTimeSpanString(getContext(), message.getDate(), false));
if (selectedThreads != null) if (selectedThreads != null)
this.checkbox.setChecked(selectedThreads.contains(threadId)); this.checkbox.setChecked(selectedThreads.contains(threadId));
clearIndicators(); clearIndicators();
setIndicators(message.getRead(), message.isKeyExchange()); setIndicators(message.getRead(), message.isKeyExchange());
if (!first) { if (!first) {
if (batchMode) checkbox.setVisibility(View.VISIBLE); if (batchMode) checkbox.setVisibility(View.VISIBLE);
else checkbox.setVisibility(View.GONE); else checkbox.setVisibility(View.GONE);
if (!PreferenceManager.getDefaultSharedPreferences(context).getBoolean(ApplicationPreferencesActivity.CONVERSATION_ICONS_LIST_PREF, ApplicationPreferencesActivity.showIcon())) { if (!PreferenceManager.getDefaultSharedPreferences(context).getBoolean(ApplicationPreferencesActivity.CONVERSATION_ICONS_LIST_PREF, ApplicationPreferencesActivity.showIcon())) {
contactPhoto.setVisibility(View.GONE); contactPhoto.setVisibility(View.GONE);
} else { } else {
contactPhoto.setImageBitmap(message.getRecipients().getPrimaryRecipient().getContactPhoto()); contactPhoto.setImageBitmap(message.getRecipients().getPrimaryRecipient().getContactPhoto());
contactPhoto.setBackgroundResource(R.drawable.light_border_background); contactPhoto.setBackgroundResource(R.drawable.light_border_background);
contactPhoto.setVisibility(View.VISIBLE); contactPhoto.setVisibility(View.VISIBLE);
} }
} }
}
public void initializeColors() {
if (!PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean(ApplicationPreferencesActivity.DARK_THREADS_PREF, true)) {
this.setBackgroundDrawable(getResources().getDrawable(R.drawable.conversation_header_background_light));
this.subjectView.setTextColor(Color.BLACK);
this.fromView.setTextColor(Color.BLACK);
this.dateView.setTextColor(Color.LTGRAY);
} else {
this.setBackgroundColor(Color.TRANSPARENT);
this.subjectView.setTextColor(Color.LTGRAY);
this.fromView.setTextColor(Color.WHITE);
this.dateView.setTextColor(Color.LTGRAY);
}
} }
private void intializeListeners() { private void intializeListeners() {
checkbox.setOnCheckedChangeListener(new CheckedChangedListener()); checkbox.setOnCheckedChangeListener(new CheckedChangedListener());
} }
private void clearIndicators() { private void clearIndicators() {
this.keyIndicator.setVisibility(View.INVISIBLE); this.keyIndicator.setVisibility(View.INVISIBLE);
this.unreadIndicator.setVisibility(View.INVISIBLE); this.unreadIndicator.setVisibility(View.INVISIBLE);
} }
private void setIndicators(boolean read, boolean key) { private void setIndicators(boolean read, boolean key) {
if (!read && key) this.keyIndicator.setVisibility(View.VISIBLE); if (!read && key) this.keyIndicator.setVisibility(View.VISIBLE);
else if (!read) this.unreadIndicator.setVisibility(View.VISIBLE); else if (!read) this.unreadIndicator.setVisibility(View.VISIBLE);
} }
private String formatFrom(Recipients from, long count) { private String formatFrom(Recipients from, long count) {
return from.toShortString() + (count > 0 ? " (" + count + ")" : ""); return from.toShortString() + (count > 0 ? " (" + count + ")" : "");
} }
public Recipients getRecipients() { public Recipients getRecipients() {
return recipients; return recipients;
} }
public long getThreadId() { public long getThreadId() {
return threadId; return threadId;
} }
private class CheckedChangedListener implements CompoundButton.OnCheckedChangeListener { private class CheckedChangedListener implements CompoundButton.OnCheckedChangeListener {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) selectedThreads.add(threadId); if (isChecked) selectedThreads.add(threadId);

View File

@ -1,6 +1,6 @@
/** /**
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -10,16 +10,49 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import java.io.IOException; import android.app.AlertDialog;
import java.util.ArrayList; import android.app.NotificationManager;
import java.util.List; import android.app.ProgressDialog;
import java.util.Set; import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcelable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockListActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;
import org.thoughtcrime.securesms.contacts.ContactAccessor; import org.thoughtcrime.securesms.contacts.ContactAccessor;
import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.DecryptingQueue;
@ -41,57 +74,21 @@ import org.thoughtcrime.securesms.service.SendReceiveService;
import org.thoughtcrime.securesms.util.Eula; import org.thoughtcrime.securesms.util.Eula;
import org.thoughtcrime.securesms.util.MemoryCleaner; import org.thoughtcrime.securesms.util.MemoryCleaner;
import android.app.AlertDialog; import java.io.IOException;
import android.app.ListActivity; import java.util.ArrayList;
import android.app.NotificationManager; import java.util.List;
import android.app.ProgressDialog; import java.util.Set;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;
/** /**
* *
* The main Activity for TextSecure. Manages the conversation list, search * The main Activity for TextSecure. Manages the conversation list, search
* access to the conversation list, and import/export handling. * access to the conversation list, and import/export handling.
* *
* @author Moxie Marlinspike * @author Moxie Marlinspike
*/ */
public class SecureSMS extends ListActivity { public class SecureSMS extends SherlockListActivity {
private static final int MENU_SEND_KEY = 1; private static final int MENU_SEND_KEY = 1;
private static final int MENU_PASSPHRASE_KEY = 2; private static final int MENU_PASSPHRASE_KEY = 2;
private static final int MENU_PREFERENCES_KEY = 3; private static final int MENU_PREFERENCES_KEY = 3;
@ -101,16 +98,16 @@ public class SecureSMS extends ListActivity {
private static final int MENU_CLEAR_PASSPHRASE = 12; private static final int MENU_CLEAR_PASSPHRASE = 12;
private static final int MENU_DELETE_SELECTED_THREADS = 13; private static final int MENU_DELETE_SELECTED_THREADS = 13;
private static final int MENU_BATCH_MODE = 14; private static final int MENU_BATCH_MODE = 14;
private static final int MENU_EXIT_BATCH = 15; private static final int MENU_EXIT_BATCH = 15;
private static final int MENU_SELECT_ALL_THREADS = 16; private static final int MENU_SELECT_ALL_THREADS = 16;
private static final int MENU_CLEAR_SELECTION = 17; private static final int MENU_CLEAR_SELECTION = 17;
private static final int VIEW_THREAD_ID = 100; private static final int VIEW_THREAD_ID = 100;
private static final int VIEW_CONTACT_ID = 101; private static final int VIEW_CONTACT_ID = 101;
private static final int DELETE_THREAD_ID = 102; private static final int DELETE_THREAD_ID = 102;
private static final int ADD_CONTACT_ID = 103; private static final int ADD_CONTACT_ID = 103;
private EditText searchBox; private EditText searchBox;
private ConversationHeaderView headerView; private ConversationHeaderView headerView;
private MasterSecret masterSecret; private MasterSecret masterSecret;
@ -119,53 +116,56 @@ public class SecureSMS extends ListActivity {
private boolean havePromptedForPassphrase = false; private boolean havePromptedForPassphrase = false;
private boolean batchMode = false; private boolean batchMode = false;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("TextSecure");
setContentView(R.layout.main); setContentView(R.layout.main);
initializeKillReceiver(); initializeKillReceiver();
initializeSenderReceiverService(); initializeSenderReceiverService();
initializeResources();
initializeSearchListener(); initializeSearchListener();
registerForContextMenu(getListView()); registerForContextMenu(getListView());
registerForContactsUpdates(); registerForContactsUpdates();
} }
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
if (receiver != null) { if (receiver != null) {
Log.w("securesms", "Unregistering receiver..."); Log.w("securesms", "Unregistering receiver...");
unregisterReceiver(receiver); unregisterReceiver(receiver);
receiver = null; receiver = null;
} }
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
Log.w("securesms", "restart called..."); Log.w("securesms", "restart called...");
initializeColors(); Eula.showDisclaimer(this);
Eula.showEula(this);
} }
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
registerPassphraseActivityStarted(); registerPassphraseActivityStarted();
} }
@Override @Override
public void onStop() { public void onStop() {
super.onStop(); super.onStop();
havePromptedForPassphrase = false; havePromptedForPassphrase = false;
registerPassphraseActivityStopped(); registerPassphraseActivityStopped();
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
Log.w("SecureSMS", "onDestroy..."); Log.w("SecureSMS", "onDestroy...");
@ -173,55 +173,55 @@ public class SecureSMS extends ListActivity {
MemoryCleaner.clean(masterSecret); MemoryCleaner.clean(masterSecret);
super.onDestroy(); super.onDestroy();
} }
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu); super.onPrepareOptionsMenu(menu);
menu.clear(); menu.clear();
if (!batchMode) prepareNormalMenu(menu); if (!batchMode) prepareNormalMenu(menu);
else prepareBatchModeMenu(menu); else prepareBatchModeMenu(menu);
return true; return true;
} }
private void prepareNormalMenu(Menu menu) { private void prepareNormalMenu(Menu menu) {
menu.add(0, MENU_BATCH_MODE, Menu.NONE, "Batch Mode").setIcon(android.R.drawable.ic_menu_share); menu.add(0, MENU_BATCH_MODE, Menu.NONE, "Batch Mode").setIcon(android.R.drawable.ic_menu_share);
if (masterSecret != null) menu.add(0, MENU_SEND_KEY, Menu.NONE, "Secure Session").setIcon(R.drawable.ic_lock_message_sms); if (masterSecret != null) menu.add(0, MENU_SEND_KEY, Menu.NONE, "Secure Session").setIcon(R.drawable.ic_lock_message_sms);
else menu.add(0, MENU_PASSPHRASE_KEY, Menu.NONE, "Enter passphrase").setIcon(R.drawable.ic_lock_message_sms); else menu.add(0, MENU_PASSPHRASE_KEY, Menu.NONE, "Enter passphrase").setIcon(R.drawable.ic_lock_message_sms);
menu.add(0, MENU_SEARCH, Menu.NONE, "Search").setIcon(android.R.drawable.ic_menu_search); menu.add(0, MENU_SEARCH, Menu.NONE, "Search").setIcon(android.R.drawable.ic_menu_search);
menu.add(0, MENU_PREFERENCES_KEY, Menu.NONE, "Settings").setIcon(android.R.drawable.ic_menu_preferences); menu.add(0, MENU_PREFERENCES_KEY, Menu.NONE, "Settings").setIcon(android.R.drawable.ic_menu_preferences);
SubMenu importExportMenu = menu.addSubMenu("Import/Export").setIcon(android.R.drawable.ic_menu_save); SubMenu importExportMenu = menu.addSubMenu("Import/Export").setIcon(android.R.drawable.ic_menu_save);
importExportMenu.add(0, MENU_EXPORT, Menu.NONE, "Export To SD Card").setIcon(android.R.drawable.ic_menu_save); importExportMenu.add(0, MENU_EXPORT, Menu.NONE, "Export To SD Card").setIcon(android.R.drawable.ic_menu_save);
importExportMenu.add(0, MENU_IMPORT, Menu.NONE, "Import From SD Card").setIcon(android.R.drawable.ic_menu_revert); importExportMenu.add(0, MENU_IMPORT, Menu.NONE, "Import From SD Card").setIcon(android.R.drawable.ic_menu_revert);
SubMenu moreMenu = menu.addSubMenu("More").setIcon(android.R.drawable.ic_menu_more); SubMenu moreMenu = menu.addSubMenu("More").setIcon(android.R.drawable.ic_menu_more);
if (masterSecret != null) if (masterSecret != null)
moreMenu.add(0, MENU_CLEAR_PASSPHRASE, Menu.NONE, "Clear Passphrase").setIcon(android.R.drawable.ic_menu_close_clear_cancel); moreMenu.add(0, MENU_CLEAR_PASSPHRASE, Menu.NONE, "Clear Passphrase").setIcon(android.R.drawable.ic_menu_close_clear_cancel);
} }
private void prepareBatchModeMenu(Menu menu) { private void prepareBatchModeMenu(Menu menu) {
menu.add(0, MENU_EXIT_BATCH, Menu.NONE, "Normal Mode").setIcon(android.R.drawable.ic_menu_set_as); menu.add(0, MENU_EXIT_BATCH, Menu.NONE, "Normal Mode").setIcon(android.R.drawable.ic_menu_set_as);
menu.add(0, MENU_DELETE_SELECTED_THREADS, Menu.NONE, "Delete Selected").setIcon(android.R.drawable.ic_menu_delete); menu.add(0, MENU_DELETE_SELECTED_THREADS, Menu.NONE, "Delete Selected").setIcon(android.R.drawable.ic_menu_delete);
menu.add(0, MENU_SELECT_ALL_THREADS, Menu.NONE, "Select All").setIcon(android.R.drawable.ic_menu_add); menu.add(0, MENU_SELECT_ALL_THREADS, Menu.NONE, "Select All").setIcon(android.R.drawable.ic_menu_add);
menu.add(0, MENU_CLEAR_SELECTION, Menu.NONE, "Unselect All").setIcon(android.R.drawable.ic_menu_revert); menu.add(0, MENU_CLEAR_SELECTION, Menu.NONE, "Unselect All").setIcon(android.R.drawable.ic_menu_revert);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item); super.onOptionsItemSelected(item);
switch (item.getItemId()) { switch (item.getItemId()) {
case MENU_SEND_KEY: case MENU_SEND_KEY:
Intent intent = new Intent(this, SendKeyActivity.class); Intent intent = new Intent(this, SendKeyActivity.class);
intent.putExtra("master_secret", masterSecret); intent.putExtra("master_secret", masterSecret);
startActivity(intent); startActivity(intent);
return true; return true;
case MENU_PASSPHRASE_KEY: case MENU_PASSPHRASE_KEY:
@ -261,24 +261,24 @@ public class SecureSMS extends ListActivity {
// finish(); // finish();
return true; return true;
} }
return false; return false;
} }
@Override @Override
protected void onNewIntent(Intent intent) { protected void onNewIntent(Intent intent) {
super.onNewIntent(intent); super.onNewIntent(intent);
Log.w("SecureSMS", "Got onNewIntent..."); Log.w("SecureSMS", "Got onNewIntent...");
createConversationIfNecessary(intent); createConversationIfNecessary(intent);
} }
public void eulaComplete() { public void eulaComplete() {
clearNotifications(); clearNotifications();
initializeReceivers(); initializeReceivers();
checkCachingService(); checkCachingService();
} }
@Override @Override
public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
if (((AdapterView.AdapterContextMenuInfo)menuInfo).position > 0) { if (((AdapterView.AdapterContextMenuInfo)menuInfo).position > 0) {
@ -287,7 +287,7 @@ public class SecureSMS extends ListActivity {
Recipients recipients = RecipientFactory.getRecipientsForIds(this, recipientId); Recipients recipients = RecipientFactory.getRecipientsForIds(this, recipientId);
menu.add(0, VIEW_THREAD_ID, Menu.NONE, "View thread"); menu.add(0, VIEW_THREAD_ID, Menu.NONE, "View thread");
if (recipients.isSingleRecipient()) { if (recipients.isSingleRecipient()) {
if (recipients.getPrimaryRecipient().getName() != null) { if (recipients.getPrimaryRecipient().getName() != null) {
menu.add(0, VIEW_CONTACT_ID, Menu.NONE, "View contact"); menu.add(0, VIEW_CONTACT_ID, Menu.NONE, "View contact");
@ -295,13 +295,13 @@ public class SecureSMS extends ListActivity {
menu.add(0, ADD_CONTACT_ID, Menu.NONE, "Add to contacts"); menu.add(0, ADD_CONTACT_ID, Menu.NONE, "Add to contacts");
} }
} }
menu.add(0, DELETE_THREAD_ID, Menu.NONE, "Delete thread"); menu.add(0, DELETE_THREAD_ID, Menu.NONE, "Delete thread");
} }
} }
@Override @Override
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(android.view.MenuItem item) {
Cursor cursor = ((CursorAdapter)this.getListAdapter()).getCursor(); Cursor cursor = ((CursorAdapter)this.getListAdapter()).getCursor();
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID)); long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
String recipientId = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_IDS)); String recipientId = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_IDS));
@ -323,35 +323,35 @@ public class SecureSMS extends ListActivity {
} }
return false; return false;
} }
private void initiateBatchMode() { private void initiateBatchMode() {
this.batchMode = true; this.batchMode = true;
((ConversationListAdapter)this.getListAdapter()).initializeBatchMode(batchMode); ((ConversationListAdapter)this.getListAdapter()).initializeBatchMode(batchMode);
} }
private void stopBatchMode() { private void stopBatchMode() {
this.batchMode = false; this.batchMode = false;
((ConversationListAdapter)this.getListAdapter()).initializeBatchMode(batchMode); ((ConversationListAdapter)this.getListAdapter()).initializeBatchMode(batchMode);
} }
private void selectAllThreads() { private void selectAllThreads() {
((ConversationListAdapter)this.getListAdapter()).selectAllThreads(); ((ConversationListAdapter)this.getListAdapter()).selectAllThreads();
} }
private void unselectAllThreads() { private void unselectAllThreads() {
((ConversationListAdapter)this.getListAdapter()).unselectAllThreads(); ((ConversationListAdapter)this.getListAdapter()).unselectAllThreads();
} }
private void deleteSelectedThreads() { private void deleteSelectedThreads() {
AlertDialog.Builder alert = new AlertDialog.Builder(this); AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setIcon(android.R.drawable.ic_dialog_alert); alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle("Delete threads?"); alert.setTitle("Delete threads?");
alert.setMessage("Are you sure you wish to delete ALL selected conversation threads?"); alert.setMessage("Are you sure you wish to delete ALL selected conversation threads?");
alert.setCancelable(true); alert.setCancelable(true);
alert.setPositiveButton("Delete", new DialogInterface.OnClickListener() { alert.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
Set<Long> selectedConversations = ((ConversationListAdapter)getListAdapter()).getBatchSelections(); Set<Long> selectedConversations = ((ConversationListAdapter)getListAdapter()).getBatchSelections();
if (!selectedConversations.isEmpty()) if (!selectedConversations.isEmpty())
DatabaseFactory.getThreadDatabase(SecureSMS.this).deleteConversations(selectedConversations); DatabaseFactory.getThreadDatabase(SecureSMS.this).deleteConversations(selectedConversations);
} }
@ -359,57 +359,52 @@ public class SecureSMS extends ListActivity {
alert.setNegativeButton("Cancel", null); alert.setNegativeButton("Cancel", null);
alert.show(); alert.show();
} }
private void registerForContactsUpdates() { private void registerForContactsUpdates() {
Log.w("SecureSMS", "Registering for contacts update..."); Log.w("SecureSMS", "Registering for contacts update...");
getContentResolver().registerContentObserver(ContactAccessor.getInstance().getContactsUri(), true, new ContactUpdateObserver()); getContentResolver().registerContentObserver(ContactAccessor.getInstance().getContactsUri(), true, new ContactUpdateObserver());
} }
private void registerPassphraseActivityStarted() { private void registerPassphraseActivityStarted() {
Intent intent = new Intent(this, KeyCachingService.class); Intent intent = new Intent(this, KeyCachingService.class);
intent.setAction(KeyCachingService.ACTIVITY_START_EVENT); intent.setAction(KeyCachingService.ACTIVITY_START_EVENT);
startService(intent); startService(intent);
} }
private void registerPassphraseActivityStopped() { private void registerPassphraseActivityStopped() {
Intent intent = new Intent(this, KeyCachingService.class); Intent intent = new Intent(this, KeyCachingService.class);
intent.setAction(KeyCachingService.ACTIVITY_STOP_EVENT); intent.setAction(KeyCachingService.ACTIVITY_STOP_EVENT);
startService(intent); startService(intent);
} }
private void addContact(Recipient recipient) { private void addContact(Recipient recipient) {
RecipientFactory.getRecipientProvider().addContact(this, recipient); RecipientFactory.getRecipientProvider().addContact(this, recipient);
} }
private void viewContact(Recipient recipient) { private void viewContact(Recipient recipient) {
if (recipient.getPersonId() > 0) { if (recipient.getPersonId() > 0) {
RecipientFactory.getRecipientProvider().viewContact(this, recipient); RecipientFactory.getRecipientProvider().viewContact(this, recipient);
} }
} }
private void clearNotifications() { private void clearNotifications() {
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(KeyCachingService.NOTIFICATION_ID); manager.cancel(KeyCachingService.NOTIFICATION_ID);
} }
private void initializeResources() {
// ImageView settingsImage = (ImageView)findViewById(R.id.settings_button);
// settingsImage.setOnClickListener(new SettingsClickListener());
}
private void initializeKillReceiver() { private void initializeKillReceiver() {
killActivityReceiver = new KillActivityReceiver(); killActivityReceiver = new KillActivityReceiver();
registerReceiver(killActivityReceiver, new IntentFilter(KeyCachingService.PASSPHRASE_EXPIRED_EVENT), registerReceiver(killActivityReceiver, new IntentFilter(KeyCachingService.PASSPHRASE_EXPIRED_EVENT),
KeyCachingService.KEY_PERMISSION, null); KeyCachingService.KEY_PERMISSION, null);
} }
private void initializeSenderReceiverService() { private void initializeSenderReceiverService() {
Intent smsSenderIntent = new Intent(SendReceiveService.SEND_SMS_ACTION, null, this, SendReceiveService.class); Intent smsSenderIntent = new Intent(SendReceiveService.SEND_SMS_ACTION, null, this, SendReceiveService.class);
Intent mmsSenderIntent = new Intent(SendReceiveService.SEND_MMS_ACTION, null, this, SendReceiveService.class); Intent mmsSenderIntent = new Intent(SendReceiveService.SEND_MMS_ACTION, null, this, SendReceiveService.class);
startService(smsSenderIntent); startService(smsSenderIntent);
startService(mmsSenderIntent); startService(mmsSenderIntent);
} }
private void checkCachingService() { private void checkCachingService() {
Log.w("securesms", "Checking caching service..."); Log.w("securesms", "Checking caching service...");
Intent bindIntent = new Intent(this, KeyCachingService.class); Intent bindIntent = new Intent(this, KeyCachingService.class);
@ -420,46 +415,46 @@ public class SecureSMS extends ListActivity {
if (masterSecret != null) if (masterSecret != null)
DecryptingQueue.schedulePendingDecrypts(this, masterSecret); DecryptingQueue.schedulePendingDecrypts(this, masterSecret);
} }
private void migrateDatabase() { private void migrateDatabase() {
MigrationHandler mh = new MigrationHandler(); MigrationHandler mh = new MigrationHandler();
mh.migrate(); mh.migrate();
} }
private boolean isMigrated() { private boolean isMigrated() {
return this.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).getBoolean("migrated", false); return this.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).getBoolean("migrated", false);
} }
private void initializeWithMasterSecret(MasterSecret masterSecret) { private void initializeWithMasterSecret(MasterSecret masterSecret) {
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
if (masterSecret != null) { if (masterSecret != null) {
if (!IdentityKeyUtil.hasIdentityKey(this)) initializeIdentityKeys(); if (!IdentityKeyUtil.hasIdentityKey(this)) initializeIdentityKeys();
if (!MasterSecretUtil.hasAsymmericMasterSecret(this)) initializeAsymmetricMasterSecret(); if (!MasterSecretUtil.hasAsymmericMasterSecret(this)) initializeAsymmetricMasterSecret();
if (!isMigrated()) migrateDatabase(); if (!isMigrated()) migrateDatabase();
else DecryptingQueue.schedulePendingDecrypts(this, masterSecret); else DecryptingQueue.schedulePendingDecrypts(this, masterSecret);
} }
addNewMessageItem(); addNewMessageItem();
addConversationItems(); addConversationItems();
createConversationIfNecessary(this.getIntent()); createConversationIfNecessary(this.getIntent());
} }
private void initializeAsymmetricMasterSecret() { private void initializeAsymmetricMasterSecret() {
new Thread(new AsymmetricMasteSecretInitializer()).start(); new Thread(new AsymmetricMasteSecretInitializer()).start();
} }
private void initializeIdentityKeys() { private void initializeIdentityKeys() {
new Thread(new IdentityKeyInitializer()).start(); new Thread(new IdentityKeyInitializer()).start();
} }
private void initializeSearchListener() { private void initializeSearchListener() {
SearchTextListener listener = new SearchTextListener(); SearchTextListener listener = new SearchTextListener();
searchBox = (EditText)findViewById(R.id.search_text); searchBox = (EditText)findViewById(R.id.search_text);
searchBox.addTextChangedListener(listener); searchBox.addTextChangedListener(listener);
this.getListView().setOnKeyListener(listener); this.getListView().setOnKeyListener(listener);
} }
private void initializeReceivers() { private void initializeReceivers() {
Log.w("securesms", "Registering receiver..."); Log.w("securesms", "Registering receiver...");
receiver = new NewKeyReceiver(); receiver = new NewKeyReceiver();
@ -468,25 +463,6 @@ public class SecureSMS extends ListActivity {
registerReceiver(receiver, filter, KeyCachingService.KEY_PERMISSION, null); registerReceiver(receiver, filter, KeyCachingService.KEY_PERMISSION, null);
} }
private void initializeColors() {
if (!PreferenceManager.getDefaultSharedPreferences(this).getBoolean(ApplicationPreferencesActivity.DARK_THREADS_PREF, true)) {
this.getListView().setBackgroundColor(Color.WHITE);
this.getListView().setCacheColorHint(Color.WHITE);
this.getListView().setDivider(new ColorDrawable(Color.parseColor("#cccccc")));
this.getListView().setDividerHeight(1);
} else {
this.getListView().setBackgroundColor(Color.BLACK);
this.getListView().setCacheColorHint(Color.BLACK);
this.getListView().setDivider(this.getResources().getDrawable(R.drawable.dark_divider));
this.getListView().setDividerHeight(1);
}
if (headerView != null) {
headerView.initializeColors();
headerView.setBackgroundColor(Color.TRANSPARENT);
}
}
@Override @Override
protected void onListItemClick(ListView l, View v, int position, long id) { protected void onListItemClick(ListView l, View v, int position, long id) {
if (position == 0) { if (position == 0) {
@ -496,11 +472,11 @@ public class SecureSMS extends ListActivity {
createConversation(headerView.getThreadId(), headerView.getRecipients()); createConversation(headerView.getThreadId(), headerView.getRecipients());
} }
} }
private void createConversationIfNecessary(Intent intent) { private void createConversationIfNecessary(Intent intent) {
long thread = intent.getLongExtra("thread_id", -1L); long thread = intent.getLongExtra("thread_id", -1L);
Recipients recipients = null; Recipients recipients = null;
if (intent.getAction() != null && intent.getAction().equals("android.intent.action.SENDTO")) { if (intent.getAction() != null && intent.getAction().equals("android.intent.action.SENDTO")) {
try { try {
recipients = RecipientFactory.getRecipientsFromString(this, intent.getData().getSchemeSpecificPart()); recipients = RecipientFactory.getRecipientsFromString(this, intent.getData().getSchemeSpecificPart());
@ -511,7 +487,7 @@ public class SecureSMS extends ListActivity {
} else { } else {
recipients = intent.getParcelableExtra("recipients"); recipients = intent.getParcelableExtra("recipients");
} }
if (recipients != null) { if (recipients != null) {
createConversation(thread, recipients); createConversation(thread, recipients);
intent.putExtra("thread_id", -1L); intent.putExtra("thread_id", -1L);
@ -519,41 +495,41 @@ public class SecureSMS extends ListActivity {
intent.setAction(null); intent.setAction(null);
} }
} }
private void createConversation(long threadId, Recipients recipients) { private void createConversation(long threadId, Recipients recipients) {
if (this.masterSecret == null) { if (this.masterSecret == null) {
promptForPassphrase(); promptForPassphrase();
return; return;
} }
Intent intent = new Intent(this, ComposeMessageActivity.class); Intent intent = new Intent(this, ComposeMessageActivity.class);
intent.putExtra("recipients", recipients); intent.putExtra("recipients", recipients);
intent.putExtra("thread_id", threadId); intent.putExtra("thread_id", threadId);
intent.putExtra("master_secret", masterSecret); intent.putExtra("master_secret", masterSecret);
startActivity(intent); startActivity(intent);
} }
private void addNewMessageItem() { private void addNewMessageItem() {
ListView listView = getListView(); ListView listView = getListView();
if (listView.getHeaderViewsCount() > 0) return; if (listView.getHeaderViewsCount() > 0) return;
ArrayList<Recipient> dummyList = new ArrayList<Recipient>(); ArrayList<Recipient> dummyList = new ArrayList<Recipient>();
dummyList.add(new Recipient("New Message", null, null)); dummyList.add(new Recipient("New Message", null, null));
Recipients recipients = new Recipients(dummyList); Recipients recipients = new Recipients(dummyList);
headerView = new ConversationHeaderView(this, true); headerView = new ConversationHeaderView(this, true);
MessageRecord messageRecord = new MessageRecord(-1, recipients, 0, 0, true, -1); MessageRecord messageRecord = new MessageRecord(-1, recipients, 0, 0, true, -1);
messageRecord.setBody("Compose new message."); messageRecord.setBody("Compose new message.");
headerView.set(messageRecord, false); headerView.set(messageRecord, false);
// headerView.setBackgroundColor(Color.TRANSPARENT); // headerView.setBackgroundColor(Color.TRANSPARENT);
listView.addHeaderView(headerView, null, true); listView.addHeaderView(headerView, null, true);
} }
private void addConversationItems() { private void addConversationItems() {
Cursor cursor = DatabaseFactory.getThreadDatabase(this).getConversationList(); Cursor cursor = DatabaseFactory.getThreadDatabase(this).getConversationList();
startManagingCursor(cursor); startManagingCursor(cursor);
if (masterSecret == null) setListAdapter(new ConversationListAdapter(this, cursor)); if (masterSecret == null) setListAdapter(new ConversationListAdapter(this, cursor));
else setListAdapter(new DecryptingConversationListAdapter(this, cursor, masterSecret)); else setListAdapter(new DecryptingConversationListAdapter(this, cursor, masterSecret));
} }
@ -568,18 +544,18 @@ public class SecureSMS extends ListActivity {
builder.setNegativeButton(R.string.no, null); builder.setNegativeButton(R.string.no, null);
builder.show(); builder.show();
} }
private void promptForPassphrase() { private void promptForPassphrase() {
havePromptedForPassphrase = true; havePromptedForPassphrase = true;
if (hasSelectedPassphrase()) startActivity(new Intent(this, PassphrasePromptActivity.class)); if (hasSelectedPassphrase()) startActivity(new Intent(this, PassphrasePromptActivity.class));
else startActivity(new Intent(this, PassphraseCreateActivity.class)); else startActivity(new Intent(this, PassphraseCreateActivity.class));
} }
private boolean hasSelectedPassphrase() { private boolean hasSelectedPassphrase() {
SharedPreferences settings = getSharedPreferences(KeyCachingService.PREFERENCES_NAME, 0); SharedPreferences settings = getSharedPreferences(KeyCachingService.PREFERENCES_NAME, 0);
return settings.getBoolean("passphrase_initialized", false); return settings.getBoolean("passphrase_initialized", false);
} }
private ServiceConnection serviceConnection = new ServiceConnection() { private ServiceConnection serviceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
KeyCachingService keyCachingService = ((KeyCachingService.KeyCachingBinder)service).getService(); KeyCachingService keyCachingService = ((KeyCachingService.KeyCachingBinder)service).getService();
@ -587,14 +563,14 @@ public class SecureSMS extends ListActivity {
initializeWithMasterSecret(masterSecret); initializeWithMasterSecret(masterSecret);
if (masterSecret == null && !havePromptedForPassphrase) if (masterSecret == null && !havePromptedForPassphrase)
promptForPassphrase(); promptForPassphrase();
Intent cachingIntent = new Intent(SecureSMS.this, KeyCachingService.class); Intent cachingIntent = new Intent(SecureSMS.this, KeyCachingService.class);
startService(cachingIntent); startService(cachingIntent);
try { try {
SecureSMS.this.unbindService(this); SecureSMS.this.unbindService(this);
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
Log.w("SecureSMS", iae); Log.w("SecureSMS", iae);
} }
@ -602,21 +578,21 @@ public class SecureSMS extends ListActivity {
public void onServiceDisconnected(ComponentName name) {} public void onServiceDisconnected(ComponentName name) {}
}; };
private class DeleteThreadListener implements DialogInterface.OnClickListener { private class DeleteThreadListener implements DialogInterface.OnClickListener {
private final long threadId; private final long threadId;
public DeleteThreadListener(long threadId) { public DeleteThreadListener(long threadId) {
this.threadId = threadId; this.threadId = threadId;
} }
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (threadId > 0) { if (threadId > 0) {
DatabaseFactory.getThreadDatabase(SecureSMS.this).deleteConversation(threadId); DatabaseFactory.getThreadDatabase(SecureSMS.this).deleteConversation(threadId);
} }
} }
}; };
private class NewKeyReceiver extends BroadcastReceiver { private class NewKeyReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -624,43 +600,43 @@ public class SecureSMS extends ListActivity {
initializeWithMasterSecret((MasterSecret)intent.getParcelableExtra("master_secret")); initializeWithMasterSecret((MasterSecret)intent.getParcelableExtra("master_secret"));
} }
} }
private class KillActivityReceiver extends BroadcastReceiver { private class KillActivityReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context arg0, Intent arg1) { public void onReceive(Context arg0, Intent arg1) {
finish(); finish();
} }
} }
// private class SettingsClickListener implements View.OnClickListener { // private class SettingsClickListener implements View.OnClickListener {
// public void onClick(View v) { // public void onClick(View v) {
// startActivity(new Intent(SecureSMS.this, ApplicationPreferencesActivity.class)); // startActivity(new Intent(SecureSMS.this, ApplicationPreferencesActivity.class));
// } // }
// } // }
private class IdentityKeyInitializer implements Runnable { private class IdentityKeyInitializer implements Runnable {
public void run() { public void run() {
IdentityKeyUtil.generateIdentityKeys(SecureSMS.this, masterSecret); IdentityKeyUtil.generateIdentityKeys(SecureSMS.this, masterSecret);
} }
} }
private class AsymmetricMasteSecretInitializer implements Runnable { private class AsymmetricMasteSecretInitializer implements Runnable {
public void run() { public void run() {
MasterSecretUtil.generateAsymmetricMasterSecret(SecureSMS.this, masterSecret); MasterSecretUtil.generateAsymmetricMasterSecret(SecureSMS.this, masterSecret);
} }
} }
private class ExportHandler extends Handler implements Runnable { private class ExportHandler extends Handler implements Runnable {
private static final int ERROR_NO_SD = 0; private static final int ERROR_NO_SD = 0;
private static final int ERROR_IO = 1; private static final int ERROR_IO = 1;
private static final int COMPLETE = 2; private static final int COMPLETE = 2;
private static final int TASK_EXPORT = 0; private static final int TASK_EXPORT = 0;
private static final int TASK_IMPORT = 1; private static final int TASK_IMPORT = 1;
private int task; private int task;
private ProgressDialog progressDialog; private ProgressDialog progressDialog;
public void run() { public void run() {
try { try {
switch (task) { switch (task) {
@ -676,11 +652,11 @@ public class SecureSMS extends ListActivity {
this.obtainMessage(ERROR_IO).sendToTarget(); this.obtainMessage(ERROR_IO).sendToTarget();
return; return;
} }
this.obtainMessage(COMPLETE).sendToTarget(); this.obtainMessage(COMPLETE).sendToTarget();
} }
private void continueExport() { private void continueExport() {
task = TASK_EXPORT; task = TASK_EXPORT;
progressDialog = new ProgressDialog(SecureSMS.this); progressDialog = new ProgressDialog(SecureSMS.this);
progressDialog.setTitle("Exporting Database and Keys"); progressDialog.setTitle("Exporting Database and Keys");
@ -691,7 +667,7 @@ public class SecureSMS extends ListActivity {
progressDialog.show(); progressDialog.show();
new Thread(this).start(); new Thread(this).start();
} }
private void continueImport() { private void continueImport() {
task = TASK_IMPORT; task = TASK_IMPORT;
progressDialog = new ProgressDialog(SecureSMS.this); progressDialog = new ProgressDialog(SecureSMS.this);
@ -701,21 +677,21 @@ public class SecureSMS extends ListActivity {
progressDialog.setIndeterminate(true); progressDialog.setIndeterminate(true);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show(); progressDialog.show();
initializeWithMasterSecret(null); initializeWithMasterSecret(null);
Intent clearKeyIntent = new Intent(KeyCachingService.CLEAR_KEY_ACTION, null, SecureSMS.this, KeyCachingService.class); Intent clearKeyIntent = new Intent(KeyCachingService.CLEAR_KEY_ACTION, null, SecureSMS.this, KeyCachingService.class);
startService(clearKeyIntent); startService(clearKeyIntent);
DatabaseFactory.getInstance(SecureSMS.this).close(); DatabaseFactory.getInstance(SecureSMS.this).close();
new Thread(this).start(); new Thread(this).start();
} }
public void importFromSd() { public void importFromSd() {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(SecureSMS.this); AlertDialog.Builder alertBuilder = new AlertDialog.Builder(SecureSMS.this);
alertBuilder.setTitle("Import Database and Settings?"); alertBuilder.setTitle("Import Database and Settings?");
alertBuilder.setMessage("Import TextSecure database, keys, and settings from the SD Card?\n\nWARNING: This will clobber any existing messages, keys, and settings!"); alertBuilder.setMessage("Import TextSecure database, keys, and settings from the SD Card?\n\nWARNING: This will clobber any existing messages, keys, and settings!");
alertBuilder.setCancelable(false); alertBuilder.setCancelable(false);
alertBuilder.setPositiveButton("Import", new DialogInterface.OnClickListener() { alertBuilder.setPositiveButton("Import", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
continueImport(); continueImport();
} }
@ -724,15 +700,15 @@ public class SecureSMS extends ListActivity {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
} }
}); });
alertBuilder.create().show(); alertBuilder.create().show();
} }
public void export() { public void export() {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(SecureSMS.this); AlertDialog.Builder alertBuilder = new AlertDialog.Builder(SecureSMS.this);
alertBuilder.setTitle("Export Database?"); alertBuilder.setTitle("Export Database?");
alertBuilder.setMessage("Export TextSecure database, keys, and settings to the SD Card?"); alertBuilder.setMessage("Export TextSecure database, keys, and settings to the SD Card?");
alertBuilder.setCancelable(false); alertBuilder.setCancelable(false);
alertBuilder.setPositiveButton("Export", new DialogInterface.OnClickListener() { alertBuilder.setPositiveButton("Export", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
continueExport(); continueExport();
} }
@ -743,7 +719,7 @@ public class SecureSMS extends ListActivity {
}); });
alertBuilder.create().show(); alertBuilder.create().show();
} }
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
switch (message.what) { switch (message.what) {
@ -766,68 +742,68 @@ public class SecureSMS extends ListActivity {
} }
break; break;
} }
progressDialog.dismiss(); progressDialog.dismiss();
} }
} }
private class SearchTextListener extends Handler implements TextWatcher, Runnable, View.OnClickListener, View.OnKeyListener { private class SearchTextListener extends Handler implements TextWatcher, Runnable, View.OnClickListener, View.OnKeyListener {
private final ImageView closeButton; private final ImageView closeButton;
private final ProgressBar progressDialog; private final ProgressBar progressDialog;
private final KeyCharacterMap keyMap; private final KeyCharacterMap keyMap;
private int outstandingThreads; private int outstandingThreads;
public SearchTextListener() { public SearchTextListener() {
closeButton = (ImageView)findViewById(R.id.search_close); closeButton = (ImageView)findViewById(R.id.search_close);
progressDialog = (ProgressBar)findViewById(R.id.search_progress); progressDialog = (ProgressBar)findViewById(R.id.search_progress);
keyMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD); keyMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
outstandingThreads = 0; outstandingThreads = 0;
closeButton.setOnClickListener(this); closeButton.setOnClickListener(this);
} }
private Cursor getCursorForFilter(String text) { private Cursor getCursorForFilter(String text) {
if (text.length() > 0) { if (text.length() > 0) {
List<String> numbers = ContactAccessor.getInstance().getNumbersForThreadSearchFilter(text, getContentResolver()); List<String> numbers = ContactAccessor.getInstance().getNumbersForThreadSearchFilter(text, getContentResolver());
return DatabaseFactory.getThreadDatabase(SecureSMS.this).getFilteredConversationList(numbers); return DatabaseFactory.getThreadDatabase(SecureSMS.this).getFilteredConversationList(numbers);
} else { } else {
return DatabaseFactory.getThreadDatabase(SecureSMS.this).getConversationList(); return DatabaseFactory.getThreadDatabase(SecureSMS.this).getConversationList();
} }
} }
public void afterTextChanged(Editable arg0) { public void afterTextChanged(Editable arg0) {
synchronized (this) { synchronized (this) {
if (outstandingThreads == 0) if (outstandingThreads == 0)
progressDialog.setVisibility(View.VISIBLE); progressDialog.setVisibility(View.VISIBLE);
outstandingThreads++; outstandingThreads++;
} }
new Thread(this).start(); new Thread(this).start();
} }
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
Cursor cursor = (Cursor)message.obj; Cursor cursor = (Cursor)message.obj;
if (cursor != null) if (cursor != null)
startManagingCursor(cursor); startManagingCursor(cursor);
if (getListAdapter() != null) if (getListAdapter() != null)
((CursorAdapter)getListAdapter()).changeCursor(cursor); ((CursorAdapter)getListAdapter()).changeCursor(cursor);
synchronized (this) { synchronized (this) {
outstandingThreads--; outstandingThreads--;
if (outstandingThreads == 0) if (outstandingThreads == 0)
progressDialog.setVisibility(View.GONE); progressDialog.setVisibility(View.GONE);
} }
} }
public void run() { public void run() {
String text = searchBox.getText().toString(); String text = searchBox.getText().toString();
Cursor cursor = getCursorForFilter(text); Cursor cursor = getCursorForFilter(text);
this.obtainMessage(0, cursor).sendToTarget(); this.obtainMessage(0, cursor).sendToTarget();
} }
@ -849,11 +825,11 @@ public class SecureSMS extends ListActivity {
searchBox.requestFocus(); searchBox.requestFocus();
return true; return true;
} }
return false; return false;
} }
} }
private class ContactUpdateObserver extends ContentObserver { private class ContactUpdateObserver extends ContentObserver {
public ContactUpdateObserver() { public ContactUpdateObserver() {
super(null); super(null);
@ -866,15 +842,15 @@ public class SecureSMS extends ListActivity {
RecipientFactory.clearCache(); RecipientFactory.clearCache();
} }
} }
private class MigrationHandler extends Handler implements Runnable { private class MigrationHandler extends Handler implements Runnable {
private ProgressDialog progressDialog; private ProgressDialog progressDialog;
public void run() { public void run() {
SmsMigrator.migrateDatabase(SecureSMS.this, masterSecret, this); SmsMigrator.migrateDatabase(SecureSMS.this, masterSecret, this);
} }
private void continueMigration() { private void continueMigration() {
progressDialog = new ProgressDialog(SecureSMS.this); progressDialog = new ProgressDialog(SecureSMS.this);
progressDialog.setTitle("Migrating Database"); progressDialog.setTitle("Migrating Database");
progressDialog.setMessage("Migrating your SMS database..."); progressDialog.setMessage("Migrating your SMS database...");
@ -885,18 +861,18 @@ public class SecureSMS extends ListActivity {
progressDialog.show(); progressDialog.show();
new Thread(this).start(); new Thread(this).start();
} }
private void cancelMigration() { private void cancelMigration() {
SecureSMS.this.getSharedPreferences("SecureSMS", MODE_PRIVATE).edit().putBoolean("migrated", true).commit(); SecureSMS.this.getSharedPreferences("SecureSMS", MODE_PRIVATE).edit().putBoolean("migrated", true).commit();
SecureSMS.this.migrateDatabaseComplete(); SecureSMS.this.migrateDatabaseComplete();
} }
public void migrate() { public void migrate() {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(SecureSMS.this); AlertDialog.Builder alertBuilder = new AlertDialog.Builder(SecureSMS.this);
alertBuilder.setTitle("Copy System Text Message Database?"); alertBuilder.setTitle("Copy System Text Message Database?");
alertBuilder.setMessage("Current versions of TextSecure use an encrypted database that is separate from the default system database. Would you like to copy your existing text messages into TextSecure's encrypted database? Your default system database will be unaffected."); alertBuilder.setMessage("Current versions of TextSecure use an encrypted database that is separate from the default system database. Would you like to copy your existing text messages into TextSecure's encrypted database? Your default system database will be unaffected.");
alertBuilder.setCancelable(false); alertBuilder.setCancelable(false);
alertBuilder.setPositiveButton("Copy", new DialogInterface.OnClickListener() { alertBuilder.setPositiveButton("Copy", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
continueMigration(); continueMigration();
} }
@ -908,7 +884,7 @@ public class SecureSMS extends ListActivity {
}); });
alertBuilder.create().show(); alertBuilder.create().show();
} }
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
switch (message.what) { switch (message.what) {
@ -927,5 +903,5 @@ public class SecureSMS extends ListActivity {
} }
} }
} }