More sync status messages

Added messaging for 2 more scenarios where auto-sync could be off:
- Global auto-sync is turned off
- Device is in airplane mode

Once user has dismissed the tip in conversation list,
continue to show 5 more times in the form of a toast every time they
do a manual refresh.

Bug 9825835

Change-Id: I33b1f2f0ac56ea7ec70f64c765447c05f6ed9b0e
diff --git a/res/layout/conversation_sync_disabled_tip_view.xml b/res/layout/conversation_sync_disabled_tip_view.xml
index ad19f7c..4cc3556 100644
--- a/res/layout/conversation_sync_disabled_tip_view.xml
+++ b/res/layout/conversation_sync_disabled_tip_view.xml
@@ -13,21 +13,33 @@
         android:background="@drawable/conversation_read_selector"
         android:orientation="horizontal" >
 
-        <TextView
-            android:id="@+id/text"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:layout_marginBottom="12dp"
-            android:layout_marginTop="12dp"
-            android:layout_marginLeft="16dp"
-            android:layout_marginStart="16dp"
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
             android:layout_weight="1"
-            android:duplicateParentState="true"
-            android:fontFamily="sans-serif-light"
-            android:text="@string/account_sync_off"
-            android:textColor="@color/teaser_main_text"
-            android:textSize="16sp" />
+            android:orientation="vertical"
+            android:padding="16dp" >
+
+            <TextView
+                android:id="@+id/text_line1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:duplicateParentState="true"
+                android:fontFamily="sans-serif-light"
+                android:textColor="@color/teaser_main_text"
+                android:textSize="16sp" />
+
+            <TextView
+                android:id="@+id/text_line2"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:duplicateParentState="true"
+                android:fontFamily="sans-serif-light"
+                android:text="@string/tap_to_enable_sync"
+                android:textColor="@color/teaser_main_text"
+                android:textSize="16sp" />
+
+        </LinearLayout>
 
         <View
             android:id="@+id/dismiss_separator"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d299cbe..9ac321f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -980,15 +980,18 @@
     <!-- Tip for letting user know that their device auto-sync setting
         is turned off, in case they are wondering why they are not
         receiving any new mail. [CHAR LIMIT=250] -->
-    <string name="auto_sync_off">Auto-sync is off.\nTurn on in Data usage settings.</string>
+    <string name="auto_sync_off">Auto-sync is off.</string>
 
     <!-- Tip for letting user know that their account level sync setting
         is turned off, in case they are wondering why they are not
         receiving any new mail. [CHAR LIMIT=250] -->
-    <string name="account_sync_off">Account sync is off.\nTurn on in Account settings.</string>
+    <string name="account_sync_off">Account sync is off.</string>
 
     <!-- Tip for letting user know that airplane mode is enabled on
         their device, in case they are wondering why they are not
         receiving any new mail. [CHAR LIMIT=250] -->
     <string name="airplane_mode_on">Airplane mode is on</string>
+
+    <!-- Tap to turn on sync in settings.  [CHAR LIMIT=250] -->
+    <string name="tap_to_enable_sync" translatable="false">Tap to turn sync on.</string>
 </resources>
diff --git a/src/com/android/mail/preferences/AccountPreferences.java b/src/com/android/mail/preferences/AccountPreferences.java
index 30fe7ba..7746330 100644
--- a/src/com/android/mail/preferences/AccountPreferences.java
+++ b/src/com/android/mail/preferences/AccountPreferences.java
@@ -120,7 +120,6 @@
                 PreferenceKeys.ACCOUNT_SYNC_OFF_DISMISSES, 0);
         if (value != 0) {
             getEditor().putInt(PreferenceKeys.ACCOUNT_SYNC_OFF_DISMISSES, 0).apply();
-            notifyBackupPreferenceChanged();
         }
     }
 
@@ -128,6 +127,5 @@
         final int value = getSharedPreferences().getInt(
                 PreferenceKeys.ACCOUNT_SYNC_OFF_DISMISSES, 0);
         getEditor().putInt(PreferenceKeys.ACCOUNT_SYNC_OFF_DISMISSES, value + 1).apply();
-        notifyBackupPreferenceChanged();
     }
 }
diff --git a/src/com/android/mail/preferences/MailPrefs.java b/src/com/android/mail/preferences/MailPrefs.java
index dd01586..1b46fc2 100644
--- a/src/com/android/mail/preferences/MailPrefs.java
+++ b/src/com/android/mail/preferences/MailPrefs.java
@@ -94,6 +94,9 @@
         public static final String EXPERIMENT_AP_PARALLAX_DIRECTION_ALTERNATIVE
                 = "ap-parallax-direction";
 
+        public static final String GLOBAL_SYNC_OFF_DISMISSES = "num-of-dismisses-auto-sync-off";
+        public static final String AIRPLANE_MODE_ON_DISMISSES = "num-of-dismisses-airplane-mode-on";
+
         public static final ImmutableSet<String> BACKUP_KEYS =
                 new ImmutableSet.Builder<String>()
                 .add(DEFAULT_REPLY_ALL)
@@ -426,4 +429,40 @@
         return sharedPreferences
                 .getBoolean(PreferenceKeys.EXPERIMENT_AP_PARALLAX_DIRECTION_ALTERNATIVE, false);
     }
+
+    public int getNumOfDismissesForAutoSyncOff() {
+        return getSharedPreferences().getInt(PreferenceKeys.GLOBAL_SYNC_OFF_DISMISSES, 0);
+    }
+
+    public void resetNumOfDismissesForAutoSyncOff() {
+        final int value = getSharedPreferences().getInt(
+                PreferenceKeys.GLOBAL_SYNC_OFF_DISMISSES, 0);
+        if (value != 0) {
+            getEditor().putInt(PreferenceKeys.GLOBAL_SYNC_OFF_DISMISSES, 0).apply();
+        }
+    }
+
+    public void incNumOfDismissesForAutoSyncOff() {
+        final int value = getSharedPreferences().getInt(
+                PreferenceKeys.GLOBAL_SYNC_OFF_DISMISSES, 0);
+        getEditor().putInt(PreferenceKeys.GLOBAL_SYNC_OFF_DISMISSES, value + 1).apply();
+    }
+
+    public int getNumOfDismissesForAirplaneModeOn() {
+        return getSharedPreferences().getInt(PreferenceKeys.AIRPLANE_MODE_ON_DISMISSES, 0);
+    }
+
+    public void resetNumOfDismissesForAirplaneModeOn() {
+        final int value = getSharedPreferences().getInt(
+                PreferenceKeys.AIRPLANE_MODE_ON_DISMISSES, 0);
+        if (value != 0) {
+            getEditor().putInt(PreferenceKeys.AIRPLANE_MODE_ON_DISMISSES, 0).apply();
+        }
+    }
+
+    public void incNumOfDismissesForAirplaneModeOn() {
+        final int value = getSharedPreferences().getInt(
+                PreferenceKeys.AIRPLANE_MODE_ON_DISMISSES, 0);
+        getEditor().putInt(PreferenceKeys.AIRPLANE_MODE_ON_DISMISSES, value + 1).apply();
+    }
 }
diff --git a/src/com/android/mail/ui/ConversationListView.java b/src/com/android/mail/ui/ConversationListView.java
index 7eda905..48e08b9 100644
--- a/src/com/android/mail/ui/ConversationListView.java
+++ b/src/com/android/mail/ui/ConversationListView.java
@@ -21,10 +21,14 @@
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.android.mail.ConversationListContext;
 import com.android.mail.R;
 import com.android.mail.analytics.Analytics;
+import com.android.mail.preferences.AccountPreferences;
+import com.android.mail.preferences.MailPrefs;
+import com.android.mail.ui.ConversationSyncDisabledTipView.ReasonSyncOff;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
@@ -45,6 +49,11 @@
     private static final int SYNC_STATUS_BAR_FADE_DURATION_IN_MILLIS = 150;
     private static final int SYNC_TRIGGER_SHRINK_DURATION_IN_MILLIS = 250;
 
+    // Max number of times we display the same sync turned off warning message in a toast.
+    // After we reach this max, and device/account still has sync off, we assume user has
+    // intentionally disabled sync and no longer warn.
+    private static final int MAX_NUM_OF_SYNC_TOASTS = 5;
+
     private static final String LOG_TAG = LogTag.getLogTag();
 
     private View mSyncTriggerBar;
@@ -80,6 +89,9 @@
 
     private ConversationListContext mConvListContext;
 
+    private final MailPrefs mMailPrefs;
+    private AccountPreferences mAccountPreferences;
+
     // Instantiated through view inflation
     @SuppressWarnings("unused")
     public ConversationListView(Context context) {
@@ -103,6 +115,8 @@
                 mSyncTriggerBar.setVisibility(GONE);
             }
         };
+
+        mMailPrefs = MailPrefs.get(context);
     }
 
     @Override
@@ -128,6 +142,7 @@
 
     protected void setConversationContext(ConversationListContext convListContext) {
         mConvListContext = convListContext;
+        mAccountPreferences = AccountPreferences.get(getContext(), convListContext.account.name);
     }
 
     @Override
@@ -303,6 +318,42 @@
             mSyncTriggerBar.setVisibility(GONE);
             mSyncProgressBar.setVisibility(VISIBLE);
             mSyncProgressBar.setAlpha(1f);
+
+            showToastIfSyncIsOff();
+        }
+    }
+
+    // If sync is turned off on this device or account, remind the user with a toast.
+    private void showToastIfSyncIsOff() {
+        final int reasonSyncOff = ConversationSyncDisabledTipView.calculateReasonSyncOff(
+                getContext(), mMailPrefs, mConvListContext.account, mAccountPreferences);
+        switch (reasonSyncOff) {
+            case ReasonSyncOff.AUTO_SYNC_OFF:
+                // TODO: make this an actionable toast, tapping on it goes to Settings
+                int num = mMailPrefs.getNumOfDismissesForAutoSyncOff();
+                if (num > 0 && num <= MAX_NUM_OF_SYNC_TOASTS) {
+                    Toast.makeText(getContext(), R.string.auto_sync_off, Toast.LENGTH_SHORT)
+                            .show();
+                    mMailPrefs.incNumOfDismissesForAutoSyncOff();
+                }
+                break;
+            case ReasonSyncOff.ACCOUNT_SYNC_OFF:
+                // TODO: make this an actionable toast, tapping on it goes to Settings
+                num = mAccountPreferences.getNumOfDismissesForAccountSyncOff();
+                if (num > 0 && num <= MAX_NUM_OF_SYNC_TOASTS) {
+                    Toast.makeText(getContext(), R.string.account_sync_off, Toast.LENGTH_SHORT)
+                            .show();
+                    mAccountPreferences.incNumOfDismissesForAccountSyncOff();
+                }
+                break;
+            case ReasonSyncOff.AIRPLANE_MODE_ON:
+                num = mMailPrefs.getNumOfDismissesForAirplaneModeOn();
+                if (num > 0 && num <= MAX_NUM_OF_SYNC_TOASTS) {
+                    Toast.makeText(getContext(), R.string.airplane_mode_on, Toast.LENGTH_SHORT)
+                            .show();
+                    mMailPrefs.incNumOfDismissesForAirplaneModeOn();
+                }
+                break;
         }
     }
 
diff --git a/src/com/android/mail/ui/ConversationSyncDisabledTipView.java b/src/com/android/mail/ui/ConversationSyncDisabledTipView.java
index 98824ed..122914a 100644
--- a/src/com/android/mail/ui/ConversationSyncDisabledTipView.java
+++ b/src/com/android/mail/ui/ConversationSyncDisabledTipView.java
@@ -20,7 +20,9 @@
 import android.app.LoaderManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
@@ -30,8 +32,11 @@
 import com.android.mail.R;
 import com.android.mail.browse.ConversationCursor;
 import com.android.mail.preferences.AccountPreferences;
+import com.android.mail.preferences.MailPrefs;
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Folder;
+import com.android.mail.utils.LogTag;
+import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
 
 /**
@@ -41,19 +46,38 @@
 public class ConversationSyncDisabledTipView extends FrameLayout
         implements ConversationSpecialItemView, SwipeableItemView {
 
+    private static final String LOG_TAG = LogTag.getLogTag();
+
     private static int sScrollSlop = 0;
     private static int sShrinkAnimationDuration;
 
     private Account mAccount = null;
+    private final MailPrefs mMailPrefs;
     private AccountPreferences mAccountPreferences;
     private AnimatedAdapter mAdapter;
 
     private View mSwipeableContent;
-    private TextView mText;
+    private TextView mText1;
+    private TextView mText2;
+    private final OnClickListener mAutoSyncOffTextClickedListener;
+    private final OnClickListener mAccountSyncOffTextClickedListener;
 
     private int mAnimatedHeight = -1;
     private boolean mAcceptUserTaps = false;
 
+    private int mReasonSyncOff = ReasonSyncOff.NONE;
+
+    public interface ReasonSyncOff {
+        // Background sync is enabled for current account, do not display this tip
+        public static final int NONE = 0;
+        // Global auto-sync (affects all apps and all accounts) is turned off
+        public static final int AUTO_SYNC_OFF = 1;
+        // Global auto-sync is on, but Gmail app level sync is disabled for this particular account
+        public static final int ACCOUNT_SYNC_OFF = 2;
+        // Auto-sync is enabled at both device and account level, but device is in airplane mode
+        public static final int AIRPLANE_MODE_ON = 3;
+    }
+
     public ConversationSyncDisabledTipView(final Context context) {
         this(context, null);
     }
@@ -73,6 +97,23 @@
             sShrinkAnimationDuration = resources.getInteger(
                     R.integer.shrink_animation_duration);
         }
+
+        mMailPrefs = MailPrefs.get(context);
+
+        mAutoSyncOffTextClickedListener = new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                openGlobalAutoSyncSettingDialog();
+            }
+        };
+
+        mAccountSyncOffTextClickedListener = new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // TODO: Link to account level settings instead of top level settings.
+                Utils.showSettings(getContext(), mAccount);
+            }
+        };
     }
 
     public void bindAccount(Account account) {
@@ -89,15 +130,8 @@
     protected void onFinishInflate() {
         mSwipeableContent = findViewById(R.id.swipeable_content);
 
-        mText = (TextView) findViewById(R.id.text);
-        mText.setText(R.string.account_sync_off);
-        mText.setClickable(true);
-        mText.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                Utils.showSettings(getContext(), mAccount);
-            }
-        });
+        mText1 = (TextView) findViewById(R.id.text_line1);
+        mText2 = (TextView) findViewById(R.id.text_line2);
 
         findViewById(R.id.dismiss_button).setOnClickListener(new OnClickListener() {
             @Override
@@ -117,19 +151,89 @@
         if (mAccount == null || mAccount.syncAuthority == null) {
             return false;
         }
-        boolean globalSyncAutomatically = ContentResolver.getMasterSyncAutomatically();
-        // Not sure why directly passing mAccount to ContentResolver doesn't just work.
-        android.accounts.Account account = new android.accounts.Account(
-                mAccount.name, mAccount.type);
-        if (globalSyncAutomatically &&
-                ContentResolver.getSyncAutomatically(account, mAccount.syncAuthority)) {
-            // Sync is on, clear the number of times users has dismissed this
-            // warning so that next time sync is off, warning gets displayed again.
-            mAccountPreferences.resetNumOfDismissesForAccountSyncOff();
-            return false;
+
+        // TODO: do not show this message for folders/labels that are not set to sync.
+        // We need a solution that works for both Gmail and Email.
+
+        setReasonSyncOff(calculateReasonSyncOff(
+                getContext(), mMailPrefs, mAccount, mAccountPreferences));
+
+        if (mReasonSyncOff != ReasonSyncOff.NONE) {
+            LogUtils.i(LOG_TAG, "Sync is off with reason %d", mReasonSyncOff);
+        }
+
+        switch (mReasonSyncOff) {
+            case ReasonSyncOff.AUTO_SYNC_OFF:
+                return (mMailPrefs.getNumOfDismissesForAutoSyncOff() == 0);
+            case ReasonSyncOff.ACCOUNT_SYNC_OFF:
+                return (mAccountPreferences.getNumOfDismissesForAccountSyncOff() == 0);
+            case ReasonSyncOff.AIRPLANE_MODE_ON:
+                return (mMailPrefs.getNumOfDismissesForAirplaneModeOn() == 0);
+            default:
+                return false;
+        }
+    }
+
+    public static int calculateReasonSyncOff(Context context, MailPrefs mailPrefs,
+            Account account, AccountPreferences accountPreferences) {
+        if (!ContentResolver.getMasterSyncAutomatically()) {
+            // Global sync is turned off
+            accountPreferences.resetNumOfDismissesForAccountSyncOff();
+            mailPrefs.resetNumOfDismissesForAirplaneModeOn();
+            return ReasonSyncOff.AUTO_SYNC_OFF;
         } else {
-            // Sync is off
-            return (mAccountPreferences.getNumOfDismissesForAccountSyncOff() == 0);
+            // Global sync is on, clear the number of times users has dismissed this
+            // warning so that next time global sync is off, warning gets displayed again.
+            mailPrefs.resetNumOfDismissesForAutoSyncOff();
+
+            // Now check for whether account level sync is on/off.
+            // Not sure why directly passing mAccount to ContentResolver doesn't just work.
+            android.accounts.Account acct = new android.accounts.Account(
+                    account.name, account.type);
+            if (!ContentResolver.getSyncAutomatically(acct, account.syncAuthority)) {
+                // Account level sync is off
+                mailPrefs.resetNumOfDismissesForAirplaneModeOn();
+                return ReasonSyncOff.ACCOUNT_SYNC_OFF;
+            } else {
+                // Account sync is on, clear the number of times users has dismissed this
+                // warning so that next time sync is off, warning gets displayed again.
+                accountPreferences.resetNumOfDismissesForAccountSyncOff();
+
+                // Now check for whether airplane mode is on
+                if (Utils.isAirplaneModeOn(context)) {
+                    return ReasonSyncOff.AIRPLANE_MODE_ON;
+                } else {
+                    mailPrefs.resetNumOfDismissesForAirplaneModeOn();
+                    return ReasonSyncOff.NONE;
+                }
+            }
+        }
+    }
+
+    private void setReasonSyncOff(int reason) {
+        if (mReasonSyncOff != reason) {
+            mReasonSyncOff = reason;
+            switch (mReasonSyncOff) {
+                case ReasonSyncOff.AUTO_SYNC_OFF:
+                    mText1.setText(R.string.auto_sync_off);
+                    mText2.setClickable(true);
+                    mText2.setVisibility(View.VISIBLE);
+                    mText2.setOnClickListener(mAutoSyncOffTextClickedListener);
+                    break;
+                case ReasonSyncOff.ACCOUNT_SYNC_OFF:
+                    mText1.setText(R.string.account_sync_off);
+                    mText2.setClickable(true);
+                    mText2.setVisibility(View.VISIBLE);
+                    mText2.setOnClickListener(mAccountSyncOffTextClickedListener);
+                    break;
+                case ReasonSyncOff.AIRPLANE_MODE_ON:
+                    mText1.setText(R.string.airplane_mode_on);
+                    mText2.setClickable(false);
+                    mText2.setVisibility(View.GONE);
+                    break;
+                default:
+                    // Doesn't matter what mText is since this view is not displayed
+            }
         }
     }
 
@@ -170,7 +274,17 @@
 
     @Override
     public void dismiss() {
-        mAccountPreferences.incNumOfDismissesForAccountSyncOff();
+        switch (mReasonSyncOff) {
+            case ReasonSyncOff.AUTO_SYNC_OFF:
+                mMailPrefs.incNumOfDismissesForAutoSyncOff();
+                break;
+            case ReasonSyncOff.ACCOUNT_SYNC_OFF:
+                mAccountPreferences.incNumOfDismissesForAccountSyncOff();
+                break;
+            case ReasonSyncOff.AIRPLANE_MODE_ON:
+                mMailPrefs.incNumOfDismissesForAirplaneModeOn();
+                break;
+        }
         startDestroyAnimation();
     }
 
@@ -219,4 +333,11 @@
             setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mAnimatedHeight);
         }
     }
+
+    private void openGlobalAutoSyncSettingDialog() {
+        final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
+        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+        intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] {mAccount.syncAuthority});
+        getContext().startActivity(intent);
+    }
 }
diff --git a/src/com/android/mail/utils/Utils.java b/src/com/android/mail/utils/Utils.java
index ef366d9..be57c51 100644
--- a/src/com/android/mail/utils/Utils.java
+++ b/src/com/android/mail/utils/Utils.java
@@ -38,6 +38,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.provider.Browser;
+import android.provider.Settings;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
@@ -1376,4 +1377,9 @@
             return context.getResources().getColor(R.color.list_background_color);
         }
     }
+
+    public static boolean isAirplaneModeOn(Context context) {
+        return Settings.System.getInt(context.getContentResolver(),
+                Settings.System.AIRPLANE_MODE_ON, 0) != 0;
+    }
 }