[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.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)