diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index dc5437b27..1f7f8ab12 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -206,6 +206,10 @@
+
+
diff --git a/res/layout/message_view.xml b/res/layout/message_view.xml
index 3e236de66..acdd12be5 100644
--- a/res/layout/message_view.xml
+++ b/res/layout/message_view.xml
@@ -29,6 +29,7 @@
/>
This class has very limited feature set compared to {@link MessageView}, that is:
+ *
+ * - No action buttons (can't reply, forward or delete)
+ *
- No favorite starring.
+ *
- No navigating around (no older/newer buttons)
+ *
+ *
+ * TODO Test it!
+ */
+public class MessageFileView extends MessageViewBase {
+ /**
+ * URI to the email (i.e. *.eml files, and possibly *.msg files) file that's being
+ */
+ private Uri mFileEmailUri;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Intent intent = getIntent();
+ mFileEmailUri = intent.getData();
+
+ // TODO set title here: "Viewing XXX.eml".
+
+ // Hide all bottom buttons.
+ findViewById(R.id.button_panel).setVisibility(View.GONE);
+ findViewById(R.id.favorite).setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // Note: We don't have to close it even if an account has been deleted, unlike MessageView.
+ getFragment().openMessage(mFileEmailUri);
+ }
+
+ /** @return always -1, as there's no account associated with EML files. */
+ @Override
+ protected long getAccountId() {
+ return -1;
+ }
+
+ // Note EML files can have ICS (calendar invitation) files, but we don't treat them as
+ // invitations at this point. (Only exchange provider sets the FLAG_INCOMING_MEETING_INVITE
+ // flag.) At any rate, it'd be weird to respond to an invitation in an EML that might not
+ // be addressed to you...
+
+ // TODO Remove these callbacks below, when breaking down the fragment.
+ // MessageViewFragment for email files shouldn't have these callbacks.
+
+ @Override
+ public void onRespondedToInvite(int response) {
+ // EML files shouldn't have calender response buttons.
+ throw new RuntimeException();
+ }
+
+ @Override
+ public void onCalendarLinkClicked(long epochEventStartTime) {
+ // EML files shouldn't have the "View in calender" button.
+ throw new RuntimeException();
+ }
+
+ @Override
+ public void onMessageSetUnread() {
+ // EML files shouldn't have the "mark unread" button.
+ throw new RuntimeException();
+ }
+}
diff --git a/src/com/android/email/activity/MessageView.java b/src/com/android/email/activity/MessageView.java
index 215903c0f..40b2b77de 100644
--- a/src/com/android/email/activity/MessageView.java
+++ b/src/com/android/email/activity/MessageView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,28 +16,27 @@
package com.android.email.activity;
-import com.android.email.Controller;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.Utility;
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.provider.Browser;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.View.OnClickListener;
-// TODO Spin-off a new activity for EML files.
-
-public class MessageView extends Activity implements OnClickListener, MessageOrderManager.Callback,
- MessageViewFragment.Callback {
+/**
+ * Activity to show (non-EML) email messages.
+ *
+ * This activity shows regular email messages, which are not file-based. (i.e. not *.eml or *.msg)
+ *
+ * TODO Test it!
+ */
+public class MessageView extends MessageViewBase implements View.OnClickListener,
+ MessageOrderManager.Callback {
private static final String EXTRA_MESSAGE_ID = "com.android.email.MessageView_message_id";
private static final String EXTRA_MAILBOX_ID = "com.android.email.MessageView_mailbox_id";
/* package */ static final String EXTRA_DISABLE_REPLY =
@@ -46,28 +45,11 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
// for saveInstanceState()
private static final String STATE_MESSAGE_ID = "messageId";
- private ProgressDialog mFetchAttachmentProgressDialog;
- private MessageViewFragment mMessageViewFragment;
-
- /**
- * If set, URI to the email (i.e. *.eml files, and possibly *.msg files) file that's being
- * viewed.
- *
- * Use {@link #isViewingEmailFile()} to see if the activity is created for opening an EML file.
- *
- * TODO: We probably should split it into two different MessageViews, one for regular messages
- * and the other for for EML files (these two will share the same base MessageView class) to
- * eliminate the bunch of 'if {@link #isViewingEmailFile()}'s.
- * Do this after making it into a fragment.
- */
- private Uri mFileEmailUri;
private long mMessageId;
private long mMailboxId;
private MessageOrderManager mOrderManager;
- private Controller mController;
-
private View mMoveToNewer;
private View mMoveToOlder;
@@ -100,10 +82,6 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- setContentView(R.layout.message_view);
-
- mMessageViewFragment = (MessageViewFragment) findFragmentById(R.id.message_view_fragment);
- mMessageViewFragment.setCallback(this);
mMoveToNewer = findViewById(R.id.moveToNewer);
mMoveToOlder = findViewById(R.id.moveToOlder);
@@ -114,41 +92,21 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
findViewById(R.id.reply_all).setOnClickListener(this);
findViewById(R.id.delete).setOnClickListener(this);
- // TODO Turn it into a "managed" dialog?
- // Managed dialogs survive activity re-creation. (e.g. orientation change)
- mFetchAttachmentProgressDialog = new ProgressDialog(this);
- mFetchAttachmentProgressDialog.setIndeterminate(true);
- mFetchAttachmentProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
-
initFromIntent();
if (icicle != null) {
mMessageId = icicle.getLong(STATE_MESSAGE_ID, mMessageId);
}
-
- mController = Controller.getInstance(getApplication());
}
- /* package */ void initFromIntent() {
+ private void initFromIntent() {
Intent intent = getIntent();
- mFileEmailUri = intent.getData();
- if (mFileEmailUri == null) {
- mMessageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
- mMailboxId = intent.getLongExtra(EXTRA_MAILBOX_ID, -1);
- } else {
- mMessageId = -1;
- mMailboxId = -1;
- }
- mDisableReplyAndForward = intent.getBooleanExtra(EXTRA_DISABLE_REPLY, false)
- || isViewingEmailFile();
+ mMessageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
+ mMailboxId = intent.getLongExtra(EXTRA_MAILBOX_ID, -1);
+ mDisableReplyAndForward = intent.getBooleanExtra(EXTRA_DISABLE_REPLY, false);
if (mDisableReplyAndForward) {
findViewById(R.id.reply).setEnabled(false);
findViewById(R.id.reply_all).setEnabled(false);
}
- if (isViewingEmailFile()) {
- // TODO set title here: "Viewing XXX.eml".
- findViewById(R.id.delete).setEnabled(false);
- findViewById(R.id.favorite).setVisibility(View.GONE);
- }
}
@Override
@@ -163,15 +121,13 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
public void onResume() {
super.onResume();
- if (!isViewingEmailFile()) {
- // Exit immediately if the accounts list has changed (e.g. externally deleted)
- if (Email.getNotifyUiAccountsChanged()) {
- Welcome.actionStart(this);
- finish();
- return;
- }
- mOrderManager = new MessageOrderManager(this, mMailboxId, this);
+ // Exit immediately if the accounts list has changed (e.g. externally deleted)
+ if (Email.getNotifyUiAccountsChanged()) {
+ Welcome.actionStart(this);
+ finish();
+ return;
}
+ mOrderManager = new MessageOrderManager(this, mMailboxId, this);
messageChanged();
}
@@ -184,94 +140,32 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
super.onPause();
}
- /**
- * We override onDestroy to make sure that the WebView gets explicitly destroyed.
- * Otherwise it can leak native references.
- */
@Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- // TODO Make EML specific activity, and this will be gone.
- /**
- * @return true if viewing an email file. (i.e. *.eml files)
- */
- private boolean isViewingEmailFile() {
- return mFileEmailUri != null;
- }
-
- /**
- * {@inheritDoc}
- *
- * This is intended to mirror the operation of the original
- * (see android.webkit.CallbackProxy) with one addition of intent flags
- * "FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET". This improves behavior when sublaunching
- * other apps via embedded URI's.
- *
- * We also use this hook to catch "mailto:" links and handle them locally.
- */
- @Override
- public boolean onUrlInMessageClicked(String url) {
- // hijack mailto: uri's and handle locally
- if (url != null && url.toLowerCase().startsWith("mailto:")) {
- // If it's showing an EML file, there might be no accounts, but then MessageCompose
- // should close itself.
- long senderAccountId = isViewingEmailFile() ? -1 : mMessageViewFragment.getAccountId();
-
- // TODO if MessageCompose implements the account selector, we'll be able to just pass -1
- // as the account id.
- return MessageCompose.actionCompose(MessageView.this, url, senderAccountId);
- }
-
- // Handle most uri's via intent launch
- boolean result = false;
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- intent.addCategory(Intent.CATEGORY_BROWSABLE);
- intent.putExtra(Browser.EXTRA_APPLICATION_ID, getPackageName());
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- try {
- startActivity(intent);
- result = true;
- } catch (ActivityNotFoundException ex) {
- // No applications can handle it. Ignore.
- }
- return result;
+ protected long getAccountId() {
+ return getFragment().getAccountId();
}
private void onReply() {
- if (isViewingEmailFile()) {
- return;
- }
MessageCompose.actionReply(this, mMessageId, false);
finish();
}
private void onReplyAll() {
- if (isViewingEmailFile()) {
- return;
- }
MessageCompose.actionReply(this, mMessageId, true);
finish();
}
private void onForward() {
- if (isViewingEmailFile()) {
- return;
- }
MessageCompose.actionForward(this, mMessageId);
finish();
}
private void onDeleteMessage() {
- if (isViewingEmailFile()) {
- return;
- }
// the delete triggers mCursorObserver in MessageOrderManager.
// first move to older/newer before the actual delete
long messageIdToDelete = mMessageId;
boolean moved = moveToOlder() || moveToNewer();
- mController.deleteMessage(messageIdToDelete, -1);
+ getController().deleteMessage(messageIdToDelete, -1);
Utility.showToast(this,
getResources().getQuantityString(R.plurals.message_deleted_toast, 1));
if (!moved) {
@@ -283,9 +177,6 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
}
private boolean moveToOlder() {
- if (isViewingEmailFile()) {
- return false;
- }
if (mOrderManager != null && mOrderManager.moveToOlder()) {
mMessageId = mOrderManager.getCurrentMessageId();
messageChanged();
@@ -295,9 +186,6 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
}
private boolean moveToNewer() {
- if (isViewingEmailFile()) {
- return false;
- }
if (mOrderManager != null && mOrderManager.moveToNewer()) {
mMessageId = mOrderManager.getCurrentMessageId();
messageChanged();
@@ -357,7 +245,7 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
onForward();
break;
case R.id.mark_as_unread:
- mMessageViewFragment.onMarkMessageAsRead(false);
+ getFragment().onMarkMessageAsRead(false);
break;
default:
return false;
@@ -373,9 +261,6 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- if (isViewingEmailFile()) {
- return false; // No menu options for EML files.
- }
getMenuInflater().inflate(R.menu.message_view_option, menu);
if (mDisableReplyAndForward) {
menu.findItem(R.id.forward).setEnabled(false);
@@ -385,17 +270,15 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
return true;
}
- // TODO This method name and logic are both not too great. Make it cleaner.
- // - This method wouldn't be needed for the activity for EML.
- // - Change it to something like openMessage(long messageId).
+ /**
+ * Sync the current message.
+ * - Set message id to the fragment and the message order manager.
+ * - Update the navigation arrows.
+ */
private void messageChanged() {
- if (mFileEmailUri != null) {
- mMessageViewFragment.openMessage(mFileEmailUri);
- } else {
- mMessageViewFragment.openMessage(mMessageId);
- if (mOrderManager != null) {
- mOrderManager.moveTo(mMessageId);
- }
+ getFragment().openMessage(mMessageId);
+ if (mOrderManager != null) {
+ mOrderManager.moveTo(mMessageId);
}
updateNavigationArrows();
}
@@ -422,46 +305,6 @@ public class MessageView extends Activity implements OnClickListener, MessageOrd
updateNavigationArrows();
}
- @Override
- public void onLoadMessageStarted() {
- setProgressBarIndeterminateVisibility(true);
- }
-
- @Override
- public void onLoadMessageFinished() {
- setProgressBarIndeterminateVisibility(false);
- }
-
- @Override
- public void onLoadMessageError() {
- onLoadMessageFinished();
- }
-
- @Override
- public void onFetchAttachmentStarted(String attachmentName) {
- mFetchAttachmentProgressDialog.setMessage(
- getString(R.string.message_view_fetching_attachment_progress,
- attachmentName));
- mFetchAttachmentProgressDialog.show();
- setProgressBarIndeterminateVisibility(true);
- }
-
- @Override
- public void onFetchAttachmentFinished() {
- mFetchAttachmentProgressDialog.dismiss();
- setProgressBarIndeterminateVisibility(false);
- }
-
- @Override
- public void onFetchAttachmentError() {
- onFetchAttachmentFinished();
- }
-
- @Override
- public void onMessageNotExists() { // Probably meessage deleted.
- finish();
- }
-
@Override
public void onRespondedToInvite(int response) {
if (!moveToOlder()) {
diff --git a/src/com/android/email/activity/MessageViewBase.java b/src/com/android/email/activity/MessageViewBase.java
new file mode 100644
index 000000000..120db8d4b
--- /dev/null
+++ b/src/com/android/email/activity/MessageViewBase.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email.activity;
+
+import com.android.email.Controller;
+import com.android.email.R;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Browser;
+
+/**
+ * Base class for {@link MessageView} and {@link MessageFileView}.
+ */
+public abstract class MessageViewBase extends Activity implements MessageViewFragment.Callback {
+ private ProgressDialog mFetchAttachmentProgressDialog;
+ private MessageViewFragment mMessageViewFragment;
+ private Controller mController;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.message_view);
+
+ mMessageViewFragment = (MessageViewFragment) findFragmentById(R.id.message_view_fragment);
+ mMessageViewFragment.setCallback(this);
+
+ // TODO Turn it into a "managed" dialog?
+ // Managed dialogs survive activity re-creation. (e.g. orientation change)
+ mFetchAttachmentProgressDialog = new ProgressDialog(this);
+ mFetchAttachmentProgressDialog.setIndeterminate(true);
+ mFetchAttachmentProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+
+ mController = Controller.getInstance(getApplication());
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ protected Controller getController() {
+ return mController;
+ }
+
+ protected MessageViewFragment getFragment() {
+ return mMessageViewFragment;
+ }
+
+ /**
+ * @return the account id for the current message, or -1 if there's no account associated with.
+ * (i.e. when opening an EML file.)
+ */
+ protected abstract long getAccountId();
+
+ /**
+ * {@inheritDoc}
+ *
+ * This is intended to mirror the operation of the original
+ * (see android.webkit.CallbackProxy) with one addition of intent flags
+ * "FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET". This improves behavior when sublaunching
+ * other apps via embedded URI's.
+ *
+ * We also use this hook to catch "mailto:" links and handle them locally.
+ */
+ @Override
+ public boolean onUrlInMessageClicked(String url) {
+ // hijack mailto: uri's and handle locally
+ if (url != null && url.toLowerCase().startsWith("mailto:")) {
+ // If it's showing an EML file, we pass -1 as the account id, and MessageCompose
+ // uses the default account. If there's no accounts set up, MessageCompose will close
+ // itself.
+ long senderAccountId = getAccountId();
+
+ // TODO if MessageCompose implements the account selector, we'll be able to just pass -1
+ // as the account id.
+ return MessageCompose.actionCompose(MessageViewBase.this, url, senderAccountId);
+ }
+
+ // Handle most uri's via intent launch
+ boolean result = false;
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ intent.addCategory(Intent.CATEGORY_BROWSABLE);
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID, getPackageName());
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ try {
+ startActivity(intent);
+ result = true;
+ } catch (ActivityNotFoundException ex) {
+ // No applications can handle it. Ignore.
+ }
+ return result;
+ }
+
+ @Override
+ public void onLoadMessageStarted() {
+ setProgressBarIndeterminateVisibility(true);
+ }
+
+ @Override
+ public void onLoadMessageFinished() {
+ setProgressBarIndeterminateVisibility(false);
+ }
+
+ @Override
+ public void onLoadMessageError() {
+ onLoadMessageFinished();
+ }
+
+ @Override
+ public void onFetchAttachmentStarted(String attachmentName) {
+ mFetchAttachmentProgressDialog.setMessage(
+ getString(R.string.message_view_fetching_attachment_progress,
+ attachmentName));
+ mFetchAttachmentProgressDialog.show();
+ setProgressBarIndeterminateVisibility(true);
+ }
+
+ @Override
+ public void onFetchAttachmentFinished() {
+ mFetchAttachmentProgressDialog.dismiss();
+ setProgressBarIndeterminateVisibility(false);
+ }
+
+ @Override
+ public void onFetchAttachmentError() {
+ onFetchAttachmentFinished();
+ }
+
+ @Override
+ public void onMessageNotExists() { // Probably meessage deleted.
+ finish();
+ }
+
+ @Override
+ public abstract void onRespondedToInvite(int response);
+
+ @Override
+ public abstract void onCalendarLinkClicked(long epochEventStartTime);
+
+ @Override
+ public abstract void onMessageSetUnread();
+}