diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 3b2ea1a4bae..8a832a922b7 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -50,6 +50,9 @@ import android.content.res.TypedArray; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.hardware.fingerprint.FingerprintManager; import android.icu.text.MeasureFormat; import android.icu.text.RelativeDateTimeFormatter; @@ -1366,4 +1369,50 @@ public final class Utils extends com.android.settingslib.Utils { public static void setEditTextCursorPosition(EditText editText) { editText.setSelection(editText.getText().length()); } + + /** + * Sets the preference icon with a drawable that is scaled down to to avoid crashing Settings if + * it's too big. + */ + public static void setSafeIcon(Preference pref, Drawable icon) { + Drawable safeIcon = icon; + if (icon != null) { + safeIcon = getSafeDrawable(icon, 500, 500); + } + pref.setIcon(safeIcon); + } + + /** + * Gets a drawable with a limited size to avoid crashing Settings if it's too big. + * + * @param original original drawable, typically an app icon. + * @param maxWidth maximum width, in pixels. + * @param maxHeight maximum height, in pixels. + */ + public static Drawable getSafeDrawable(Drawable original, int maxWidth, int maxHeight) { + final int actualWidth = original.getMinimumWidth(); + final int actualHeight = original.getMinimumHeight(); + + if (actualWidth <= maxWidth && actualHeight <= maxHeight) { + return original; + } + + float scaleWidth = ((float) maxWidth) / actualWidth; + float scaleHeight = ((float) maxHeight) / actualHeight; + float scale = Math.min(scaleWidth, scaleHeight); + final int width = (int) (actualWidth * scale); + final int height = (int) (actualHeight * scale); + + final Bitmap bitmap; + if (original instanceof BitmapDrawable) { + bitmap = Bitmap.createScaledBitmap(((BitmapDrawable) original).getBitmap(), width, + height, false); + } else { + bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(bitmap); + original.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + original.draw(canvas); + } + return new BitmapDrawable(null, bitmap); + } } diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index a335c83b04c..fd48c39f5bd 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -485,7 +485,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements preference.setKey(componentName.flattenToString()); preference.setTitle(title); - preference.setIcon(icon); + Utils.setSafeIcon(preference, icon); final boolean serviceEnabled = accessibilityEnabled && enabledServices.contains(componentName); final String serviceState = serviceEnabled ? diff --git a/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java index d533d0f4993..91143b1d59d 100644 --- a/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java +++ b/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java @@ -26,6 +26,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.widget.GearPreference; import com.android.settingslib.core.AbstractPreferenceController; @@ -54,7 +55,7 @@ public abstract class DefaultAppPreferenceController extends AbstractPreferenceC CharSequence defaultAppLabel = getDefaultAppLabel(); if (!TextUtils.isEmpty(defaultAppLabel)) { preference.setSummary(defaultAppLabel); - preference.setIcon(getDefaultAppIcon()); + Utils.setSafeIcon(preference, getDefaultAppIcon()); } else { Log.d(TAG, "No default app"); preference.setSummary(R.string.app_list_preference_none); diff --git a/src/com/android/settings/widget/RadioButtonPickerFragment.java b/src/com/android/settings/widget/RadioButtonPickerFragment.java index 68547934c5c..d73631965bc 100644 --- a/src/com/android/settings/widget/RadioButtonPickerFragment.java +++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java @@ -17,6 +17,9 @@ package com.android.settings.widget; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.UserHandle; @@ -154,7 +157,7 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr public RadioButtonPreference bindPreference(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey) { pref.setTitle(info.loadLabel()); - pref.setIcon(info.loadIcon()); + Utils.setSafeIcon(pref, info.loadIcon()); pref.setKey(key); if (TextUtils.equals(defaultKey, key)) { pref.setChecked(true);