From e60bff2d818dea3b829421c97595b78a20bfc32e Mon Sep 17 00:00:00 2001 From: Jacky Wang Date: Thu, 27 Feb 2025 20:32:01 +0800 Subject: [PATCH] [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 --- .../network/AirplaneModePreference.kt | 51 ++++--------------- 1 file changed, 10 insertions(+), 41 deletions(-) diff --git a/src/com/android/settings/network/AirplaneModePreference.kt b/src/com/android/settings/network/AirplaneModePreference.kt index 3d80f12ce2d..de2eb1a43f1 100644 --- a/src/com/android/settings/network/AirplaneModePreference.kt +++ b/src/com/android/settings/network/AirplaneModePreference.kt @@ -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(), KeyValueStore { - private var phoneStateListener: PhoneStateListener? = null + private val settingsStore: SettingsStore = SettingsGlobalStore.get(context), + ) : KeyedObservableDelegate(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 getDefaultValue(key: String, valueType: Class) = DEFAULT_VALUE as T @@ -116,31 +104,12 @@ class AirplaneModePreference : (settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T override fun setValue(key: String, valueType: Class, 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)