package org.bitseal.activities;
import info.guardianproject.cacheword.CacheWordHandler;
import info.guardianproject.cacheword.ICacheWordSubscriber;
import java.util.ArrayList;
import org.bitseal.R;
import org.bitseal.core.QueueRecordProcessor;
import org.bitseal.data.Address;
import org.bitseal.data.AddressBookRecord;
import org.bitseal.data.Message;
import org.bitseal.data.Payload;
import org.bitseal.data.QueueRecord;
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.database.MessagesTable;
import org.bitseal.database.PayloadProvider;
import org.bitseal.database.QueueRecordProvider;
import org.bitseal.database.QueueRecordsTable;
import org.bitseal.services.AppLockHandler;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
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.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
/**
* The Activity class for the display of a single sent message.
*
* @author Jonathan Coe
*/
public class SentMessageActivity extends Activity implements ICacheWordSubscriber
{
public static final String EXTRA_MESSAGE_ID = "BITSEAL_MESSAGE_ID";
public static final String EXTRA_DESTINATION_ADDRESS = "sentMessageActivity.DESTINATION_ADDRESS";
public static final String EXTRA_COLOUR_R = "sentMessageActivity.COLOUR_R";
public static final String EXTRA_COLOUR_G = "sentMessageActivity.COLOUR_G";
public static final String EXTRA_COLOUR_B = "sentMessageActivity.COLOUR_B";
public static final String FLAG_SENT_MESSAGE_DELETED = "sentMessageDeleted";
private ArrayList<Message> mMessages;
private Message mMessage;
private long mMessageId;
private View mMainView;
private TextView mToAddressTextView;
private TextView mFromAddressTextView;
private TextView mStatusTextView;
private TextView mSubjectTextView;
private TextView mBodyTextView;
private Button mCopyButton;
private Button mDeleteButton;
private int mColourR;
private int mColourG;
private int mColourB;
private boolean mDestinationAddressInAddressBook;
private static final int SENT_MESSAGE_COLOURS_ALPHA_VALUE = 70;
/** 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 = "SENT_MESSAGE_ACTIVITY";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sent_message);
// 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();
}
Bundle b = getIntent().getExtras();
mMessageId = b.getLong(EXTRA_MESSAGE_ID);
mColourR = b.getInt(EXTRA_COLOUR_R);
mColourG = b.getInt(EXTRA_COLOUR_G);
mColourB = b.getInt(EXTRA_COLOUR_B);
// Retrieve the selected Message from the application database using the ID from the intent
MessageProvider msgProv = MessageProvider.get(getApplicationContext());
ArrayList<Message> retrievedMessages = msgProv.searchMessages(MessagesTable.COLUMN_ID, String.valueOf(mMessageId));
mMessage = retrievedMessages.get(0);
mToAddressTextView = (TextView) findViewById(R.id.sent_message_toAddress_textview);
mFromAddressTextView = (TextView) findViewById(R.id.sent_message_fromAddress_textview);
mStatusTextView = (TextView) findViewById(R.id.sent_message_status_textview);
mSubjectTextView = (TextView) findViewById(R.id.sent_message_subject_textview);
mBodyTextView = (TextView) findViewById(R.id.sent_message_body_textview);
String toAddressString = mMessage.getToAddress();
// Check if we have an entry for this address in our address book. If we do, substitute the label of that entry for the address.
AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
ArrayList<AddressBookRecord> retrievedAddressBookRecords = addBookProv.searchAddressBookRecords(AddressBookRecordsTable.COLUMN_ADDRESS, toAddressString);
if (retrievedAddressBookRecords.size() > 0)
{
mToAddressTextView.setText(retrievedAddressBookRecords.get(0).getLabel());
mToAddressTextView.setTextSize(15);
mDestinationAddressInAddressBook = true;
}
else
{
mToAddressTextView.setText(toAddressString);
}
String fromAddressString = mMessage.getFromAddress();
// Check if we can find the proper label for this address. If we can, then display it rather than the raw address.
AddressProvider addProv = AddressProvider.get(getApplicationContext());
ArrayList<Address> retrievedAddresses = addProv.searchAddresses(AddressesTable.COLUMN_ADDRESS, fromAddressString);
if (retrievedAddresses.size() > 0)
{
mFromAddressTextView.setText(retrievedAddresses.get(0).getLabel());
mFromAddressTextView.setTextSize(15);
}
else
{
mFromAddressTextView.setText(fromAddressString);
}
mStatusTextView.setText(mMessage.getStatus());
if (mMessage.getSubject() == null)
{
mSubjectTextView.setText("[No subject]");
}
else
{
mSubjectTextView.setText(mMessage.getSubject());
}
mBodyTextView.setText(mMessage.getBody());
mCopyButton = (Button) findViewById(R.id.sent_message_copy_button);
mCopyButton.setOnClickListener(new View.OnClickListener()
{
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onClick(View v)
{
Log.i(TAG, "Sent message copy button pressed");
int sdk = android.os.Build.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.HONEYCOMB)
{
android.text.ClipboardManager clipboard = (android.text.ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setText(mMessage.getBody());
}
else
{
android.content.ClipboardManager clipboard = (android.content.ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
android.content.ClipData clip = android.content.ClipData.newPlainText("COPIED_MESSAGE_TEXT", mMessage.getBody());
clipboard.setPrimaryClip(clip);
}
Toast.makeText(getApplicationContext(), R.string.sent_message_toast_message_copied, Toast.LENGTH_LONG).show();
}
});
mDeleteButton = (Button) findViewById(R.id.sent_message_delete_button);
mDeleteButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "Sent message delete button pressed");
// Open a dialog to confirm or cancel the deletion of the message
final Dialog deleteDialog = new Dialog(SentMessageActivity.this);
LinearLayout dialogLayout = (LinearLayout) View.inflate(SentMessageActivity.this, R.layout.dialog_sent_message_delete, null);
deleteDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
deleteDialog.setContentView(dialogLayout);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(deleteDialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
deleteDialog.show();
deleteDialog.getWindow().setAttributes(lp);
Button confirmButton = (Button) dialogLayout.findViewById(R.id.sent_message_delete_dialog_confirm_button);
confirmButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "Sent message delete dialog confirm button pressed");
// Delete this Message from the application's database
MessageProvider msgProv = MessageProvider.get(getApplicationContext());
mMessages = msgProv.getAllMessages();
mMessages.remove(mMessage);
msgProv.deleteMessage(mMessage);
// Find any QueueRecords and Payloads associated with this Message and delete them from the database
try
{
QueueRecordProvider queueProv = QueueRecordProvider.get(getApplicationContext());
ArrayList<QueueRecord> correspondingQueueRecords = queueProv.searchQueueRecords(QueueRecordsTable.COLUMN_OBJECT_0_ID, String.valueOf(mMessage.getId()));
for (QueueRecord q : correspondingQueueRecords)
{
// If this is a 'disseminate msg' QueueRecord, delete the msg and ack payloads
if (q.getTask().equals(QueueRecordProcessor.TASK_DISSEMINATE_MESSAGE))
{
PayloadProvider payProv = PayloadProvider.get(getApplicationContext());
Payload msgPayload = payProv.searchForSingleRecord(q.getObject1Id());
payProv.deletePayload(msgPayload);
// If there is an ack Payload stored for this msg, delete it as well
Payload ackPayload = payProv.searchForSingleRecord(mMessage.getAckPayloadId());
payProv.deletePayload(ackPayload);
}
// Delete this QueueRecord from the database
queueProv.deleteQueueRecord(q);
}
}
catch (Exception e)
{
Log.e(TAG, "Exception occurred in ComposeActivity.mDeleteButton.onClick(). The exception message was: \n" + e.getMessage());
}
// Set a flag so that the 'Sent' Activity can adjust its list view properly
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(FLAG_SENT_MESSAGE_DELETED, true);
editor.commit();
deleteDialog.dismiss();
Toast.makeText(getApplicationContext(), R.string.sent_message_toast_message_deleted, Toast.LENGTH_SHORT).show();
// Return to the 'Sent' Activity
Intent i = new Intent(getBaseContext(), SentActivity.class);
startActivityForResult(i, 0);
}
});
Button cancelButton = (Button) dialogLayout.findViewById(R.id.sent_message_delete_dialog_cancel_button);
cancelButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "Sent message delete dialog cancel button pressed");
deleteDialog.dismiss();
}
});
}
});
// Set the colors inherited from the sent list view
int color = Color.argb(0, mColourR, mColourG, mColourB);
mToAddressTextView.setBackgroundColor(color);
mFromAddressTextView.setBackgroundColor(color);
mStatusTextView.setBackgroundColor(color);
mSubjectTextView.setBackgroundColor(color);
mBodyTextView.setBackgroundColor(color);
int backgroundColor = Color.argb(SENT_MESSAGE_COLOURS_ALPHA_VALUE, mColourR, mColourG, mColourB);
mMainView = (View) findViewById(R.id.sent_message_scrollView);
mMainView.setBackgroundColor(backgroundColor);
}
@Override
protected void onSaveInstanceState (Bundle outState)
{
super.onSaveInstanceState(outState);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu items for use in the action bar
getMenuInflater().inflate(R.menu.sent_message_activity_actions, menu);
MenuItem addToAddressBookAction = menu.findItem(R.id.action_add_to_address_book);
if (mDestinationAddressInAddressBook)
{
addToAddressBookAction.setVisible(false);
}
return super.onCreateOptionsMenu(menu);
}
@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_add_to_address_book:
Intent i = new Intent(getBaseContext(), AddressBookActivity.class);
i.putExtra(EXTRA_DESTINATION_ADDRESS, mMessage.getToAddress());
startActivityForResult(i, 0);
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:
Intent intent3 = new Intent(this, ComposeActivity.class);
intent3.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent3);
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
}
}