am 01d8b440: Merge "Add extra checks to widget to make sure it clears when the account goes away" into jb-ub-mail-ur10

* commit '01d8b440ee0fa3531ba54d5152506f801a809a32':
  Add extra checks to widget to make sure it clears when the account goes away
diff --git a/src/com/android/bitmap/DecodeTask.java b/src/com/android/bitmap/DecodeTask.java
index 2210ec6..8fa11f1 100644
--- a/src/com/android/bitmap/DecodeTask.java
+++ b/src/com/android/bitmap/DecodeTask.java
@@ -54,6 +54,7 @@
     public interface Request {
         AssetFileDescriptor createFd() throws IOException;
         InputStream createInputStream() throws IOException;
+        boolean hasOrientationExif() throws IOException;
     }
 
     /**
@@ -130,20 +131,26 @@
             Trace.endSection();
 
             Trace.beginSection("get orientation");
-            if (fd != null) {
-                // Creating an input stream from the file descriptor makes it useless afterwards.
-                Trace.beginSection("create fd and stream");
-                final AssetFileDescriptor orientationFd = mKey.createFd();
-                in = orientationFd.createInputStream();
-                Trace.endSection();
-            }
-            final int orientation = Exif.getOrientation(in, byteSize);
-            if (fd != null) {
-                try {
-                    // Close the temporary file descriptor.
-                    in.close();
-                } catch (IOException ex) {
+            final int orientation;
+            if (mKey.hasOrientationExif()) {
+                if (fd != null) {
+                    // Creating an input stream from the file descriptor makes it useless
+                    // afterwards.
+                    Trace.beginSection("create fd and stream");
+                    final AssetFileDescriptor orientationFd = mKey.createFd();
+                    in = orientationFd.createInputStream();
+                    Trace.endSection();
                 }
+                orientation = Exif.getOrientation(in, byteSize);
+                if (fd != null) {
+                    try {
+                        // Close the temporary file descriptor.
+                        in.close();
+                    } catch (IOException ex) {
+                    }
+                }
+            } else {
+                orientation = 0;
             }
             final boolean isNotRotatedOr180 = orientation == 0 || orientation == 180;
             Trace.endSection();
diff --git a/src/com/android/mail/bitmap/ImageAttachmentRequest.java b/src/com/android/mail/bitmap/ImageAttachmentRequest.java
index 6c58772..b680db5 100644
--- a/src/com/android/mail/bitmap/ImageAttachmentRequest.java
+++ b/src/com/android/mail/bitmap/ImageAttachmentRequest.java
@@ -1,6 +1,5 @@
 package com.android.mail.bitmap;
 
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
@@ -25,6 +24,9 @@
     private final int mRendition;
     public final int mDestW;
 
+    private Uri mCachedUri;
+    private String mCachedMimeType;
+
     public ImageAttachmentRequest(final Context context, final String lookupUri,
             final int rendition, final int destW) {
         mContext = context;
@@ -78,26 +80,40 @@
 
     @Override
     public AssetFileDescriptor createFd() throws IOException {
-        AssetFileDescriptor result = null;
+        if (mCachedUri == null) {
+            cacheValues();
+        }
+        return mContext.getContentResolver().openAssetFileDescriptor(mCachedUri, "r");
+    }
+
+    private void cacheValues() throws IOException {
         Cursor cursor = null;
-        final ContentResolver cr = mContext.getContentResolver();
         try {
-            cursor = cr.query(Uri.parse(mLookupUri), UIProvider.ATTACHMENT_PROJECTION, null, null,
-                    null);
+            cursor = mContext.getContentResolver().query(Uri.parse(mLookupUri),
+                    UIProvider.ATTACHMENT_PROJECTION, null, null, null);
             if (cursor != null && cursor.moveToFirst()) {
                 final Attachment a = new Attachment(cursor);
-                result = cr.openAssetFileDescriptor(a.getUriForRendition(mRendition), "r");
+                mCachedUri = a.getUriForRendition(mRendition);
+                final String mimeType = a.getContentType();
+                mCachedMimeType = mimeType != null ? mimeType.toLowerCase() : null;
             }
         } finally {
             if (cursor != null) {
                 cursor.close();
             }
         }
-        return result;
     }
 
     @Override
     public InputStream createInputStream() throws IOException {
         return null;
     }
+
+    @Override
+    public boolean hasOrientationExif() throws IOException {
+        if (mCachedUri == null) {
+            cacheValues();
+        }
+        return mCachedMimeType == null || mCachedMimeType.equals("image/jpeg");
+    }
 }
diff --git a/src/com/android/mail/browse/ConversationCursor.java b/src/com/android/mail/browse/ConversationCursor.java
index 6c15e88..7a3ca0f 100644
--- a/src/com/android/mail/browse/ConversationCursor.java
+++ b/src/com/android/mail/browse/ConversationCursor.java
@@ -165,6 +165,8 @@
 
     private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
 
+    private final boolean mCachingEnabled;
+
     private void setCursor(UnderlyingCursorWrapper cursor) {
         // If we have an existing underlying cursor, make sure it's closed
         if (mUnderlyingCursor != null) {
@@ -193,6 +195,9 @@
         mName = name;
         qProjection = UIProvider.CONVERSATION_PROJECTION;
         mCursorObserver = new CursorObserver(new Handler(Looper.getMainLooper()));
+
+        // Disable caching on low memory devices
+        mCachingEnabled = !Utils.isLowRamDevice(activity);
     }
 
     /**
@@ -357,7 +362,7 @@
          * notes on thread safety.
          */
         private int mCachePos;
-        private boolean mCachingEnabled = true;
+        private boolean mCachingEnabled;
         private final NewCursorUpdateObserver mCursorUpdateObserver;
         private boolean mUpdateObserverRegistered = false;
 
@@ -370,9 +375,11 @@
 
         private boolean mCursorUpdated = false;
 
-        public UnderlyingCursorWrapper(Cursor result) {
+        public UnderlyingCursorWrapper(Cursor result, boolean cachingEnabled) {
             super(result);
 
+            mCachingEnabled = cachingEnabled;
+
             // Register the content observer immediately, as we want to make sure that we don't miss
             // any updates
             mCursorUpdateObserver =
@@ -639,7 +646,8 @@
                     uri, time, result.getCount());
         }
         System.gc();
-        return new UnderlyingCursorWrapper(result);
+
+        return new UnderlyingCursorWrapper(result, mCachingEnabled);
     }
 
     static boolean offUiThread() {
@@ -1946,6 +1954,15 @@
     }
 
     @Override
+    public Uri getNotificationUri() {
+        if (mUnderlyingCursor == null) {
+            return null;
+        } else {
+            return mUnderlyingCursor.getNotificationUri();
+        }
+    }
+
+    @Override
     public void setNotificationUri(ContentResolver cr, Uri uri) {
         throw new UnsupportedOperationException();
     }
diff --git a/src/com/android/mail/preferences/MailPrefs.java b/src/com/android/mail/preferences/MailPrefs.java
index f13e298..3791055 100644
--- a/src/com/android/mail/preferences/MailPrefs.java
+++ b/src/com/android/mail/preferences/MailPrefs.java
@@ -23,6 +23,7 @@
 import com.android.mail.providers.Account;
 import com.android.mail.providers.UIProvider;
 import com.android.mail.utils.LogUtils;
+import com.android.mail.utils.Utils;
 import com.android.mail.widget.BaseWidgetProvider;
 
 import com.google.common.collect.ImmutableSet;
@@ -40,7 +41,7 @@
  */
 public final class MailPrefs extends VersionedPrefs {
 
-    public static final boolean SHOW_EXPERIMENTAL_PREFS = false;
+    public static final boolean SHOW_EXPERIMENTAL_PREFS = true;
 
     private static final String PREFS_NAME = "UnifiedEmail";
 
@@ -396,6 +397,11 @@
     }
 
     public boolean getShowSenderImages() {
+        if (Utils.isLowRamDevice(getContext())) {
+            // Do not show sender images in conversation list on low memory devices since they are
+            // expensive to render.
+            return false;
+        }
         final SharedPreferences sharedPreferences = getSharedPreferences();
         return sharedPreferences.getBoolean(PreferenceKeys.SHOW_SENDER_IMAGES, true);
     }
@@ -406,6 +412,9 @@
     }
 
     public boolean getShowAttachmentPreviews() {
+        if (Utils.isLowRamDevice(getContext())) {
+            return false;
+        }
         final SharedPreferences sharedPreferences = getSharedPreferences();
         return sharedPreferences.getBoolean(PreferenceKeys.SHOW_ATTACHMENT_PREVIEWS, true);
     }
diff --git a/src/com/android/mail/ui/AbstractMailActivity.java b/src/com/android/mail/ui/AbstractMailActivity.java
index 33a7da2..43f3b23 100644
--- a/src/com/android/mail/ui/AbstractMailActivity.java
+++ b/src/com/android/mail/ui/AbstractMailActivity.java
@@ -39,7 +39,7 @@
 
     private final UiHandler mUiHandler = new UiHandler();
 
-    private static final boolean STRICT_MODE = false;
+    private static final boolean STRICT_MODE = true;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/src/com/android/mail/utils/LogUtils.java b/src/com/android/mail/utils/LogUtils.java
index 5d4f434..3203422 100644
--- a/src/com/android/mail/utils/LogUtils.java
+++ b/src/com/android/mail/utils/LogUtils.java
@@ -64,7 +64,7 @@
      * production releases.  This should be set to DEBUG for production releases, and VERBOSE for
      * internal builds.
      */
-    private static final int MAX_ENABLED_LOG_LEVEL = DEBUG;
+    private static final int MAX_ENABLED_LOG_LEVEL = VERBOSE;
 
     private static Boolean sDebugLoggingEnabledForTests = null;
 
diff --git a/src/com/android/mail/utils/Utils.java b/src/com/android/mail/utils/Utils.java
index de21172..c4927cd 100644
--- a/src/com/android/mail/utils/Utils.java
+++ b/src/com/android/mail/utils/Utils.java
@@ -22,6 +22,7 @@
 import com.google.android.mail.common.html.parser.HtmlTreeBuilder;
 import com.google.common.collect.Maps;
 
+import android.app.ActivityManager;
 import android.app.Fragment;
 import android.app.SearchManager;
 import android.content.Context;
@@ -146,6 +147,21 @@
     }
 
     /**
+     * @return Whether we are running on a low memory device.  This is used to disable certain
+     * memory intensive features in the app.
+     */
+    public static boolean isLowRamDevice(Context context) {
+        // TODO: use SDK_INT to check if device is KitKat or greater.
+        if (Build.VERSION.CODENAME.startsWith("K")) {
+            final ActivityManager am = (ActivityManager) context.getSystemService(
+                    Context.ACTIVITY_SERVICE);
+            return am.isLowRamDevice();
+        } else {
+            return false;
+        }
+    }
+
+    /**
      * Sets WebView in a restricted mode suitable for email use.
      *
      * @param webView The WebView to restrict