Merge "Import translations. DO NOT MERGE" into jb-ub-mail-ur10
diff --git a/res/layout/two_pane_activity.xml b/res/layout/two_pane_activity.xml
index a8c1004..fdafb3b 100644
--- a/res/layout/two_pane_activity.xml
+++ b/res/layout/two_pane_activity.xml
@@ -65,6 +65,11 @@
             android:layout_width="0dp"
             android:layout_height="match_parent" />
 
+        <FrameLayout
+            android:id="@+id/miscellaneous_pane"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" />
+
         <com.android.mail.ui.ActionableToastBar
             android:id="@+id/toast_bar"
             style="@style/ToastBarStyle" />
diff --git a/src/com/android/mail/analytics/AnalyticsUtils.java b/src/com/android/mail/analytics/AnalyticsUtils.java
index 0cc9e48..038a4bf 100644
--- a/src/com/android/mail/analytics/AnalyticsUtils.java
+++ b/src/com/android/mail/analytics/AnalyticsUtils.java
@@ -51,6 +51,8 @@
             s = "mark not important";
         } else if (id == R.id.mute) {
             s = "mute";
+        } else if (id == R.id.report_phishing) {
+            s = "report_phishing";
         } else if (id == R.id.report_spam) {
             s = "report_spam";
         } else if (id == R.id.mark_not_spam) {
@@ -99,6 +101,8 @@
             s = "send_message";
         } else if (id == R.id.discard) {
             s = "compose_discard_draft";
+        } else if (id == R.id.search) {
+            s = "search";
         } else {
             s = null;
         }
diff --git a/src/com/android/mail/browse/MessageAttachmentBar.java b/src/com/android/mail/browse/MessageAttachmentBar.java
index 18efa86..a66fd21 100644
--- a/src/com/android/mail/browse/MessageAttachmentBar.java
+++ b/src/com/android/mail/browse/MessageAttachmentBar.java
@@ -40,6 +40,7 @@
 import android.widget.TextView;
 
 import com.android.mail.R;
+import com.android.mail.analytics.Analytics;
 import com.android.mail.providers.Attachment;
 import com.android.mail.providers.UIProvider.AttachmentDestination;
 import com.android.mail.providers.UIProvider.AttachmentState;
@@ -173,15 +174,27 @@
             if (mAttachment.canSave()) {
                 mActionHandler.startDownloadingAttachment(AttachmentDestination.EXTERNAL);
                 mSaveClicked = true;
+
+                Analytics.getInstance().sendEvent(
+                        "save_attachment", Utils.normalizeMimeType(mAttachment.getContentType()),
+                        "attachment_bar", mAttachment.size);
             }
         } else if (res == R.id.download_again) {
             if (mAttachment.isPresentLocally()) {
                 mActionHandler.showDownloadingDialog();
                 mActionHandler.startRedownloadingAttachment(mAttachment);
+
+                Analytics.getInstance().sendEvent("redownload_attachment",
+                        Utils.normalizeMimeType(mAttachment.getContentType()), "attachment_bar",
+                        mAttachment.size);
             }
         } else if (res == R.id.cancel_attachment) {
             mActionHandler.cancelAttachment();
             mSaveClicked = false;
+
+            Analytics.getInstance().sendEvent(
+                    "cancel_attachment", Utils.normalizeMimeType(mAttachment.getContentType()),
+                    "attachment_bar", mAttachment.size);
         } else if (res == R.id.overflow) {
             // If no overflow items are visible, just bail out.
             // We shouldn't be able to get here anyhow since the overflow
@@ -207,6 +220,9 @@
             // button or cancel button or one of the
             // overflow items.
 
+            final String mime = Utils.normalizeMimeType(mAttachment.getContentType());
+            final String action;
+
             // If the mimetype is blocked, show the info dialog
             if (MimeType.isBlocked(mAttachment.getContentType())) {
                 AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
@@ -214,6 +230,9 @@
                 builder.setTitle(R.string.more_info_attachment)
                        .setMessage(dialogMessage)
                        .show();
+
+                action = "attachment_bar_blocked";
+
             }
             // If we can install, install.
             else if (MimeType.isInstallable(mAttachment.getContentType())) {
@@ -222,16 +241,22 @@
                 // workaround in
                 // UiProvider#getUiAttachmentsCursorForUIAttachments()
                 mActionHandler.showAttachment(AttachmentDestination.EXTERNAL);
+
+                action = "attachment_bar_install";
             }
             // If we can view or play with an on-device app,
             // view or play.
             else if (MimeType.isViewable(
                     getContext(), mAttachment.contentUri, mAttachment.getContentType())) {
                 mActionHandler.showAttachment(AttachmentDestination.CACHE);
+
+                action = "attachment_bar";
             }
             // If we can only preview the attachment, preview.
             else if (mAttachment.canPreview()) {
                 previewAttachment();
+
+                action = null;
             }
             // Otherwise, if we cannot do anything, show the info dialog.
             else {
@@ -240,6 +265,13 @@
                 builder.setTitle(R.string.more_info_attachment)
                        .setMessage(dialogMessage)
                        .show();
+
+                action = "attachment_bar_no_viewer";
+            }
+
+            if (action != null) {
+                Analytics.getInstance()
+                        .sendEvent("view_attachment", mime, action, mAttachment.size);
             }
         }
 
@@ -305,6 +337,10 @@
             final Intent previewIntent =
                     new Intent(Intent.ACTION_VIEW, mAttachment.previewIntentUri);
             getContext().startActivity(previewIntent);
+
+            Analytics.getInstance().sendEvent(
+                    "preview_attachment", Utils.normalizeMimeType(mAttachment.getContentType()),
+                    null, mAttachment.size);
         }
     }
 
diff --git a/src/com/android/mail/browse/MessageAttachmentTile.java b/src/com/android/mail/browse/MessageAttachmentTile.java
index 61e104b..90a87cc 100644
--- a/src/com/android/mail/browse/MessageAttachmentTile.java
+++ b/src/com/android/mail/browse/MessageAttachmentTile.java
@@ -32,6 +32,7 @@
 
 import com.android.ex.photo.util.ImageUtils;
 import com.android.mail.R;
+import com.android.mail.analytics.Analytics;
 import com.android.mail.photo.MailPhotoViewActivity;
 import com.android.mail.providers.Attachment;
 import com.android.mail.providers.UIProvider;
@@ -151,7 +152,12 @@
 
     @Override
     public void viewAttachment() {
-        if (ImageUtils.isImageMimeType(Utils.normalizeMimeType(mAttachment.getContentType()))) {
+        final String mime = Utils.normalizeMimeType(mAttachment.getContentType());
+
+        Analytics.getInstance()
+                .sendEvent("view_attachment", mime, "attachment_tile", mAttachment.size);
+
+        if (ImageUtils.isImageMimeType(mime)) {
             MailPhotoViewActivity
                     .startMailPhotoViewActivity(getContext(), mAttachmentsListUri, mPhotoIndex);
             return;
@@ -161,7 +167,7 @@
         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                 | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
         Utils.setIntentDataAndTypeAndNormalize(
-                intent, mAttachment.contentUri, mAttachment.getContentType());
+                intent, mAttachment.contentUri, mime);
         try {
             getContext().startActivity(intent);
         } catch (ActivityNotFoundException e) {
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
index bb3b0f4..e3558bd 100644
--- a/src/com/android/mail/compose/ComposeActivity.java
+++ b/src/com/android/mail/compose/ComposeActivity.java
@@ -447,6 +447,8 @@
             previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
             mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
             quotedText = savedState.getCharSequence(EXTRA_QUOTED_TEXT);
+
+            mExtraValues = savedState.getParcelable(EXTRA_VALUES);
         } else {
             account = obtainAccount(intent);
             action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
@@ -750,7 +752,7 @@
         if (!isChangingConfigurations()) {
             saveIfNeeded();
 
-            if (isFinishing() && !mPerformedSendOrDiscard) {
+            if (isFinishing() && !mPerformedSendOrDiscard && !isBlank()) {
                 // log saving upon backing out of activity. (we avoid logging every sendOrSave()
                 // because that method can be invoked many times in a single compose session.)
                 logSendOrSave(true /* save */);
@@ -869,6 +871,8 @@
         state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled());
         state.putParcelableArrayList(
                 EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews());
+
+        state.putParcelable(EXTRA_VALUES, mExtraValues);
     }
 
     private int getMode() {
@@ -1530,7 +1534,12 @@
                     final Uri uri = Uri.parse(uriString);
                     long size = 0;
                     try {
-                        size =  mAttachmentsView.addAttachment(mAccount, uri);
+                        final Attachment a = mAttachmentsView.generateLocalAttachment(uri);
+                        size = mAttachmentsView.addAttachment(mAccount, a);
+
+                        Analytics.getInstance().sendEvent("send_intent_attachment",
+                                Utils.normalizeMimeType(a.getContentType()), null, size);
+
                     } catch (AttachmentFailureException e) {
                         LogUtils.e(LOG_TAG, e, "Error adding attachment");
                         showAttachmentTooBigToast(e.getErrorRes());
@@ -1545,7 +1554,13 @@
                     ArrayList<Attachment> attachments = new ArrayList<Attachment>();
                     for (Parcelable uri : uris) {
                         try {
-                            attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri));
+                            final Attachment a = mAttachmentsView.generateLocalAttachment(
+                                    (Uri) uri);
+                            attachments.add(a);
+
+                            Analytics.getInstance().sendEvent("send_intent_attachment",
+                                    Utils.normalizeMimeType(a.getContentType()), null, a.size);
+
                         } catch (AttachmentFailureException e) {
                             LogUtils.e(LOG_TAG, e, "Error adding attachment");
                             String maxSize = AttachmentUtils.convertToHumanReadableSize(
@@ -1560,7 +1575,12 @@
                     final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
                     long size = 0;
                     try {
-                        size = mAttachmentsView.addAttachment(mAccount, uri);
+                        final Attachment a = mAttachmentsView.generateLocalAttachment(uri);
+                        size = mAttachmentsView.addAttachment(mAccount, a);
+
+                        Analytics.getInstance().sendEvent("send_intent_attachment",
+                                Utils.normalizeMimeType(a.getContentType()), null, size);
+
                     } catch (AttachmentFailureException e) {
                         LogUtils.e(LOG_TAG, e, "Error adding attachment");
                         showAttachmentTooBigToast(e.getErrorRes());
@@ -1572,6 +1592,9 @@
             if (totalSize > 0) {
                 mAttachmentsChanged = true;
                 updateSaveUi();
+
+                Analytics.getInstance().sendEvent("send_intent_with_attachments",
+                        Integer.toString(getAttachments().size()), null, totalSize);
             }
         }
     }
diff --git a/src/com/android/mail/providers/Folder.java b/src/com/android/mail/providers/Folder.java
index 0262e06..fb25905 100644
--- a/src/com/android/mail/providers/Folder.java
+++ b/src/com/android/mail/providers/Folder.java
@@ -719,9 +719,9 @@
     public String getTypeDescription() {
         final String desc;
         if (isType(FolderType.INBOX_SECTION)) {
-            desc = "inbox_section";
+            desc = "inbox_section:" + persistentId;
         } else if (isInbox()) {
-            desc = "inbox";
+            desc = "inbox:" + persistentId;
         } else if (isDraft()) {
             desc = "draft";
         } else if (isImportantOnly()) {
@@ -741,7 +741,7 @@
         } else if (isViewAll()) {
             desc = "all_mail";
         } else if (isProviderFolder()) {
-            desc = "(other)";
+            desc = "other:" + persistentId;
         } else {
             desc = "user_folder";
         }
diff --git a/src/com/android/mail/ui/ConversationSyncDisabledTipView.java b/src/com/android/mail/ui/ConversationSyncDisabledTipView.java
index 8593f14..f2782d3 100644
--- a/src/com/android/mail/ui/ConversationSyncDisabledTipView.java
+++ b/src/com/android/mail/ui/ConversationSyncDisabledTipView.java
@@ -226,7 +226,7 @@
                 accountPreferences.resetNumOfDismissesForAccountSyncOff();
 
                 // Now check for whether airplane mode is on
-                if (Utils.isAirplaneModeOn(context)) {
+                if (Utils.isAirplaneModeOnAndDeviceOffline(context)) {
                     return ReasonSyncOff.AIRPLANE_MODE_ON;
                 } else {
                     mailPrefs.resetNumOfDismissesForAirplaneModeOn();
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 1d44375..646ee52 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -18,6 +18,7 @@
 package com.android.mail.ui;
 
 import android.app.Fragment;
+import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.content.Intent;
 import android.net.Uri;
@@ -164,6 +165,12 @@
 
     @Override
     public void onViewModeChanged(int newMode) {
+        if (mMiscellaneousViewTransactionId >= 0) {
+            final FragmentManager fragmentManager = mActivity.getFragmentManager();
+            fragmentManager.popBackStackImmediate(mMiscellaneousViewTransactionId, 0 /* flags */);
+            mMiscellaneousViewTransactionId = -1;
+        }
+
         super.onViewModeChanged(newMode);
         if (newMode != ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION) {
             // Clear the wait fragment
@@ -174,7 +181,8 @@
         // untouched.
         // When the conversation list is made visible again, try to enable the CAB
         // mode if any conversations are selected.
-        if (newMode == ViewMode.CONVERSATION || newMode == ViewMode.CONVERSATION_LIST){
+        if (newMode == ViewMode.CONVERSATION || newMode == ViewMode.CONVERSATION_LIST
+                || ViewMode.isAdMode(newMode)) {
             enableOrDisableCab();
         }
     }
@@ -342,7 +350,7 @@
     @Override
     public boolean handleUpPress() {
         int mode = mViewMode.getMode();
-        if (mode == ViewMode.CONVERSATION) {
+        if (mode == ViewMode.CONVERSATION || mViewMode.isAdMode()) {
             handleBackPress();
         } else if (mode == ViewMode.SEARCH_RESULTS_CONVERSATION) {
             if (mLayout.isConversationListCollapsed()
@@ -388,7 +396,7 @@
         int mode = mViewMode.getMode();
         if (mode == ViewMode.SEARCH_RESULTS_LIST) {
             mActivity.finish();
-        } else if (mode == ViewMode.CONVERSATION) {
+        } else if (mode == ViewMode.CONVERSATION || mViewMode.isAdMode()) {
             // Go to conversation list.
             mViewMode.enterConversationListMode();
         } else if (mode == ViewMode.SEARCH_RESULTS_CONVERSATION) {
@@ -558,8 +566,17 @@
         return ListView.CHOICE_MODE_SINGLE;
     }
 
+    private int mMiscellaneousViewTransactionId = -1;
+
     @Override
     public void launchFragment(final Fragment fragment) {
-        // TODO(skennedy)
+        final int containerViewId = TwoPaneLayout.MISCELLANEOUS_VIEW_ID;
+
+        final FragmentManager fragmentManager = mActivity.getFragmentManager();
+        final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+        fragmentTransaction.addToBackStack(null);
+        fragmentTransaction.replace(containerViewId, fragment, TAG_CUSTOM_FRAGMENT);
+        mMiscellaneousViewTransactionId = fragmentTransaction.commitAllowingStateLoss();
+        fragmentManager.executePendingTransactions();
     }
 }
diff --git a/src/com/android/mail/ui/TwoPaneLayout.java b/src/com/android/mail/ui/TwoPaneLayout.java
index 2d00d28..f4276a3 100644
--- a/src/com/android/mail/ui/TwoPaneLayout.java
+++ b/src/com/android/mail/ui/TwoPaneLayout.java
@@ -91,10 +91,13 @@
 
     private DrawerLayout mDrawerLayout;
 
+    private View mMiscellaneousView;
     private View mConversationView;
     private View mFoldersView;
     private View mListView;
 
+    public static final int MISCELLANEOUS_VIEW_ID = R.id.miscellaneous_pane;
+
     private final Runnable mTransitionCompleteRunnable = new Runnable() {
         @Override
         public void run() {
@@ -158,6 +161,7 @@
         mListView = findViewById(R.id.conversation_list_pane);
         mListCopyView = (ConversationListCopy) findViewById(R.id.conversation_list_copy);
         mConversationView = findViewById(R.id.conversation_pane);
+        mMiscellaneousView = findViewById(MISCELLANEOUS_VIEW_ID);
 
         // all panes start GONE in initial UNKNOWN mode to avoid drawing misplaced panes
         mCurrentMode = ViewMode.UNKNOWN;
@@ -165,6 +169,7 @@
         mListView.setVisibility(GONE);
         mListCopyView.setVisibility(GONE);
         mConversationView.setVisibility(GONE);
+        mMiscellaneousView.setVisibility(GONE);
     }
 
     @VisibleForTesting
@@ -217,12 +222,14 @@
             LogUtils.i(LOG_TAG, "setting up new TPL, w=%d fw=%d cv=%d", parentWidth,
                     foldersWidth, convWidth);
 
+            setPaneWidth(mMiscellaneousView, convWidth);
             setPaneWidth(mConversationView, convWidth);
         }
 
         final int currListWidth = getPaneWidth(mListView);
         int listWidth = currListWidth;
         switch (mCurrentMode) {
+            case ViewMode.AD:
             case ViewMode.CONVERSATION:
             case ViewMode.SEARCH_RESULTS_CONVERSATION:
                 if (!mListCollapsible) {
@@ -263,6 +270,7 @@
         int convX = 0, listX = 0, foldersX = 0;
 
         switch (mCurrentMode) {
+            case ViewMode.AD:
             case ViewMode.CONVERSATION:
             case ViewMode.SEARCH_RESULTS_CONVERSATION: {
                 final int foldersW = getPaneWidth(mFoldersView);
@@ -330,6 +338,7 @@
         // a view intent.
         if (mPositionedMode == ViewMode.UNKNOWN) {
             mConversationView.setX(convX);
+            mMiscellaneousView.setX(convX);
             mListView.setX(listX);
             if (!isDrawerView(mFoldersView)) {
                 mFoldersView.setX(foldersX);
@@ -354,7 +363,12 @@
 
         useHardwareLayer(true);
 
-        mConversationView.animate().x(convX);
+        if (ViewMode.isAdMode(mCurrentMode)) {
+            mMiscellaneousView.animate().x(convX);
+        } else {
+            mConversationView.animate().x(convX);
+        }
+
         if (!isDrawerView(mFoldersView)) {
             mFoldersView.animate().x(foldersX);
         }
@@ -365,7 +379,8 @@
             .x(listX)
             .alpha(1.0f)
             .setListener(mPaneAnimationListener);
-        configureAnimations(mConversationView, mFoldersView, mListView, mListCopyView);
+        configureAnimations(mConversationView, mFoldersView, mListView, mListCopyView,
+                mMiscellaneousView);
     }
 
     private void configureAnimations(View... views) {
@@ -387,6 +402,7 @@
         mListView.setLayerType(layerType, null);
         mListCopyView.setLayerType(layerType, null);
         mConversationView.setLayerType(layerType, null);
+        mMiscellaneousView.setLayerType(layerType, null);
         if (useHardware) {
             // these buildLayer calls are safe because layout is the only way we get here
             // (i.e. these views must already be attached)
@@ -396,6 +412,7 @@
             mListView.buildLayer();
             mListCopyView.buildLayer();
             mConversationView.buildLayer();
+            mMiscellaneousView.buildLayer();
         }
     }
 
@@ -431,6 +448,11 @@
                 dispatchConversationListVisibilityChange(true);
 
                 break;
+            case ViewMode.AD:
+                dispatchConversationVisibilityChanged(false);
+                dispatchConversationListVisibilityChange(false);
+
+                break;
             default:
                 break;
         }
@@ -452,6 +474,7 @@
             case ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION:
             case ViewMode.SEARCH_RESULTS_LIST:
                 return totalWidth - computeFolderListWidth(totalWidth);
+            case ViewMode.AD:
             case ViewMode.CONVERSATION:
             case ViewMode.SEARCH_RESULTS_CONVERSATION:
                 return (int) (totalWidth * mConversationListWeight);
@@ -505,10 +528,6 @@
         return isDrawerView(pane) ? 0 : pane.getLayoutParams().width;
     }
 
-    public View getConversationView() {
-        return mConversationView;
-    }
-
     private boolean isDrawerView(View child) {
         return child != null && child.getParent() == mDrawerLayout;
     }
@@ -527,7 +546,14 @@
             mFoldersView.setVisibility(VISIBLE);
             mListView.setVisibility(VISIBLE);
             mListCopyView.setVisibility(VISIBLE);
+        }
+
+        if (ViewMode.isAdMode(newMode)) {
+            mMiscellaneousView.setVisibility(VISIBLE);
+            mConversationView.setVisibility(GONE);
+        } else {
             mConversationView.setVisibility(VISIBLE);
+            mMiscellaneousView.setVisibility(GONE);
         }
 
         // set up the drawer as appropriate for the configuration
@@ -585,6 +611,8 @@
                 s = "conv-list";
             } else if (pane == mConversationView) {
                 s = "conv-view";
+            } else if (pane == mMiscellaneousView) {
+                s = "misc-view";
             } else {
                 s = "???:" + pane;
             }
diff --git a/src/com/android/mail/utils/Utils.java b/src/com/android/mail/utils/Utils.java
index 620234a..a992dad 100644
--- a/src/com/android/mail/utils/Utils.java
+++ b/src/com/android/mail/utils/Utils.java
@@ -33,6 +33,8 @@
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.Typeface;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Build;
@@ -1394,8 +1396,17 @@
         }
     }
 
-    public static boolean isAirplaneModeOn(Context context) {
-        return Settings.System.getInt(context.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON, 0) != 0;
+    public static boolean isAirplaneModeOnAndDeviceOffline(Context context) {
+        final int airplaneMode = Settings.System.getInt(context.getContentResolver(),
+                Settings.System.AIRPLANE_MODE_ON, 0);
+        if (airplaneMode == 0) {
+            return false;
+        }
+        // Otherwise check if device is online, since it's possible to still use
+        // wifi when airplane mode is on
+        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
+        return (info == null || !info.isConnected());
     }
 }