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

Commit e60bff2d authored by Jacky Wang's avatar Jacky Wang
Browse files

[Catalyst] Fix UI flicker when toggle Airplane mode

The UI flicker is because preference change is notified twice after
onActivityResult calls setBoolean: 1) Catalyst framework registers a
common listener on each preference's storage to update UI when
preference value is changed. 2) The PhoneStateListener in
AirplaneModeStorage. Remove the second listener fixes the issue.

NO_IFTTT=Catalyst only

Fix: 395774878
Flag: com.android.settings.flags.catalyst
Test: manual
Change-Id: I9f93faf1da87d52a82d9019361b17b4b500d79fe
parent 0972a9f3
Loading
Loading
Loading
Loading
+10 −41
Original line number Diff line number Diff line
@@ -21,11 +21,9 @@ import android.app.settings.SettingsEnums.ACTION_AIRPLANE_TOGGLE
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Looper
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
import android.telephony.PhoneStateListener
import android.telephony.TelephonyManager
import androidx.annotation.DrawableRes
import androidx.preference.Preference
@@ -37,12 +35,11 @@ import com.android.settings.metrics.PreferenceActionMetricsProvider
import com.android.settings.network.SatelliteRepository.Companion.isSatelliteOn
import com.android.settings.restriction.PreferenceRestrictionMixin
import com.android.settingslib.RestrictedSwitchPreference
import com.android.settingslib.datastore.AbstractKeyedDataObservable
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.KeyedObservableDelegate
import com.android.settingslib.datastore.SettingsGlobalStore
import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit
@@ -78,12 +75,7 @@ class AirplaneModePreference :
    override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
        ReadWritePermit.ALLOW

    override fun getWritePermit(
        context: Context,
        value: Boolean?,
        callingPid: Int,
        callingUid: Int,
    ) =
    override fun getWritePermit(context: Context, callingPid: Int, callingUid: Int) =
        when {
            isSatelliteOn(context) || isInEcmMode(context) -> ReadWritePermit.DISALLOW
            else -> ReadWritePermit.ALLOW
@@ -95,19 +87,15 @@ class AirplaneModePreference :
    override val preferenceActionMetrics: Int
        get() = ACTION_AIRPLANE_TOGGLE

    override fun storage(context: Context): KeyValueStore =
        AirplaneModeStorage(context, SettingsGlobalStore.get(context))
    override fun storage(context: Context): KeyValueStore = AirplaneModeStorage(context)

    @Suppress("DEPRECATION", "MissingPermission", "UNCHECKED_CAST")
    @Suppress("UNCHECKED_CAST")
    private class AirplaneModeStorage(
        private val context: Context,
        private val settingsStore: SettingsStore,
    ) : AbstractKeyedDataObservable<String>(), KeyValueStore {
        private var phoneStateListener: PhoneStateListener? = null
        private val settingsStore: SettingsStore = SettingsGlobalStore.get(context),
    ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {

        override fun contains(key: String) =
            settingsStore.contains(KEY) &&
                context.getSystemService(TelephonyManager::class.java) != null
        override fun contains(key: String) = settingsStore.contains(KEY)

        override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
            DEFAULT_VALUE as T
@@ -116,31 +104,12 @@ class AirplaneModePreference :
            (settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T

        override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
            if (value !is Boolean) return
            settingsStore.setBoolean(key, value)
            settingsStore.setValue(key, valueType, value)

            val intent = Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
            intent.putExtra("state", value)
            intent.putExtra("state", getBoolean(KEY)!!)
            context.sendBroadcastAsUser(intent, UserHandle.ALL)
        }

        override fun onFirstObserverAdded() {
            context.getSystemService(TelephonyManager::class.java)?.let {
                phoneStateListener =
                    object : PhoneStateListener(Looper.getMainLooper()) {
                        override fun onRadioPowerStateChanged(state: Int) {
                            notifyChange(KEY, PreferenceChangeReason.VALUE)
                        }
                    }
                it.listen(phoneStateListener, PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED)
            }
        }

        override fun onLastObserverRemoved() {
            context
                .getSystemService(TelephonyManager::class.java)
                ?.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE)
        }
    }

    override fun onCreate(context: PreferenceLifecycleContext) {
@@ -198,7 +167,7 @@ class AirplaneModePreference :
        const val DEFAULT_VALUE = false
        const val REQUEST_CODE_EXIT_ECM = 1

        fun Context.isAirplaneModeOn() = SettingsGlobalStore.get(this).getBoolean(KEY) == true
        fun Context.isAirplaneModeOn() = AirplaneModeStorage(this).getBoolean(KEY) == true
    }
}
// LINT.ThenChange(AirplaneModePreferenceController.java)