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

Commit 249e381a authored by Jacky Wang's avatar Jacky Wang
Browse files

[Catalyst] Fix MainSwitchBarPreference NPE when configuration changed

When activity is recreated (due to configuration is changed),
preference screen is created before SettingsActivity sets view layout
and results in NPE. As a workaround, save the states inside
MainSwitchBarPreference to fix the problem.

Bug: 332201912
Flag: EXEMPT library
Test: manual
Change-Id: I052cd0a521dac203a5f58963c550911e7a741e6f
parent fdbfa691
Loading
Loading
Loading
Loading
+71 −4
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.settings.widget

import android.content.Context
import android.os.Parcel
import android.os.Parcelable
import android.widget.CompoundButton
import android.widget.CompoundButton.OnCheckedChangeListener
import androidx.preference.TwoStatePreference
@@ -28,24 +30,30 @@ import com.android.settingslib.widget.MainSwitchBar
class MainSwitchBarPreference(context: Context, private val metadata: MainSwitchBarMetadata) :
    TwoStatePreference(context), OnCheckedChangeListener, MainSwitchBar.PreChangeListener {

    private val mainSwitchBar: MainSwitchBar = (context as SettingsActivity).switchBar
    // main switch bar might be null when configuration is just changed
    private val mainSwitchBar: MainSwitchBar?
        get() = (context as SettingsActivity).switchBar

    override fun setTitle(title: CharSequence?) {
        mainSwitchBar.setTitle(title)
        mainSwitchBar?.setTitle(title)
        super.setTitle(title)
    }

    override fun setSummary(summary: CharSequence?) {
        mainSwitchBar.setSummary(summary)
        mainSwitchBar?.setSummary(summary)
        super.setSummary(summary)
    }

    override fun setEnabled(enabled: Boolean) {
        mainSwitchBar.isEnabled = enabled
        mainSwitchBar?.isEnabled = enabled
        super.setEnabled(enabled)
    }

    // Preference.setVisible is final, we cannot override it
    fun updateVisibility() {
        // always make preference invisible, the UI visibility is reflected on MainSwitchBar
        isVisible = false
        val mainSwitchBar = mainSwitchBar ?: return
        if ((metadata as? PreferenceAvailabilityProvider)?.isAvailable(context) != false) {
            mainSwitchBar.show()
        } else {
@@ -54,6 +62,7 @@ class MainSwitchBarPreference(context: Context, private val metadata: MainSwitch
    }

    override fun setChecked(checked: Boolean) {
        val mainSwitchBar = mainSwitchBar ?: return
        // remove listener to update UI only
        mainSwitchBar.removeOnSwitchChangeListener(this)
        mainSwitchBar.isChecked = checked
@@ -62,6 +71,7 @@ class MainSwitchBarPreference(context: Context, private val metadata: MainSwitch

    override fun onAttached() {
        super.onAttached()
        val mainSwitchBar = mainSwitchBar!!
        mainSwitchBar.setPreChangeListener(this)
        mainSwitchBar.addOnSwitchChangeListener(this)
    }
@@ -76,8 +86,65 @@ class MainSwitchBarPreference(context: Context, private val metadata: MainSwitch
    }

    override fun onDetached() {
        val mainSwitchBar = mainSwitchBar!!
        mainSwitchBar.removeOnSwitchChangeListener(this)
        mainSwitchBar.setPreChangeListener(null)
        super.onDetached()
    }

    override fun onSaveInstanceState(): Parcelable =
        SavedState(super.onSaveInstanceState()!!).also {
            it.isEnabled = isEnabled
            it.title = title
            it.summary = summary
            it.mainSwitchBarState = mainSwitchBar?.onSaveInstanceState()
        }

    override fun onRestoreInstanceState(state: Parcelable?) {
        val savedState = state as SavedState
        super.onRestoreInstanceState(savedState.superState)
        isEnabled = savedState.isEnabled
        title = savedState.title
        summary = savedState.summary
        mainSwitchBar?.onRestoreInstanceState(savedState.mainSwitchBarState!!)
    }

    private class SavedState : BaseSavedState {
        var isEnabled: Boolean = false
        var title: CharSequence? = null
        var summary: CharSequence? = null
        var mainSwitchBarState: Parcelable? = null

        constructor(source: Parcel) : super(source) {
            isEnabled = source.readBoolean()
            title = source.readCharSequence()
            summary = source.readCharSequence()
            val stateClass = MainSwitchBar.SavedState::class.java
            mainSwitchBarState = source.readParcelable(stateClass.classLoader, stateClass)
        }

        constructor(superState: Parcelable) : super(superState)

        override fun writeToParcel(dest: Parcel, flags: Int) {
            super.writeToParcel(dest, flags)
            dest.writeBoolean(isEnabled)
            dest.writeCharSequence(title)
            dest.writeCharSequence(summary)
            dest.writeParcelable(mainSwitchBarState, flags)
        }

        companion object {
            @JvmField
            val CREATOR: Parcelable.Creator<SavedState> =
                object : Parcelable.Creator<SavedState> {
                    override fun createFromParcel(parcel: Parcel): SavedState {
                        return SavedState(parcel)
                    }

                    override fun newArray(size: Int): Array<SavedState?> {
                        return arrayOfNulls(size)
                    }
                }
        }
    }
}