chromium/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialSwitchWithText.java

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.components.browser_ui.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Checkable;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.annotation.StringRes;

import com.google.android.material.materialswitch.MaterialSwitch;

/**
 * Chrome workaround for material switch wrapped within a layout to scale down the size of the
 * switch, while maintaining the size of the text.
 *
 * <p>Note that this class has many limitations, so features that'd like to further customize the
 * behavior of the switch and text are highly recommended to implement their own TextView +
 * MaterialSwitch in the layout.
 *
 * <p>The limitations including but not limited to:
 *
 * <ul>
 *   Resource attribute defined in xml for {@link MaterialSwitch} are not forwarded to the wrapped
 *   switch (e.g. android:textAppearance)
 * </ul>
 *
 * <ul>
 *   The ability to perform long-press & drag to flip the switch is disabled, due to having the
 *   LinearLayout to be focusable to have a consistent behavior with MaterialSwitch in talkback.
 *   This behavior makes it similar to the behavior as a SwitchPreferenceCompat.
 * </ul>
 */
public class MaterialSwitchWithText extends LinearLayout implements Checkable, OnClickListener {
    private final MaterialSwitch mSwitch;
    private final TextView mTextView;

    public MaterialSwitchWithText(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MaterialSwitchWithText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        LayoutInflater.from(context).inflate(R.layout.material_switch_with_text, this);

        setOrientation(LinearLayout.HORIZONTAL);
        setGravity(Gravity.CENTER_VERTICAL);
        setMinimumHeight(getResources().getDimensionPixelSize(R.dimen.switch_with_text_min_height));
        setFocusable(true);

        mTextView = findViewById(R.id.switch_text);
        mSwitch = findViewById(R.id.switch_widget);

        setOnClickListener(this);

        TypedArray textStyles =
                getContext().obtainStyledAttributes(attrs, new int[] {android.R.attr.text});
        @StringRes int textId = textStyles.getResourceId(0, 0);
        if (textId != 0) mTextView.setText(textId);
        textStyles.recycle();
    }

    @Override
    public void setChecked(boolean checked) {
        mSwitch.setChecked(checked);
    }

    @Override
    public boolean isChecked() {
        return mSwitch.isChecked();
    }

    @Override
    public void toggle() {
        mSwitch.toggle();
    }

    @Override
    public void onClick(View view) {
        toggle();
    }

    /**
     * Set the OnCheckedChangeListener for the switch.
     *
     * @see CompoundButton#setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener).
     */
    public void setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener listener) {
        mSwitch.setOnCheckedChangeListener(listener);
    }
}