Bug 1258789 - Fix remaining rcurly issues by eliminating double curly bracket. r=grisha draft
authorMichael Comella <michael.l.comella@gmail.com>
Wed, 13 Apr 2016 11:03:40 -0700
changeset 350423 da676dcd95f836b6ef3ba4d8465ecaf74d1e15e8
parent 350422 6797dc55ab478d310f43a77badc83eabcedd0d6d
child 350424 57c8e8c764f5f8fc4f0eb3e2880d741904f34a0d
push id15341
push usermichael.l.comella@gmail.com
push dateWed, 13 Apr 2016 18:23:14 +0000
reviewersgrisha
bugs1258789
milestone48.0a1
Bug 1258789 - Fix remaining rcurly issues by eliminating double curly bracket. r=grisha It's an anti-pattern: https://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/ Mobile-relevant summary: * It creates new types, bloating our APK * It can cause memory leaks by keeping a reference to the containing class MozReview-Commit-ID: 4HQHgenOq92
mobile/android/base/java/org/mozilla/gecko/DownloadsIntegration.java
mobile/android/base/java/org/mozilla/gecko/db/LocalURLMetadata.java
mobile/android/base/java/org/mozilla/gecko/home/TopSitesPanel.java
mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
--- a/mobile/android/base/java/org/mozilla/gecko/DownloadsIntegration.java
+++ b/mobile/android/base/java/org/mozilla/gecko/DownloadsIntegration.java
@@ -10,16 +10,17 @@ import org.mozilla.gecko.AppConstants.Ve
 import org.mozilla.gecko.permissions.Permissions;
 import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.EventCallback;
 
 import java.io.File;
 import java.lang.IllegalArgumentException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import android.app.DownloadManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
@@ -27,22 +28,24 @@ import android.net.Uri;
 import android.os.Environment;
 import android.text.TextUtils;
 import android.util.Log;
 
 public class DownloadsIntegration implements NativeEventListener
 {
     private static final String LOGTAG = "GeckoDownloadsIntegration";
 
-    @SuppressWarnings("serial")
-    private static final List<String> UNKNOWN_MIME_TYPES = new ArrayList<String>(3) {{
-        add("unknown/unknown"); // This will be used as a default mime type for unknown files
-        add("application/unknown");
-        add("application/octet-stream"); // Github uses this for APK files
-    }};
+    private static final List<String> UNKNOWN_MIME_TYPES;
+    static {
+        final ArrayList<String> tempTypes = new ArrayList<>(3);
+        tempTypes.add("unknown/unknown"); // This will be used as a default mime type for unknown files
+        tempTypes.add("application/unknown");
+        tempTypes.add("application/octet-stream"); // Github uses this for APK files
+        UNKNOWN_MIME_TYPES = Collections.unmodifiableList(tempTypes);
+    }
 
     private static final String DOWNLOAD_REMOVE = "Download:Remove";
 
     private DownloadsIntegration() {
         EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener)this, DOWNLOAD_REMOVE);
     }
 
     private static DownloadsIntegration sInstance;
--- a/mobile/android/base/java/org/mozilla/gecko/db/LocalURLMetadata.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/LocalURLMetadata.java
@@ -12,17 +12,16 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
 import android.util.Log;
@@ -32,48 +31,45 @@ import android.util.LruCache;
 public class LocalURLMetadata implements URLMetadata {
     private static final String LOGTAG = "GeckoURLMetadata";
     private final Uri uriWithProfile;
 
     public LocalURLMetadata(String mProfile) {
         uriWithProfile = DBUtils.appendProfileWithDefault(mProfile, URLMetadataTable.CONTENT_URI);
     }
 
-    // This returns a list of columns in the table. It's used to simplify some loops for reading/writing data.
-    @SuppressWarnings("serial")
-    private final Set<String> getModel() {
-        return new HashSet<String>() {{
-            add(URLMetadataTable.URL_COLUMN);
-            add(URLMetadataTable.TILE_IMAGE_URL_COLUMN);
-            add(URLMetadataTable.TILE_COLOR_COLUMN);
-            add(URLMetadataTable.TOUCH_ICON_COLUMN);
-        }};
+    // A list of columns in the table. It's used to simplify some loops for reading/writing data.
+    private static final Set<String> COLUMNS;
+    static {
+        final HashSet<String> tempModel = new HashSet<>(4);
+        tempModel.add(URLMetadataTable.URL_COLUMN);
+        tempModel.add(URLMetadataTable.TILE_IMAGE_URL_COLUMN);
+        tempModel.add(URLMetadataTable.TILE_COLOR_COLUMN);
+        tempModel.add(URLMetadataTable.TOUCH_ICON_COLUMN);
+        COLUMNS = Collections.unmodifiableSet(tempModel);
     }
 
     // Store a cache of recent results. This number is chosen to match the max number of tiles on about:home
     private static final int CACHE_SIZE = 9;
     // Note: Members of this cache are unmodifiable.
     private final LruCache<String, Map<String, Object>> cache = new LruCache<String, Map<String, Object>>(CACHE_SIZE);
 
     /**
      * Converts a JSON object into a unmodifiable Map of known metadata properties.
      * Will throw away any properties that aren't stored in the database.
      *
      * Incoming data can include a list like: {touchIconList:{56:"http://x.com/56.png", 76:"http://x.com/76.png"}}.
      * This will then be filtered to find the most appropriate touchIcon, i.e. the closest icon size that is larger
      * than (or equal to) the preferred homescreen launcher icon size, which is then stored in the "touchIcon" property.
-     *
-     * @see #getModel() Returns the list of properties that will be stored in the database.
      */
     @Override
     public Map<String, Object> fromJSON(JSONObject obj) {
         Map<String, Object> data = new HashMap<String, Object>();
 
-        Set<String> model = getModel();
-        for (String key : model) {
+        for (String key : COLUMNS) {
             if (obj.has(key)) {
                 data.put(key, obj.optString(key));
             }
         }
 
 
         try {
             JSONObject icons;
@@ -103,20 +99,19 @@ public class LocalURLMetadata implements
     /**
      * Converts a Cursor into a unmodifiable Map of known metadata properties.
      * Will throw away any properties that aren't stored in the database.
      * Will also not iterate through multiple rows in the cursor.
      */
     private Map<String, Object> fromCursor(Cursor c) {
         Map<String, Object> data = new HashMap<String, Object>();
 
-        Set<String> model = getModel();
         String[] columns = c.getColumnNames();
         for (String column : columns) {
-            if (model.contains(column)) {
+            if (COLUMNS.contains(column)) {
                 try {
                     data.put(column, c.getString(c.getColumnIndexOrThrow(column)));
                 } catch (Exception ex) {
                     Log.i(LOGTAG, "Error getting data for " + column, ex);
                 }
             }
         }
 
@@ -216,18 +211,17 @@ public class LocalURLMetadata implements
     @Override
     public void save(final ContentResolver cr, final String url, final Map<String, Object> data) {
         ThreadUtils.assertNotOnUiThread();
         ThreadUtils.assertNotOnGeckoThread();
 
         try {
             ContentValues values = new ContentValues();
 
-            Set<String> model = getModel();
-            for (String key : model) {
+            for (String key : COLUMNS) {
                 if (data.containsKey(key)) {
                     values.put(key, (String) data.get(key));
                 }
             }
 
             if (values.size() == 0) {
                 return;
             }
--- a/mobile/android/base/java/org/mozilla/gecko/home/TopSitesPanel.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/TopSitesPanel.java
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.home;
 
 import static org.mozilla.gecko.db.URLMetadataTable.TILE_COLOR_COLUMN;
 import static org.mozilla.gecko.db.URLMetadataTable.TILE_IMAGE_URL_COLUMN;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
@@ -777,26 +778,28 @@ public class TopSitesPanel extends HomeF
 
             return new ThumbnailInfo(imageUrl, bgColor);
         }
     }
 
     /**
      * An AsyncTaskLoader to load the thumbnails from a cursor.
      */
-    @SuppressWarnings("serial")
     static class ThumbnailsLoader extends AsyncTaskLoader<Map<String, ThumbnailInfo>> {
         private final BrowserDB mDB;
         private Map<String, ThumbnailInfo> mThumbnailInfos;
         private final ArrayList<String> mUrls;
 
-        private static final ArrayList<String> COLUMNS = new ArrayList<String>() {{
-            add(TILE_IMAGE_URL_COLUMN);
-            add(TILE_COLOR_COLUMN);
-        }};
+        private static final List<String> COLUMNS;
+        static {
+            final ArrayList<String> tempColumns = new ArrayList<>(2);
+            tempColumns.add(TILE_IMAGE_URL_COLUMN);
+            tempColumns.add(TILE_COLOR_COLUMN);
+            COLUMNS = Collections.unmodifiableList(tempColumns);
+        }
 
         public ThumbnailsLoader(Context context, ArrayList<String> urls) {
             super(context);
             mUrls = urls;
             mDB = GeckoProfile.get(context).getDB();
         }
 
         @Override
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
@@ -87,16 +87,17 @@ import android.widget.AdapterView;
 import android.widget.EditText;
 import android.widget.LinearLayout;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 
 import org.json.JSONObject;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
 public class GeckoPreferences
 extends PreferenceActivity
@@ -176,16 +177,24 @@ OnSharedPreferenceChangeListener
 
     // Result code used when a locale preference changes.
     // Callers can recognize this code to refresh themselves to
     // accommodate a locale change.
     public static final int RESULT_CODE_LOCALE_DID_CHANGE = 7;
 
     private static final int REQUEST_CODE_TAB_QUEUE = 8;
 
+    private final Map<String, PrefHandler> HANDLERS;
+    {
+        final HashMap<String, PrefHandler> tempHandlers = new HashMap<>(2);
+        tempHandlers.put(ClearOnShutdownPref.PREF, new ClearOnShutdownPref());
+        tempHandlers.put(AndroidImportPreference.PREF_KEY, new AndroidImportPreference.Handler());
+        HANDLERS = Collections.unmodifiableMap(tempHandlers);
+    }
+
     private SwitchPreference tabQueuePreference;
 
     /**
      * Track the last locale so we know whether to redisplay.
      */
     private Locale lastLocale = Locale.getDefault();
     private boolean localeSwitchingIsEnabled;
 
@@ -683,18 +692,18 @@ OnSharedPreferenceChangeListener
                 } else if (PREFS_SCREEN_ADVANCED.equals(key) &&
                         !Restrictions.isAllowed(this, Restrictable.ADVANCED_SETTINGS)) {
                     preferences.removePreference(pref);
                     i--;
                     continue;
                 }
                 setupPreferences((PreferenceGroup) pref, prefs);
             } else {
-                if (handlers.containsKey(key)) {
-                    PrefHandler handler = handlers.get(key);
+                if (HANDLERS.containsKey(key)) {
+                    PrefHandler handler = HANDLERS.get(key);
                     if (!handler.setupPref(this, pref)) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 }
 
                 pref.setOnPreferenceChangeListener(this);
@@ -1140,22 +1149,16 @@ OnSharedPreferenceChangeListener
 
     public interface PrefHandler {
         // Allows the pref to do any initialization it needs. Return false to have the pref removed
         // from the prefs screen entirely.
         public boolean setupPref(Context context, Preference pref);
         public void onChange(Context context, Preference pref, Object newValue);
     }
 
-    @SuppressWarnings("serial")
-    private final Map<String, PrefHandler> handlers = new HashMap<String, PrefHandler>() {{
-        put(ClearOnShutdownPref.PREF, new ClearOnShutdownPref());
-        put(AndroidImportPreference.PREF_KEY, new AndroidImportPreference.Handler());
-    }};
-
     private void recordSettingChangeTelemetry(String prefName, Object newValue) {
         final String value;
         if (newValue instanceof Boolean) {
             value = (Boolean) newValue ? "1" : "0";
         } else if (prefName.equals(PREFS_HOMEPAGE)) {
             // Don't record the user's homepage preference.
             value = "*";
         } else {
@@ -1217,18 +1220,18 @@ OnSharedPreferenceChangeListener
         } else if (PREFS_TAB_QUEUE.equals(prefName)) {
             if ((Boolean) newValue && !TabQueueHelper.canDrawOverlays(this)) {
                 Intent promptIntent = new Intent(this, TabQueuePrompt.class);
                 startActivityForResult(promptIntent, REQUEST_CODE_TAB_QUEUE);
                 return false;
             }
         } else if (PREFS_NOTIFICATIONS_CONTENT.equals(prefName)) {
             FeedService.setup(this);
-        } else if (handlers.containsKey(prefName)) {
-            PrefHandler handler = handlers.get(prefName);
+        } else if (HANDLERS.containsKey(prefName)) {
+            PrefHandler handler = HANDLERS.get(prefName);
             handler.onChange(this, preference, newValue);
         }
 
         // Send Gecko-side pref changes to Gecko
         if (isGeckoPref(prefName)) {
             PrefsHelper.setPref(prefName, newValue, true /* flush */);
         }