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
--- 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 */);
}