Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f5ba67dc authored by Daniel Nishi's avatar Daniel Nishi
Browse files

Fix a crash in Storage Settings.

This prevents a NullPtrException when the DonutView attempts to shrink
the percentage sign. By gracefully falling back when we don't understand
the percentage sign, we can avoid a crash.

Change-Id: I0b0770ce4b51eb30817dc556636f86476f4cd1bf
Fixes: 77653937
Test: Robotest -- screenshot attached
parent c2ec26b4
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.text.style.RelativeSizeSpan;
import android.util.AttributeSet;
import android.view.View;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;

@@ -173,19 +174,13 @@ public class DonutView extends View {
        final float centerY = getHeight() / 2;
        final float totalHeight = getTextHeight(mTextPaint) + getTextHeight(mBigNumberPaint);
        final float startY = centerY + totalHeight / 2;
        final float fontProportion = getResources().getDimension(
                R.dimen.storage_donut_view_percent_sign_size) /
                getResources().getDimension(R.dimen.storage_donut_view_percent_text_size);
        // Support from Android P
        final String localizedPercentSign = new DecimalFormatSymbols().getPercentString();
        final int startIndex = mPercentString.indexOf(localizedPercentSign);
        final int endIndex = startIndex + localizedPercentSign.length();

        // The first line y-coordinates start at (total height - all TextPaint height) / 2
        canvas.save();
        final Spannable percentStringSpan = new SpannableString(mPercentString);
        percentStringSpan.setSpan(new RelativeSizeSpan(fontProportion),
                startIndex, endIndex, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        final Spannable percentStringSpan =
                getPercentageStringSpannable(getResources(), mPercentString, localizedPercentSign);
        final StaticLayout percentStringLayout = new StaticLayout(percentStringSpan,
                mBigNumberPaint, getWidth(), Layout.Alignment.ALIGN_CENTER, 1, 0, false);
        canvas.translate(0, (getHeight() - totalHeight) / 2);
@@ -235,6 +230,30 @@ public class DonutView extends View {
        invalidate();
    }

    @VisibleForTesting
    static Spannable getPercentageStringSpannable(
            Resources resources, String percentString, String percentageSignString) {
        final float fontProportion =
                resources.getDimension(R.dimen.storage_donut_view_percent_sign_size)
                        / resources.getDimension(R.dimen.storage_donut_view_percent_text_size);
        final Spannable percentStringSpan = new SpannableString(percentString);
        int startIndex = percentString.indexOf(percentageSignString);
        int endIndex = startIndex + percentageSignString.length();

        // Fallback to no small string if we can't find the percentage sign.
        if (startIndex < 0) {
            startIndex = 0;
            endIndex = percentString.length();
        }

        percentStringSpan.setSpan(
                new RelativeSizeSpan(fontProportion),
                startIndex,
                endIndex,
                Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
        return percentStringSpan;
    }

    private float getTextHeight(TextPaint paint) {
        // Technically, this should be the cap height, but I can live with the descent - ascent.
        return paint.descent() - paint.ascent();
+19 −0
Original line number Diff line number Diff line
package com.android.settings.widget;

import android.content.Context;

import com.android.settings.testutils.SettingsRobolectricTestRunner;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;

@RunWith(SettingsRobolectricTestRunner.class)
public class DonutViewTest {
    @Test
    public void getPercentageStringSpannable_doesntCrashForMissingPercentage() {
        Context context = RuntimeEnvironment.application;

        DonutView.getPercentageStringSpannable(context.getResources(), "50%", "h");
    }
}