• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.network
18 
19 import android.app.Activity
20 import android.app.settings.SettingsEnums.ACTION_AIRPLANE_TOGGLE
21 import android.content.Context
22 import android.content.Intent
23 import android.content.pm.PackageManager
24 import android.os.UserHandle
25 import android.os.UserManager
26 import android.provider.Settings
27 import android.telephony.TelephonyManager
28 import androidx.annotation.DrawableRes
29 import androidx.preference.Preference
30 import com.android.settings.AirplaneModeEnabler
31 import com.android.settings.R
32 import com.android.settings.Utils
33 import com.android.settings.contract.KEY_AIRPLANE_MODE
34 import com.android.settings.metrics.PreferenceActionMetricsProvider
35 import com.android.settings.network.SatelliteRepository.Companion.isSatelliteOn
36 import com.android.settings.restriction.PreferenceRestrictionMixin
37 import com.android.settingslib.RestrictedSwitchPreference
38 import com.android.settingslib.datastore.KeyValueStore
39 import com.android.settingslib.datastore.KeyValueStoreDelegate
40 import com.android.settingslib.datastore.SettingsGlobalStore
41 import com.android.settingslib.metadata.PreferenceAvailabilityProvider
42 import com.android.settingslib.metadata.PreferenceLifecycleContext
43 import com.android.settingslib.metadata.PreferenceLifecycleProvider
44 import com.android.settingslib.metadata.ReadWritePermit
45 import com.android.settingslib.metadata.SensitivityLevel
46 import com.android.settingslib.metadata.SwitchPreference
47 
48 // LINT.IfChange
49 class AirplaneModePreference :
50     SwitchPreference(KEY, R.string.airplane_mode),
51     PreferenceActionMetricsProvider,
52     PreferenceAvailabilityProvider,
53     PreferenceLifecycleProvider,
54     PreferenceRestrictionMixin {
55 
56     override val icon: Int
57         @DrawableRes get() = R.drawable.ic_airplanemode_active
58 
59     override fun tags(context: Context) = arrayOf(KEY_AIRPLANE_MODE)
60 
61     override fun isAvailable(context: Context) =
62         (context.resources.getBoolean(R.bool.config_show_toggle_airplane) &&
63             !context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
64 
65     override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context)
66 
67     override val restrictionKeys
68         get() = arrayOf(UserManager.DISALLOW_AIRPLANE_MODE)
69 
70     override fun getReadPermissions(context: Context) = SettingsGlobalStore.getReadPermissions()
71 
72     override fun getWritePermissions(context: Context) = SettingsGlobalStore.getWritePermissions()
73 
74     override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
75         ReadWritePermit.ALLOW
76 
77     override fun getWritePermit(context: Context, callingPid: Int, callingUid: Int) =
78         when {
79             isSatelliteOn(context) || isInEcmMode(context) -> ReadWritePermit.DISALLOW
80             else -> ReadWritePermit.ALLOW
81         }
82 
83     override val sensitivityLevel
84         get() = SensitivityLevel.HIGH_SENSITIVITY
85 
86     override val preferenceActionMetrics: Int
87         get() = ACTION_AIRPLANE_TOGGLE
88 
89     override fun storage(context: Context): KeyValueStore = AirplaneModeStorage(context)
90 
91     @Suppress("UNCHECKED_CAST")
92     private class AirplaneModeStorage(
93         private val context: Context,
94         private val settingsStore: KeyValueStore = SettingsGlobalStore.get(context),
95     ) : KeyValueStoreDelegate {
96 
97         override val keyValueStoreDelegate
98             get() = settingsStore
99 
100         override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
101             DEFAULT_VALUE as T
102 
103         override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
104             settingsStore.setValue(key, valueType, value)
105 
106             val intent = Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
107             intent.putExtra("state", getBoolean(KEY)!!)
108             context.sendBroadcastAsUser(intent, UserHandle.ALL)
109         }
110     }
111 
112     override fun onCreate(context: PreferenceLifecycleContext) {
113         context.requirePreference<RestrictedSwitchPreference>(KEY).onPreferenceChangeListener =
114             Preference.OnPreferenceChangeListener { _: Preference, _: Any ->
115                 if (isInEcmMode(context)) {
116                     showEcmDialog(context)
117                     return@OnPreferenceChangeListener false
118                 }
119                 if (isSatelliteOn(context)) {
120                     showSatelliteDialog(context)
121                     return@OnPreferenceChangeListener false
122                 }
123                 return@OnPreferenceChangeListener true
124             }
125     }
126 
127     override fun onActivityResult(
128         context: PreferenceLifecycleContext,
129         requestCode: Int,
130         resultCode: Int,
131         data: Intent?,
132     ): Boolean {
133         if (requestCode == REQUEST_CODE_EXIT_ECM && resultCode == Activity.RESULT_OK) {
134             context.getKeyValueStore(KEY)?.setBoolean(KEY, true)
135         }
136         return true
137     }
138 
139     private fun isInEcmMode(context: Context) =
140         AirplaneModeEnabler.isInEcmMode(
141             context,
142             context.getSystemService(TelephonyManager::class.java),
143         )
144 
145     private fun showEcmDialog(context: PreferenceLifecycleContext) {
146         val intent =
147             Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null)
148                 .setPackage(Utils.PHONE_PACKAGE_NAME)
149         context.startActivityForResult(intent, REQUEST_CODE_EXIT_ECM, null)
150     }
151 
152     private fun showSatelliteDialog(context: PreferenceLifecycleContext) {
153         val intent =
154             Intent(context, SatelliteWarningDialogActivity::class.java)
155                 .putExtra(
156                     SatelliteWarningDialogActivity.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG,
157                     SatelliteWarningDialogActivity.TYPE_IS_AIRPLANE_MODE,
158                 )
159         context.startActivity(intent)
160     }
161 
162     companion object {
163         const val KEY = Settings.Global.AIRPLANE_MODE_ON
164         const val DEFAULT_VALUE = false
165         const val REQUEST_CODE_EXIT_ECM = 1
166 
167         fun Context.isAirplaneModeOn() = AirplaneModeStorage(this).getBoolean(KEY) == true
168     }
169 }
170 // LINT.ThenChange(AirplaneModePreferenceController.java)
171