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.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.database.MessagesTable;
import org.bitseal.services.AppLockHandler;
import org.bitseal.services.NotificationsService;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Dialog;
import android.app.NotificationManager;
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 message.
*
* @author Jonathan Coe
*/
public class InboxMessageActivity extends Activity implements ICacheWordSubscriber
{
public static final String EXTRA_MESSAGE_ID = "inboxMessageActivity.MESSAGE_ID";
public static final String EXTRA_SENDER_ADDRESS = "inboxMessageActivity.SENDER_ADDRESS";
public static final String EXTRA_COLOUR_R = "inboxMessageActivity.COLOUR_R";
public static final String EXTRA_COLOUR_G = "inboxMessageActivity.COLOUR_G";
public static final String EXTRA_COLOUR_B = "inboxMessageActivity.COLOUR_B";
public static final String FLAG_INBOX_MESSAGE_DELETED = "inboxMessageDeleted";
private ArrayList<Message> mMessages;
private Message mMessage;
private long mMessageId;
private View mMainView;
private TextView mToAddressTextView;
private TextView mFromAddressTextView;
private TextView mSubjectTextView;
private TextView mBodyTextView;
private Button mReplyButton;
private Button mCopyButton;
private Button mDeleteButton;
private int mColourR;
private int mColourG;
private int mColourB;
private boolean mSenderInAddressBook;
private static final int INBOX_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 = "INBOX_MESSAGE_ACTIVITY";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inbox_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();
}
// Inflate the layout objects for this activity
mToAddressTextView = (TextView) findViewById(R.id.inbox_message_toAddress_textview);
mFromAddressTextView = (TextView) findViewById(R.id.inbox_message_fromAddress_textview);
mSubjectTextView = (TextView) findViewById(R.id.inbox_message_subject_textview);
mBodyTextView = (TextView) findViewById(R.id.inbox_message_body_textview);
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 Message object from the database
MessageProvider msgProv = MessageProvider.get(getApplicationContext());
ArrayList<Message> retrievedMessages = msgProv.searchMessages(MessagesTable.COLUMN_ID, String.valueOf(mMessageId));
mMessage = retrievedMessages.get(0);
// If this is the first time that this message has been opened, set the 'read' field
// of this Message to true and update the database to record that
if (mMessage.hasBeenRead() == false)
{
mMessage.setRead(true);
msgProv.updateMessage(mMessage);
// If the user is opening unread messages from the inbox then we can clear any 'new messages' notifications
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NotificationsService.getNewMessagesNotificationId());
// Set the 'new messages notification currently displayed' shared preference to false
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(NotificationsService.KEY_NEW_MESSAGES_NOTIFICATION_CURRENTLY_DISPLAYED, false);
editor.commit();
Log.i(TAG, "Recorded dismissal of new messages notification");
}
// Set the display data for this activity with the data from the Message
String toAddressString = mMessage.getToAddress();
// 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, toAddressString);
if (retrievedAddresses.size() > 0)
{
mToAddressTextView.setText(retrievedAddresses.get(0).getLabel());
mToAddressTextView.setTextSize(15);
}
else if (toAddressString.equals(getResources().getString(R.string.inbox_welcome_message_to_address)))
{
// If this is the welcome message, we want the "to" label to be full size, even though it isn't really a valid label
mToAddressTextView.setText(toAddressString);
mToAddressTextView.setTextSize(15);
}
else
{
mToAddressTextView.setText(toAddressString);
}
if (mMessage.getSubject() == null)
{
mSubjectTextView.setText("[No subject]");
}
else
{
mSubjectTextView.setText(mMessage.getSubject());
}
mBodyTextView.setText(mMessage.getBody());
mReplyButton = (Button) findViewById(R.id.inbox_message_reply_button);
mReplyButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "Inbox message reply button pressed");
Intent i = new Intent(getBaseContext(), ComposeActivity.class);
i.putExtra(ComposeActivity.EXTRA_TO_ADDRESS, mMessage.getFromAddress());
i.putExtra(ComposeActivity.EXTRA_FROM_ADDRESS, mMessage.getToAddress());
i.putExtra(ComposeActivity.EXTRA_SUBJECT, mMessage.getSubject());
i.putExtra(ComposeActivity.EXTRA_COLOUR_R, mColourR);
i.putExtra(ComposeActivity.EXTRA_COLOUR_G, mColourG);
i.putExtra(ComposeActivity.EXTRA_COLOUR_B, mColourB);
startActivityForResult(i, 0);
}
});
mCopyButton = (Button) findViewById(R.id.inbox_message_copy_button);
mCopyButton.setOnClickListener(new View.OnClickListener()
{
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onClick(View v)
{
Log.i(TAG, "Inbox 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.inbox_message_message_copied, Toast.LENGTH_LONG).show();
}
});
mDeleteButton = (Button) findViewById(R.id.inbox_message_delete_button);
mDeleteButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "Inbox message delete button pressed");
// Open a dialog to confirm or cancel the deletion of the message
final Dialog deleteDialog = new Dialog(InboxMessageActivity.this);
LinearLayout dialogLayout = (LinearLayout) View.inflate(InboxMessageActivity.this, R.layout.dialog_inbox_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.inbox_message_delete_dialog_confirm_button);
confirmButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "Inbox message delete dialog confirm button pressed");
MessageProvider msgProv = MessageProvider.get(getApplicationContext());
mMessages = msgProv.getAllMessages();
mMessages.remove(mMessage);
msgProv.deleteMessage(mMessage);
// Set a flag so that the 'Inbox' Activity can adjust its list view properly
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(FLAG_INBOX_MESSAGE_DELETED, true);
editor.commit();
deleteDialog.dismiss();
Toast.makeText(getApplicationContext(), R.string.inbox_message_message_deleted, Toast.LENGTH_SHORT).show();
Intent i = new Intent(getBaseContext(), InboxActivity.class);
startActivityForResult(i, 0);
}
});
Button cancelButton = (Button) dialogLayout.findViewById(R.id.inbox_message_delete_dialog_cancel_button);
cancelButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Log.i(TAG, "Inbox message delete dialog cancel button pressed");
deleteDialog.dismiss();
}
});
}
});
// Check whether we have an entry for this address in our address book.
String fromAddressString = mMessage.getFromAddress();
AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
ArrayList<AddressBookRecord> retrievedAddressBookRecords = addBookProv.searchAddressBookRecords(AddressBookRecordsTable.COLUMN_ADDRESS, fromAddressString);
if (retrievedAddressBookRecords.size() > 0)
{
// Substitute the label of that entry for the address.
mFromAddressTextView.setText(retrievedAddressBookRecords.get(0).getLabel());
mFromAddressTextView.setTextSize(15);
mSenderInAddressBook = true;
}
else
{
mFromAddressTextView.setText(fromAddressString);
}
// Set the colours inherited from the inbox list view
int color = Color.argb(0, mColourR, mColourG, mColourB);
mToAddressTextView.setBackgroundColor(color);
mFromAddressTextView.setBackgroundColor(color);
mSubjectTextView.setBackgroundColor(color);
mBodyTextView.setBackgroundColor(color);
int backgroundColor = Color.argb(INBOX_MESSAGE_COLOURS_ALPHA_VALUE, mColourR, mColourG, mColourB);
mMainView = (View) findViewById(R.id.inbox_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.inbox_message_activity_actions, menu);
MenuItem addToAddressBookAction = menu.findItem(R.id.action_add_to_address_book);
if (mSenderInAddressBook)
{
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_SENDER_ADDRESS, mMessage.getFromAddress());
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
}
}