<commit_before>/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.material.badge;

import com.google.android.material.R;

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static com.google.android.material.badge.BadgeDrawable.TOP_END;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
import androidx.annotation.Dimension;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.PluralsRes;
import androidx.annotation.RestrictTo;
import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
import androidx.annotation.StyleableRes;
import androidx.annotation.XmlRes;
import com.google.android.material.badge.BadgeDrawable.BadgeGravity;
import com.google.android.material.drawable.DrawableUtils;
import com.google.android.material.internal.ThemeEnforcement;
import com.google.android.material.resources.MaterialResources;
import com.google.android.material.resources.TextAppearance;
import java.util.Locale;

/**
 * Provides a {@link Parcelable} implementation ({@link State}) used to ensure the state of {@code
 * BadgeDrawable} is saved and restored properly, and the default values of the states are correctly
 * loaded during every restoration.
 *
 * @hide
 */
@RestrictTo(LIBRARY_GROUP)
public final class BadgeState {
  /**
   * Maximum number of characters a badge supports displaying by default. It could be changed using
   * {@link BadgeDrawable#setMaxCharacterCount(int)}.
   */
  private static final int DEFAULT_MAX_BADGE_CHARACTER_COUNT = 4;

  private static final String BADGE_RESOURCE_TAG = "badge";

  private final State overridingState;
  private final State currentState = new State();

  final float badgeRadius;
  final float badgeWithTextRadius;
  final float badgeWidePadding;

  BadgeState(
      Context context,
      @XmlRes int badgeResId,
      @AttrRes int defStyleAttr,
      @StyleRes int defStyleRes,
      @Nullable State storedState) {
    if (storedState == null) {
      storedState = new State();
    }
    if (badgeResId != 0) {
      storedState.badgeResId = badgeResId;
    }

    TypedArray a = generateTypedArray(context, storedState.badgeResId, defStyleAttr, defStyleRes);

    Resources res = context.getResources();
    badgeRadius =
        a.getDimensionPixelSize(
            R.styleable.Badge_badgeRadius, res.getDimensionPixelSize(R.dimen.mtrl_badge_radius));
    badgeWidePadding =
        a.getDimensionPixelSize(
            R.styleable.Badge_badgeWidePadding,
            res.getDimensionPixelSize(R.dimen.mtrl_badge_long_text_horizontal_padding));
    badgeWithTextRadius =
        a.getDimensionPixelSize(
            R.styleable.Badge_badgeWithTextRadius,
            res.getDimensionPixelSize(R.dimen.mtrl_badge_with_text_radius));

    currentState.alpha = storedState.alpha == State.NOT_SET ? 255 : storedState.alpha;

    currentState.contentDescriptionNumberless =
        storedState.contentDescriptionNumberless == null
            ? context.getString(R.string.mtrl_badge_numberless_content_description)
            : storedState.contentDescriptionNumberless;

    currentState.contentDescriptionQuantityStrings =
        storedState.contentDescriptionQuantityStrings == 0
            ? R.plurals.mtrl_badge_content_description
            : storedState.contentDescriptionQuantityStrings;

    currentState.contentDescriptionExceedsMaxBadgeNumberRes =
        storedState.contentDescriptionExceedsMaxBadgeNumberRes == 0
            ? R.string.mtrl_exceed_max_badge_number_content_description
            : storedState.contentDescriptionExceedsMaxBadgeNumberRes;

    currentState.isVisible = storedState.isVisible == null || storedState.isVisible;

    currentState.maxCharacterCount =
        storedState.maxCharacterCount == State.NOT_SET
            ? a.getInt(R.styleable.Badge_maxCharacterCount, DEFAULT_MAX_BADGE_CHARACTER_COUNT)
            : storedState.maxCharacterCount;

    // Only set the badge number if it exists in the style.
    // Defaulting it to 0 means the badge will incorrectly show text when the user may want a
    // numberless badge.
    if (storedState.number != State.NOT_SET) {
      currentState.number = storedState.number;
    } else if (a.hasValue(R.styleable.Badge_number)) {
      currentState.number = a.getInt(R.styleable.Badge_number, 0);
    } else {
      currentState.number = State.BADGE_NUMBER_NONE;
    }

    currentState.backgroundColor =
        storedState.backgroundColor == null
            ? readColorFromAttributes(context, a, R.styleable.Badge_backgroundColor)
            : storedState.backgroundColor;

    // Only set the badge text color if this attribute has explicitly been set, otherwise use the
    // text color specified in the TextAppearance.
    if (storedState.badgeTextColor != null) {
      currentState.badgeTextColor = storedState.badgeTextColor;
    } else if (a.hasValue(R.styleable.Badge_badgeTextColor)) {
      currentState.badgeTextColor =
          readColorFromAttributes(context, a, R.styleable.Badge_badgeTextColor);
    } else {
      TextAppearance textAppearance =
          new TextAppearance(context, R.style.TextAppearance_MaterialComponents_Badge);
      currentState.badgeTextColor = textAppearance.getTextColor().getDefaultColor();
    }

    currentState.badgeGravity =
        storedState.badgeGravity == null
            ? a.getInt(R.styleable.Badge_badgeGravity, TOP_END)
            : storedState.badgeGravity;

    currentState.horizontalOffsetWithoutText =
        storedState.horizontalOffsetWithoutText == null
            ? a.getDimensionPixelOffset(R.styleable.Badge_horizontalOffset, 0)
            : storedState.horizontalOffsetWithoutText;

    currentState.verticalOffsetWithoutText =
        storedState.horizontalOffsetWithoutText == null
            ? a.getDimensionPixelOffset(R.styleable.Badge_verticalOffset, 0)
            : storedState.verticalOffsetWithoutText;

    // Set the offsets when the badge has text. Default to using the badge "dot" offsets
    // (horizontalOffsetWithoutText and verticalOffsetWithoutText) if there is no offsets defined
    // for badges with text.
    currentState.horizontalOffsetWithText =
        storedState.horizontalOffsetWithText == null
            ? a.getDimensionPixelOffset(
                R.styleable.Badge_horizontalOffsetWithText,
                currentState.horizontalOffsetWithoutText)
            : storedState.horizontalOffsetWithText;

    currentState.verticalOffsetWithText =
        storedState.verticalOffsetWithText == null
            ? a.getDimensionPixelOffset(
                R.styleable.Badge_verticalOffsetWithText, currentState.verticalOffsetWithoutText)
            : storedState.verticalOffsetWithText;

    currentState.additionalHorizontalOffset =
        storedState.additionalHorizontalOffset == null ? 0 : storedState.additionalHorizontalOffset;

    currentState.additionalVerticalOffset =
        storedState.additionalVerticalOffset == null ? 0 : storedState.additionalVerticalOffset;

    a.recycle();
<commit_msg>[Badging] Fix NPE in BadgeState<commit_after>/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.material.badge;

import com.google.android.material.R;

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static com.google.android.material.badge.BadgeDrawable.TOP_END;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
import androidx.annotation.Dimension;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.PluralsRes;
import androidx.annotation.RestrictTo;
import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
import androidx.annotation.StyleableRes;
import androidx.annotation.XmlRes;
import com.google.android.material.badge.BadgeDrawable.BadgeGravity;
import com.google.android.material.drawable.DrawableUtils;
import com.google.android.material.internal.ThemeEnforcement;
import com.google.android.material.resources.MaterialResources;
import com.google.android.material.resources.TextAppearance;
import java.util.Locale;

/**
 * Provides a {@link Parcelable} implementation ({@link State}) used to ensure the state of {@code
 * BadgeDrawable} is saved and restored properly, and the default values of the states are correctly
 * loaded during every restoration.
 *
 * @hide
 */
@RestrictTo(LIBRARY_GROUP)
public final class BadgeState {
  /**
   * Maximum number of characters a badge supports displaying by default. It could be changed using
   * {@link BadgeDrawable#setMaxCharacterCount(int)}.
   */
  private static final int DEFAULT_MAX_BADGE_CHARACTER_COUNT = 4;

  private static final String BADGE_RESOURCE_TAG = "badge";

  private final State overridingState;
  private final State currentState = new State();

  final float badgeRadius;
  final float badgeWithTextRadius;
  final float badgeWidePadding;

  BadgeState(
      Context context,
      @XmlRes int badgeResId,
      @AttrRes int defStyleAttr,
      @StyleRes int defStyleRes,
      @Nullable State storedState) {
    if (storedState == null) {
      storedState = new State();
    }
    if (badgeResId != 0) {
      storedState.badgeResId = badgeResId;
    }

    TypedArray a = generateTypedArray(context, storedState.badgeResId, defStyleAttr, defStyleRes);

    Resources res = context.getResources();
    badgeRadius =
        a.getDimensionPixelSize(
            R.styleable.Badge_badgeRadius, res.getDimensionPixelSize(R.dimen.mtrl_badge_radius));
    badgeWidePadding =
        a.getDimensionPixelSize(
            R.styleable.Badge_badgeWidePadding,
            res.getDimensionPixelSize(R.dimen.mtrl_badge_long_text_horizontal_padding));
    badgeWithTextRadius =
        a.getDimensionPixelSize(
            R.styleable.Badge_badgeWithTextRadius,
            res.getDimensionPixelSize(R.dimen.mtrl_badge_with_text_radius));

    currentState.alpha = storedState.alpha == State.NOT_SET ? 255 : storedState.alpha;

    currentState.contentDescriptionNumberless =
        storedState.contentDescriptionNumberless == null
            ? context.getString(R.string.mtrl_badge_numberless_content_description)
            : storedState.contentDescriptionNumberless;

    currentState.contentDescriptionQuantityStrings =
        storedState.contentDescriptionQuantityStrings == 0
            ? R.plurals.mtrl_badge_content_description
            : storedState.contentDescriptionQuantityStrings;

    currentState.contentDescriptionExceedsMaxBadgeNumberRes =
        storedState.contentDescriptionExceedsMaxBadgeNumberRes == 0
            ? R.string.mtrl_exceed_max_badge_number_content_description
            : storedState.contentDescriptionExceedsMaxBadgeNumberRes;

    currentState.isVisible = storedState.isVisible == null || storedState.isVisible;

    currentState.maxCharacterCount =
        storedState.maxCharacterCount == State.NOT_SET
            ? a.getInt(R.styleable.Badge_maxCharacterCount, DEFAULT_MAX_BADGE_CHARACTER_COUNT)
            : storedState.maxCharacterCount;

    // Only set the badge number if it exists in the style.
    // Defaulting it to 0 means the badge will incorrectly show text when the user may want a
    // numberless badge.
    if (storedState.number != State.NOT_SET) {
      currentState.number = storedState.number;
    } else if (a.hasValue(R.styleable.Badge_number)) {
      currentState.number = a.getInt(R.styleable.Badge_number, 0);
    } else {
      currentState.number = State.BADGE_NUMBER_NONE;
    }

    currentState.backgroundColor =
        storedState.backgroundColor == null
            ? readColorFromAttributes(context, a, R.styleable.Badge_backgroundColor)
            : storedState.backgroundColor;

    // Only set the badge text color if this attribute has explicitly been set, otherwise use the
    // text color specified in the TextAppearance.
    if (storedState.badgeTextColor != null) {
      currentState.badgeTextColor = storedState.badgeTextColor;
    } else if (a.hasValue(R.styleable.Badge_badgeTextColor)) {
      currentState.badgeTextColor =
          readColorFromAttributes(context, a, R.styleable.Badge_badgeTextColor);
    } else {
      TextAppearance textAppearance =
          new TextAppearance(context, R.style.TextAppearance_MaterialComponents_Badge);
      currentState.badgeTextColor = textAppearance.getTextColor().getDefaultColor();
    }

    currentState.badgeGravity =
        storedState.badgeGravity == null
            ? a.getInt(R.styleable.Badge_badgeGravity, TOP_END)
            : storedState.badgeGravity;

    currentState.horizontalOffsetWithoutText =
        storedState.horizontalOffsetWithoutText == null
            ? a.getDimensionPixelOffset(R.styleable.Badge_horizontalOffset, 0)
            : storedState.horizontalOffsetWithoutText;

    currentState.verticalOffsetWithoutText =
        storedState.verticalOffsetWithoutText == null
            ? a.getDimensionPixelOffset(R.styleable.Badge_verticalOffset, 0)
            : storedState.verticalOffsetWithoutText;

    // Set the offsets when the badge has text. Default to using the badge "dot" offsets
    // (horizontalOffsetWithoutText and verticalOffsetWithoutText) if there is no offsets defined
    // for badges with text.
    currentState.horizontalOffsetWithText =
        storedState.horizontalOffsetWithText == null
            ? a.getDimensionPixelOffset(
                R.styleable.Badge_horizontalOffsetWithText,
                currentState.horizontalOffsetWithoutText)
            : storedState.horizontalOffsetWithText;

    currentState.verticalOffsetWithText =
        storedState.verticalOffsetWithText == null
            ? a.getDimensionPixelOffset(
                R.styleable.Badge_verticalOffsetWithText, currentState.verticalOffsetWithoutText)
            : storedState.verticalOffsetWithText;

    currentState.additionalHorizontalOffset =
        storedState.additionalHorizontalOffset == null ? 0 : storedState.additionalHorizontalOffset;

    currentState.additionalVerticalOffset =
        storedState.additionalVerticalOffset == null ? 0 : storedState.additionalVerticalOffset;

    a.recycle();

{'fraction_non_alphanumeric': 0.07507545271629779, 'fraction_numerical': 0.002640845070422535, 'mean_word_length': 3.766257117171112, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5524635', 'n_tokens_mistral': 4363, 'n_tokens_neox': 4289, 'n_words': 954}