package org.bitseal.activities;
import info.guardianproject.cacheword.CacheWordHandler;
import info.guardianproject.cacheword.ICacheWordSubscriber;
import java.util.ArrayList;
import java.util.Collections;
import org.bitseal.R;
import org.bitseal.core.AddressProcessor;
import org.bitseal.data.Address;
import org.bitseal.data.AddressBookRecord;
import org.bitseal.data.Message;
import org.bitseal.database.AddressBookRecordProvider;
import org.bitseal.database.AddressBookRecordsTable;
import org.bitseal.database.AddressProvider;
import org.bitseal.database.AddressesTable;
import org.bitseal.database.MessageProvider;
import org.bitseal.services.BackgroundService;
import org.bitseal.services.AppLockHandler;
import org.bitseal.util.ColourCalculator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
/**
* The Activity class for the app's "Compose" screen.
*
* @author Jonathan Coe
*/
public class ComposeActivity extends Activity implements ICacheWordSubscriber
{
public static final String EXTRA_TO_ADDRESS = "composeActivity.TO_ADDRESS";
public static final String EXTRA_FROM_ADDRESS = "composeActivity.FROM_ADDRESS";
public static final String EXTRA_SUBJECT = "composeActivity.SUBJECT";
public static final String EXTRA_BODY = "composeActivity.BODY";
public static final String EXTRA_COLOUR_R = "composeActivity.COLOUR_R";
public static final String EXTRA_COLOUR_G = "composeActivity.COLOUR_G";
public static final String EXTRA_COLOUR_B = "composeActivity.COLOUR_B";
public static final String KEY_TO_ADDRESS = "toAddress";
public static final String KEY_FROM_ADDRESS = "fromAddress";
public static final String KEY_SUBJECT = "subject";
public static final String KEY_BODY = "body";
private ArrayList<AddressBookRecord> mAddressBookRecords;
private ArrayList<Address> mAddresses;
private AddressBookRecordAdapter mToAddressesAdapter;
private AddressAdapter mFromAddressesAdapter;
private String mToAddress = "";
private String mFromAddress = "";
private String mSubject = "";
private String mBody = "";
private View mMainView;
private ListView mToAddressSelectionListView;
private ListView mFromAddressSelectionListView;
private EditText mToAddressEditText;
private EditText mFromAddressEditText;
private EditText mSubjectEditText;
private EditText mBodyEditText;
private TextView mToAddressSelectionListItemLabelTextView;
private TextView mToAddressSelectionListItemAddressTextView;
private TextView mFromAddressSelectionListItemLabelTextView;
private TextView mFromAddressSelectionListItemAddressTextView;
private int mColourR;
private int mColourG;
private int mColourB;
private static final String KEY_TO_ADDRESS_DIALOG_SELECTION = "toAddressDialogSelection";
private static final String KEY_FROM_ADDRESS_DIALOG_SELECTION = "fromAddressDialogSelection";
private static final String KEY_ON_PAUSE_CALLED = "onPauseCalled";
private static final int COMPOSE_COLOURS_ALPHA_VALUE = 70;
/**
* The maximum permissible size for a message's text (subject + body), in bytes. The maximum size
* of an object in Bitmessage protocol version 3 is 256kB. We allow some extra room for the rest of
* the msg object which this message which eventually be transformed into.
*/
private static final int MAXIMUM_MESSAGE_TEXT_SIZE = 250000;
/** The key for a boolean variable that records whether or not a user-defined database encryption passphrase has been saved */
private static final String KEY_DATABASE_PASSPHRASE_SAVED = "databasePassphraseSaved";
private CacheWordHandler mCacheWordHandler;
private static final String TAG = "COMPOSE_ACTIVITY";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Check whether the user has set a database encryption passphrase
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (prefs.getBoolean(KEY_DATABASE_PASSPHRASE_SAVED, false))
{
// Connect to the CacheWordService
mCacheWordHandler = new CacheWordHandler(this);
mCacheWordHandler.connectToService();
}
setLayout();
createDialogs();
useExtras(getIntent()); // Use any extras bundled with the Intent that started this activity
autoSetFromAddress(); // If we have only one address, auto-set mFromAddress
setColours();
populateEditTexts();
}
@Override
protected void onResume()
{
super.onResume();
useAddressLabels();
formatEditTexts();
positionCursor();
}
@Override
protected void onPause()
{
super.onPause();
// We need to clear the saved dialog selections so that they aren't used in future openings of this activity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putString(KEY_TO_ADDRESS_DIALOG_SELECTION, "");
editor.putString(KEY_FROM_ADDRESS_DIALOG_SELECTION, "");
// Used to detect screen rotation while the to or from address selection dialogs are open
editor.putBoolean(KEY_ON_PAUSE_CALLED, true);
editor.commit();
}
@Override
protected void onSaveInstanceState (Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString(KEY_TO_ADDRESS, mToAddress);
savedInstanceState.putString(KEY_FROM_ADDRESS, mFromAddress);
savedInstanceState.putString(KEY_SUBJECT, mSubject);
savedInstanceState.putString(KEY_BODY, mBody);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
mToAddress = savedInstanceState.getString(KEY_TO_ADDRESS);
mFromAddress = savedInstanceState.getString(KEY_FROM_ADDRESS);
mSubject = savedInstanceState.getString(KEY_SUBJECT);
mBody = savedInstanceState.getString(KEY_BODY);
}
@Override
/**
* Deals with the result of the QR code scan
*/
public void onActivityResult(int requestCode, int resultCode, Intent intent)
{
// Get the result of the QR code scan
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (result != null)
{
String contents = result.getContents();
if (contents != null)
{
contents = contents.trim(); // Remove leading or trailing spaces
Log.i(TAG, "Found QRcode with the following contents: " + contents);
if (new AddressProcessor().validateAddress(contents))
{
mToAddress = contents;
mToAddressEditText.setTextSize((float) 12.5);
int[] colourValues = ColourCalculator.calculateColoursFromAddress(contents);
mColourR = colourValues[0];
mColourG = colourValues[1];
mColourB = colourValues[2];
getIntent().putExtra(EXTRA_COLOUR_R, colourValues[0]);
getIntent().putExtra(EXTRA_COLOUR_G, colourValues[1]);
getIntent().putExtra(EXTRA_COLOUR_B, colourValues[2]);
setColours();
populateEditTexts();
positionCursor();
}
else
{
Toast.makeText(getApplicationContext(), R.string.compose_toast_qr_address_invalid, Toast.LENGTH_LONG).show();
}
}
else
{
Log.i(TAG, "No QRcode found");
}
}
}
/**
* Sets up the basic layout for this activity
*/
private void setLayout()
{
setContentView(R.layout.activity_compose);
mToAddressEditText = (EditText) findViewById(R.id.compose_toAddress_EditText);
mFromAddressEditText = (EditText) findViewById(R.id.compose_fromAddress_EditText);
mSubjectEditText = (EditText) findViewById(R.id.compose_subject_EditText);
mBodyEditText = (EditText) findViewById(R.id.compose_body_EditText);
}
/**
* Executed when the user presses the 'Send' button
*/
private void sendMessage()
{
Log.i(TAG, "Send Button pressed");
String toAddress = mToAddressEditText.getText().toString();
String fromAddress = mFromAddressEditText.getText().toString();
// Check that the 'to address' entered by the user is either a valid Bitmessage address or a valid label from the address book
try
{
if (toAddress.equals(""))
{
Toast.makeText(getApplicationContext(), R.string.compose_toast_enter_to_address, Toast.LENGTH_LONG).show();
return;
}
AddressProcessor addProc = new AddressProcessor();
boolean toAddressValid = addProc.validateAddress(toAddress);
if (toAddressValid == false)
{
AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
ArrayList<AddressBookRecord> retrievedRecords = addBookProv.searchAddressBookRecords(AddressBookRecordsTable.COLUMN_LABEL, toAddress);
if (retrievedRecords.size() > 0)
{
toAddress = retrievedRecords.get(0).getAddress();
}
else
{
Toast.makeText(getApplicationContext(), R.string.compose_toast_to_address_invalid, Toast.LENGTH_LONG).show();
return;
}
}
}
catch (Exception e)
{
Log.e(TAG, "Exception occurred in ComposeActivity.sendMessage(). \n" +
"The exception messsage was: " + e.getMessage());
Toast.makeText(getApplicationContext(), R.string.compose_toast_to_address_error, Toast.LENGTH_LONG).show();
return;
}
// Check that the 'from address' entered by the user is either a valid Bitmessage address owned by the user or the label of one
// of those addresses
try
{
if (fromAddress.equals(""))
{
Toast.makeText(getApplicationContext(), R.string.compose_toast_enter_from_address, Toast.LENGTH_LONG).show();
return;
}
AddressProvider addProv = AddressProvider.get(getApplicationContext());
ArrayList<Address> retrievedAddresses = addProv.searchAddresses(AddressesTable.COLUMN_ADDRESS, fromAddress);
if (retrievedAddresses.size() == 0)
{
retrievedAddresses = addProv.searchAddresses(AddressesTable.COLUMN_LABEL, fromAddress);
if (retrievedAddresses.size() > 0)
{
fromAddress = retrievedAddresses.get(0).getAddress();
}
else
{
Toast.makeText(getApplicationContext(), R.string.compose_toast_from_address_invalid, Toast.LENGTH_LONG).show();
return;
}
}
}
catch (Exception e)
{
Log.e(TAG, "Exception occurred in ComposeActivity.sendMessage(). \n" +
"The exception messsage was: " + e.getMessage());
Toast.makeText(getApplicationContext(), R.string.compose_toast_from_address_error, Toast.LENGTH_LONG).show();
return;
}
// Check that the size of the message text is below the maximum permissible value
String subject = mSubjectEditText.getText().toString();
String body = mBodyEditText.getText().toString();
String combinedMessageText = subject.concat(body);
int messageTextSize = combinedMessageText.getBytes().length;
if (messageTextSize > MAXIMUM_MESSAGE_TEXT_SIZE)
{
Log.e(TAG, "The user attempted to send a message with a combined text (subject + body) size greater than the maximum value allowed. \n" +
"The size of the combined message text was " + messageTextSize + " bytes.");
Toast.makeText(getApplicationContext(), R.string.compose_toast_message_too_long, Toast.LENGTH_LONG).show();
return;
}
// --------------------------------- Send the message! -------------------------------------------
try
{
// Create a new Message object and populate its fields
Message messageToSend = new Message();
messageToSend.setBelongsToMe(true); // If I create and send a message then it 'belongs to me'. If I receive a message from someone else then it does not.
messageToSend.setTime(System.currentTimeMillis() / 1000);
messageToSend.setToAddress(toAddress);
messageToSend.setFromAddress(fromAddress);
messageToSend.setSubject(subject);
messageToSend.setBody(body);
messageToSend.setStatus(getBaseContext().getString(R.string.message_status_preparing_to_send));
// Save the Message to the database
MessageProvider msgProv = MessageProvider.get(getApplicationContext());
long messageId = msgProv.addMessage(messageToSend);
messageToSend.setId(messageId);
// Start the BackgroundService to complete the 'send message' task
Intent intent = new Intent(getBaseContext(), BackgroundService.class);
intent.putExtra(BackgroundService.UI_REQUEST, BackgroundService.UI_REQUEST_SEND_MESSAGE);
intent.putExtra(BackgroundService.MESSAGE_ID, messageId);
BackgroundService.sendWakefulWork(getBaseContext(), intent);
Toast.makeText(getApplicationContext(), R.string.compose_toast_sending_message, Toast.LENGTH_LONG).show();
mToAddressEditText.setText("");
mFromAddressEditText.setText("");
mSubjectEditText.setText("");
mBodyEditText.setText("");
// Open the Sent Activity
Intent i = new Intent(getBaseContext(), SentActivity.class);
startActivityForResult(i, 0);
}
catch (Exception e)
{
Log.e(TAG, "Exception occured in ComposeActivity while running mSendButton.onClick()");
e.printStackTrace();
Toast.makeText(getApplicationContext(), R.string.compose_toast_error, Toast.LENGTH_LONG).show();
return;
}
// ----------------------------------------------------------------------------------------------
}
/**
* Creates 'to address selection' and 'from address selection' dialogs
*/
private void createDialogs()
{
final Dialog toAddressSelectionDialog = new Dialog(ComposeActivity.this);
toAddressSelectionDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // This line has to be here so that it is not called repeatedly, which causes a crash
mToAddressEditText.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "To address edit text clicked");
// Get all AddressBookRecords from the application's database
AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
addBookProv = AddressBookRecordProvider.get(getApplicationContext());
mAddressBookRecords = addBookProv.getAllAddressBookRecords();
if (mAddressBookRecords.size() > 0)
{
// Open a dialog to select a 'to' address
LinearLayout dialogLayout = (LinearLayout) View.inflate(ComposeActivity.this, R.layout.dialog_compose_to_address_selection, null);
toAddressSelectionDialog.setContentView(dialogLayout);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(toAddressSelectionDialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
toAddressSelectionDialog.show();
toAddressSelectionDialog.getWindow().setAttributes(lp);
Button scanQRCodeButton = (Button) dialogLayout.findViewById(R.id.compose_dialog_to_address_selection_scan_qr_code_button);
scanQRCodeButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "To address selection dialog scan qr code button pressed");
toAddressSelectionDialog.dismiss();
IntentIntegrator integrator = new IntentIntegrator(ComposeActivity.this);
integrator.initiateScan(IntentIntegrator.QR_CODE_TYPES);
}
});
Button cancelButton = (Button) dialogLayout.findViewById(R.id.compose_dialog_to_address_selection_cancel_button);
cancelButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "To address selection dialog cancel button pressed");
toAddressSelectionDialog.dismiss();
}
});
mToAddressesAdapter = new AddressBookRecordAdapter(mAddressBookRecords);
// Sort the AddressBookRecords by label, in alphabetical order
Collections.sort(mAddressBookRecords);
mToAddressSelectionListView = new ListView(ComposeActivity.this);
mToAddressSelectionListView = (ListView) toAddressSelectionDialog.findViewById(android.R.id.list);
mToAddressSelectionListView.setAdapter(mToAddressesAdapter);
// Used to detect screen rotation while the to or from address selection dialogs are open
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(KEY_ON_PAUSE_CALLED, false);
editor.commit();
mToAddressSelectionListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id)
{
// Get the AddressBookRecord selected from the adapter
final AddressBookRecord listAddressBookRecord = (AddressBookRecord) parent.getItemAtPosition(position);
int r = listAddressBookRecord.getColourR();
int g = listAddressBookRecord.getColourG();
int b = listAddressBookRecord.getColourB();
// Check whether the activity has been paused while this dialog has been open (e.g. because of screen rotation)
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (prefs.getBoolean(KEY_ON_PAUSE_CALLED, false))
{
// If we just set the text of the edit text directly then the selection will not appear if the screen is rotated
// while the dialog is open
SharedPreferences.Editor editor = prefs.edit();
editor.putString(KEY_TO_ADDRESS_DIALOG_SELECTION, listAddressBookRecord.getLabel());
editor.commit();
Intent i = new Intent(getBaseContext(), ComposeActivity.class);
i.putExtra(EXTRA_TO_ADDRESS, listAddressBookRecord.getLabel());
i.putExtra(EXTRA_FROM_ADDRESS, mFromAddressEditText.getText().toString());
i.putExtra(EXTRA_SUBJECT, mSubjectEditText.getText().toString());
i.putExtra(EXTRA_BODY, mBodyEditText.getText().toString());
i.putExtra(EXTRA_COLOUR_R, r);
i.putExtra(EXTRA_COLOUR_G, g);
i.putExtra(EXTRA_COLOUR_B, b);
startActivityForResult(i, 0);
}
else
{
// If onPause() has not been called while this dialog has been open, we can just set the value of the edit text directly
mToAddressEditText.setText(listAddressBookRecord.getLabel());
}
// Set the colour member variables and extras for this activity to match those of this address book record
mColourR = r;
mColourG = g;
mColourB = b;
getIntent().putExtra(EXTRA_COLOUR_R, r);
getIntent().putExtra(EXTRA_COLOUR_G, g);
getIntent().putExtra(EXTRA_COLOUR_B, b);
setColours();
formatEditTexts();
positionCursor();
toAddressSelectionDialog.dismiss();
}
});
}
}
});
final Dialog fromAddressSelectionDialog = new Dialog(ComposeActivity.this);
fromAddressSelectionDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // This line has to be here so that it is not called repeatedly, which causes a crash
mFromAddressEditText.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "From address edit text clicked");
// Get all Addresses from the application's database
AddressProvider addProv = AddressProvider.get(getApplicationContext());
addProv = AddressProvider.get(getApplicationContext());
mAddresses = addProv.getAllAddresses();
if (mAddresses.size() > 0)
{
// Open a dialog to select a from address
LinearLayout dialogLayout = (LinearLayout) View.inflate(ComposeActivity.this, R.layout.dialog_compose_from_address_selection, null);
fromAddressSelectionDialog.setContentView(dialogLayout);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(fromAddressSelectionDialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
fromAddressSelectionDialog.show();
fromAddressSelectionDialog.getWindow().setAttributes(lp);
Button cancelButton = (Button) dialogLayout.findViewById(R.id.compose_dialog_from_address_selection_cancel_button);
cancelButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "From address selection dialog cancel button pressed");
fromAddressSelectionDialog.dismiss();
}
});
mFromAddressesAdapter = new AddressAdapter(mAddresses);
mFromAddressSelectionListView = new ListView(ComposeActivity.this);
mFromAddressSelectionListView = (ListView) fromAddressSelectionDialog.findViewById(android.R.id.list);
mFromAddressSelectionListView.setAdapter(mFromAddressesAdapter);
// Used to detect screen rotation while the to or from address selection dialogs are open
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(KEY_ON_PAUSE_CALLED, false);
editor.commit();
mFromAddressSelectionListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id)
{
// Get the Address selected from the adapter
final Address listAddress = (Address) parent.getItemAtPosition(position);
// Check whether the activity has been paused while this dialog has been open (e.g. because of screen rotation)
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (prefs.getBoolean(KEY_ON_PAUSE_CALLED, false))
{
// If we just set the text of the edit text directly then the selection will not appear if the screen is rotated
// while the dialog is open
SharedPreferences.Editor editor = prefs.edit();
editor.putString(KEY_FROM_ADDRESS_DIALOG_SELECTION, listAddress.getLabel());
editor.commit();
Intent i = new Intent(getBaseContext(), ComposeActivity.class);
i.putExtra(EXTRA_TO_ADDRESS, mToAddressEditText.getText().toString());
i.putExtra(EXTRA_FROM_ADDRESS, listAddress.getLabel());
i.putExtra(EXTRA_SUBJECT, mSubjectEditText.getText().toString());
i.putExtra(EXTRA_BODY, mBodyEditText.getText().toString());
startActivityForResult(i, 0);
}
else
{
// If onPause() has not been called while this dialog has been open, we can just set the value of the edit text directly
mFromAddressEditText.setText(listAddress.getLabel());
}
formatEditTexts();
positionCursor();
fromAddressSelectionDialog.dismiss();
}
});
}
}
});
}
/**
* Takes any extras bundled with the Intent that started this Activity
* and uses them.
*
* @param extras - The Intent
*/
private void useExtras(Intent intent)
{
Bundle extras = intent.getExtras();
if(intent.hasExtra(EXTRA_TO_ADDRESS))
{
mToAddress = extras.getString(EXTRA_TO_ADDRESS);
}
if(intent.hasExtra(EXTRA_FROM_ADDRESS))
{
mFromAddress = extras.getString(EXTRA_FROM_ADDRESS);
}
if(intent.hasExtra(EXTRA_SUBJECT))
{
mSubject = extras.getString(EXTRA_SUBJECT);
}
if(intent.hasExtra(EXTRA_BODY))
{
mBody = extras.getString(EXTRA_BODY);
}
if(intent.hasExtra(EXTRA_COLOUR_R))
{
mColourR = extras.getInt(EXTRA_COLOUR_R);
}
if(intent.hasExtra(EXTRA_COLOUR_G))
{
mColourG = extras.getInt(EXTRA_COLOUR_G);
}
if(intent.hasExtra(EXTRA_COLOUR_B))
{
mColourB = extras.getInt(EXTRA_COLOUR_B);
}
}
/**
* If we only have one address, auto-fill the 'from address'
* edit text
*/
private void autoSetFromAddress()
{
// If we only have one address, auto-fill the 'from' field
AddressProvider addProv = AddressProvider.get(getApplicationContext());
ArrayList<Address> myAddresses = addProv.getAllAddresses();
if (myAddresses.size() == 1)
{
mFromAddress = myAddresses.get(0).getLabel();
}
}
/**
* Sets the colours to use in this activity
*/
private void setColours()
{
// Set the colors inherited from the sent list view
int color = Color.argb(0, mColourR, mColourG, mColourB);
mToAddressEditText.setBackgroundColor(color);
mFromAddressEditText.setBackgroundColor(color);
mSubjectEditText.setBackgroundColor(color);
mBodyEditText.setBackgroundColor(color);
if (getIntent().hasExtra(EXTRA_COLOUR_R))
{
int backgroundColor = Color.argb(COMPOSE_COLOURS_ALPHA_VALUE, mColourR, mColourG, mColourB);
mMainView = (View) findViewById(R.id.compose_scrollView);
mMainView.setBackgroundColor(backgroundColor);
}
else
{
int backgroundColor = Color.argb(0, mColourR, mColourG, mColourB);
mMainView = (View) findViewById(R.id.compose_scrollView);
mMainView.setBackgroundColor(backgroundColor);
}
}
/**
* Populates the edit texts
*/
private void populateEditTexts()
{
mToAddressEditText.setText(mToAddress);
mFromAddressEditText.setText(mFromAddress);
mSubjectEditText.setText(mSubject);
mBodyEditText.setText(mBody);
// If we have stored values to use for the 'to' or 'from' address, use them
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String toAddressSelection = prefs.getString(KEY_TO_ADDRESS_DIALOG_SELECTION, "");
if (toAddressSelection.equals("") == false)
{
mToAddressEditText.setText(toAddressSelection);
}
String fromAddressSelection = prefs.getString(KEY_FROM_ADDRESS_DIALOG_SELECTION, "");
if (fromAddressSelection.equals("") == false)
{
mFromAddressEditText.setText(fromAddressSelection);
}
}
/**
* Substitutes labels for addresses where possible.
*/
private void useAddressLabels()
{
AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
AddressProvider addProv = AddressProvider.get(getApplicationContext());
// Attempt to use a label for the 'to address'
ArrayList<AddressBookRecord> addressBookRecords = addBookProv.searchAddressBookRecords(AddressBookRecordsTable.COLUMN_ADDRESS, mToAddressEditText.getText().toString());
if (addressBookRecords.size() == 1)
{
mToAddressEditText.setText(addressBookRecords.get(0).getLabel());
}
// Attempt to use a label for the 'from address'
ArrayList<Address> addresses = addProv.searchAddresses(AddressesTable.COLUMN_ADDRESS, mFromAddressEditText.getText().toString());
if (addresses.size() == 1)
{
mFromAddressEditText.setText(addresses.get(0).getLabel());
}
}
/**
* Formats the edit texts
*/
private void formatEditTexts()
{
AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
AddressProvider addProv = AddressProvider.get(getApplicationContext());
// Format the 'to address' edit text
ArrayList<AddressBookRecord> addressBookRecords = addBookProv.searchAddressBookRecords(AddressBookRecordsTable.COLUMN_LABEL, mToAddressEditText.getText().toString());
if (addressBookRecords.size() > 0)
{
mToAddressEditText.setTextSize(15);
}
// Format the 'from address' edit text
ArrayList<Address> addresses = addProv.searchAddresses(AddressesTable.COLUMN_LABEL, mFromAddressEditText.getText().toString());
if (addresses.size() > 0)
{
mFromAddressEditText.setTextSize(15);
}
}
/**
* Puts the cursor in the correct place.
*/
private void positionCursor()
{
if (mToAddressEditText.getText().toString().trim().equals(""))
{
mToAddressEditText.requestFocus();
}
else if (mFromAddressEditText.getText().toString().trim().equals(""))
{
mFromAddressEditText.requestFocus();
}
else if (mSubjectEditText.getText().toString().trim().equals(""))
{
mSubjectEditText.requestFocus();
}
else
{
mBodyEditText.requestFocus();
}
}
/** An inner class used for the listview in the to address selection dialog */
private class AddressBookRecordAdapter extends ArrayAdapter<AddressBookRecord>
{
public AddressBookRecordAdapter(ArrayList<AddressBookRecord> addressBookRecords)
{
super(getBaseContext(), android.R.layout.simple_list_item_1, addressBookRecords);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
// If we weren't given a view, inflate one
if (null == convertView)
{
convertView = getLayoutInflater().inflate(R.layout.list_item_address_book, parent, false);
}
// Configure the view for this Address Book Record
AddressBookRecord a = getItem(position);
// Set the label
mToAddressSelectionListItemLabelTextView = (TextView)convertView.findViewById(R.id.addressBook_list_item_label_textview);
if (a.getLabel() == null)
{
mToAddressSelectionListItemLabelTextView.setText("[No label]");
}
else
{
mToAddressSelectionListItemLabelTextView.setText(a.getLabel());
}
// Set the 'to' address
mToAddressSelectionListItemAddressTextView = (TextView)convertView.findViewById(R.id.addressBook_list_item_address_textview);
mToAddressSelectionListItemAddressTextView.setText(a.getAddress());
// Set the colour for this view
int r = a.getColourR();
int g = a.getColourG();
int b = a.getColourB();
convertView.setBackgroundColor(Color.argb(COMPOSE_COLOURS_ALPHA_VALUE, r, g, b));
int color = Color.argb(0, r, g, b);
mToAddressSelectionListItemLabelTextView.setBackgroundColor(color);
mToAddressSelectionListItemAddressTextView.setBackgroundColor(color);
return convertView;
}
}
/**
* An inner class used for the ListView in the 'from address' selection dialog
*/
private class AddressAdapter extends ArrayAdapter<Address>
{
public AddressAdapter(ArrayList<Address> addresses)
{
super(getBaseContext(), android.R.layout.simple_list_item_1, addresses);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
// If we weren't given a view, inflate one
if (null == convertView)
{
convertView = getLayoutInflater().inflate(R.layout.list_item_identities, parent, false);
}
// Configure the view for this Address
Address a = getItem(position);
mFromAddressSelectionListItemLabelTextView = (TextView)convertView.findViewById(R.id.identities_list_item_options_label_textview);
if (a.getLabel() == null)
{
mFromAddressSelectionListItemLabelTextView.setText("[No label]");
}
else
{
mFromAddressSelectionListItemLabelTextView.setText(a.getLabel());
}
mFromAddressSelectionListItemAddressTextView = (TextView)convertView.findViewById(R.id.identities_list_item_options_address_textview);
mFromAddressSelectionListItemAddressTextView.setText(a.getAddress());
// Set the colours for this view
int[] colourValues = ColourCalculator.calculateColoursFromAddress(a.getAddress());
convertView.setBackgroundColor(Color.argb(COMPOSE_COLOURS_ALPHA_VALUE, colourValues[0], colourValues[1], colourValues[2]));
int color = Color.argb(0, colourValues[0], colourValues[1], colourValues[2]);
mFromAddressSelectionListItemLabelTextView.setBackgroundColor(color);
mFromAddressSelectionListItemAddressTextView.setBackgroundColor(color);
return convertView;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.compose_activity_actions, menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (prefs.getBoolean(KEY_DATABASE_PASSPHRASE_SAVED, false) == false)
{
menu.removeItem(R.id.menu_item_lock);
}
return super.onPrepareOptionsMenu(menu);
}
@SuppressLint("InlinedApi")
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case R.id.action_send:
sendMessage();
break;
case R.id.menu_item_inbox:
Intent intent1 = new Intent(this, InboxActivity.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent1);
break;
case R.id.menu_item_sent:
Intent intent2 = new Intent(this, SentActivity.class);
intent2.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent2);
break;
case R.id.menu_item_compose:
// We are already here, so there's nothing to do
break;
case R.id.menu_item_identities:
Intent intent4 = new Intent(this, IdentitiesActivity.class);
intent4.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent4);
break;
case R.id.menu_item_addressBook:
Intent intent5 = new Intent(this, AddressBookActivity.class);
intent5.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent5);
break;
case R.id.menu_item_settings:
Intent intent6 = new Intent(this, SettingsActivity.class);
intent6.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent6);
break;
case R.id.menu_item_lock:
AppLockHandler.runLockRoutine(mCacheWordHandler);
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
@Override
protected void onStop()
{
super.onStop();
if (mCacheWordHandler != null)
{
mCacheWordHandler.disconnectFromService();
}
}
@SuppressLint("InlinedApi")
@Override
public void onCacheWordLocked()
{
// Redirect to the lock screen activity
Intent intent = new Intent(getBaseContext(), LockScreenActivity.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) // FLAG_ACTIVITY_CLEAR_TASK only exists in API 11 and later
{
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);// Clear the stack of activities
}
else
{
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
startActivity(intent);
}
@Override
public void onCacheWordOpened()
{
// Nothing to do here currently
}
@Override
public void onCacheWordUninitialized()
{
// Database encryption is currently not enabled by default, so there is nothing to do here
}
}