[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
This commit is contained in:
Jacky Wang
2025-02-27 20:32:01 +08:00
parent 0972a9f3b7
commit e60bff2d81

View File

@@ -21,11 +21,9 @@ import android.app.settings.SettingsEnums.ACTION_AIRPLANE_TOGGLE
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Looper
import android.os.UserHandle import android.os.UserHandle
import android.os.UserManager import android.os.UserManager
import android.provider.Settings import android.provider.Settings
import android.telephony.PhoneStateListener
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.preference.Preference 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.network.SatelliteRepository.Companion.isSatelliteOn
import com.android.settings.restriction.PreferenceRestrictionMixin import com.android.settings.restriction.PreferenceRestrictionMixin
import com.android.settingslib.RestrictedSwitchPreference import com.android.settingslib.RestrictedSwitchPreference
import com.android.settingslib.datastore.AbstractKeyedDataObservable
import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.KeyedObservableDelegate
import com.android.settingslib.datastore.SettingsGlobalStore import com.android.settingslib.datastore.SettingsGlobalStore
import com.android.settingslib.datastore.SettingsStore import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.metadata.PreferenceLifecycleContext import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit import com.android.settingslib.metadata.ReadWritePermit
@@ -78,12 +75,7 @@ class AirplaneModePreference :
override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) = override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
ReadWritePermit.ALLOW ReadWritePermit.ALLOW
override fun getWritePermit( override fun getWritePermit(context: Context, callingPid: Int, callingUid: Int) =
context: Context,
value: Boolean?,
callingPid: Int,
callingUid: Int,
) =
when { when {
isSatelliteOn(context) || isInEcmMode(context) -> ReadWritePermit.DISALLOW isSatelliteOn(context) || isInEcmMode(context) -> ReadWritePermit.DISALLOW
else -> ReadWritePermit.ALLOW else -> ReadWritePermit.ALLOW
@@ -95,19 +87,15 @@ class AirplaneModePreference :
override val preferenceActionMetrics: Int override val preferenceActionMetrics: Int
get() = ACTION_AIRPLANE_TOGGLE get() = ACTION_AIRPLANE_TOGGLE
override fun storage(context: Context): KeyValueStore = override fun storage(context: Context): KeyValueStore = AirplaneModeStorage(context)
AirplaneModeStorage(context, SettingsGlobalStore.get(context))
@Suppress("DEPRECATION", "MissingPermission", "UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private class AirplaneModeStorage( private class AirplaneModeStorage(
private val context: Context, private val context: Context,
private val settingsStore: SettingsStore, private val settingsStore: SettingsStore = SettingsGlobalStore.get(context),
) : AbstractKeyedDataObservable<String>(), KeyValueStore { ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
private var phoneStateListener: PhoneStateListener? = null
override fun contains(key: String) = override fun contains(key: String) = settingsStore.contains(KEY)
settingsStore.contains(KEY) &&
context.getSystemService(TelephonyManager::class.java) != null
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) = override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
DEFAULT_VALUE as T DEFAULT_VALUE as T
@@ -116,31 +104,12 @@ class AirplaneModePreference :
(settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T (settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) { override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
if (value !is Boolean) return settingsStore.setValue(key, valueType, value)
settingsStore.setBoolean(key, value)
val intent = Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED) val intent = Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
intent.putExtra("state", value) intent.putExtra("state", getBoolean(KEY)!!)
context.sendBroadcastAsUser(intent, UserHandle.ALL) 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) { override fun onCreate(context: PreferenceLifecycleContext) {
@@ -198,7 +167,7 @@ class AirplaneModePreference :
const val DEFAULT_VALUE = false const val DEFAULT_VALUE = false
const val REQUEST_CODE_EXIT_ECM = 1 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) // LINT.ThenChange(AirplaneModePreferenceController.java)