1 /* 2 * Copyright (C) 2007 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; 18 19 import android.app.settings.SettingsEnums; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.Looper; 23 import android.os.UserHandle; 24 import android.provider.Settings; 25 import android.telephony.PhoneStateListener; 26 import android.telephony.SubscriptionInfo; 27 import android.telephony.TelephonyManager; 28 import android.util.Log; 29 30 import androidx.annotation.VisibleForTesting; 31 32 import com.android.settings.network.GlobalSettingsChangeListener; 33 import com.android.settings.network.ProxySubscriptionManager; 34 import com.android.settings.overlay.FeatureFactory; 35 import com.android.settingslib.WirelessUtils; 36 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 37 38 import java.util.List; 39 40 /** 41 * Monitor and update configuration of airplane mode settings 42 */ 43 public class AirplaneModeEnabler extends GlobalSettingsChangeListener { 44 45 private static final String LOG_TAG = "AirplaneModeEnabler"; 46 private static final boolean DEBUG = false; 47 48 private final Context mContext; 49 private final MetricsFeatureProvider mMetricsFeatureProvider; 50 51 private OnAirplaneModeChangedListener mOnAirplaneModeChangedListener; 52 53 public interface OnAirplaneModeChangedListener { 54 /** 55 * Called when airplane mode status is changed. 56 * 57 * @param isAirplaneModeOn the airplane mode is on 58 */ onAirplaneModeChanged(boolean isAirplaneModeOn)59 void onAirplaneModeChanged(boolean isAirplaneModeOn); 60 } 61 62 private TelephonyManager mTelephonyManager; 63 @VisibleForTesting 64 PhoneStateListener mPhoneStateListener; 65 AirplaneModeEnabler(Context context, OnAirplaneModeChangedListener listener)66 public AirplaneModeEnabler(Context context, OnAirplaneModeChangedListener listener) { 67 super(context, Settings.Global.AIRPLANE_MODE_ON); 68 69 mContext = context; 70 mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); 71 mOnAirplaneModeChangedListener = listener; 72 73 mTelephonyManager = context.getSystemService(TelephonyManager.class); 74 75 mPhoneStateListener = new PhoneStateListener(Looper.getMainLooper()) { 76 @Override 77 public void onRadioPowerStateChanged(int state) { 78 if (DEBUG) { 79 Log.d(LOG_TAG, "RadioPower: " + state); 80 } 81 onAirplaneModeChanged(); 82 } 83 }; 84 } 85 86 /** 87 * Implementation of GlobalSettingsChangeListener.onChanged 88 */ 89 @Override onChanged(String field)90 public void onChanged(String field) { 91 if (DEBUG) { 92 Log.d(LOG_TAG, "Airplane mode configuration update"); 93 } 94 onAirplaneModeChanged(); 95 } 96 97 /** 98 * Start listening to the phone state change 99 */ start()100 public void start() { 101 mTelephonyManager.listen(mPhoneStateListener, 102 PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED); 103 } 104 105 /** 106 * Stop listening to the phone state change 107 */ stop()108 public void stop() { 109 mTelephonyManager.listen(mPhoneStateListener, 110 PhoneStateListener.LISTEN_NONE); 111 } 112 setAirplaneModeOn(boolean enabling)113 private void setAirplaneModeOn(boolean enabling) { 114 // Change the system setting 115 Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 116 enabling ? 1 : 0); 117 118 // Notify listener the system setting is changed. 119 if (mOnAirplaneModeChangedListener != null) { 120 mOnAirplaneModeChangedListener.onAirplaneModeChanged(enabling); 121 } 122 123 // Post the intent 124 final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); 125 intent.putExtra("state", enabling); 126 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 127 } 128 129 /** 130 * Called when we've received confirmation that the airplane mode was set. 131 * TODO: We update the checkbox summary when we get notified 132 * that mobile radio is powered up/down. We should not have dependency 133 * on one radio alone. We need to do the following: 134 * - handle the case of wifi/bluetooth failures 135 * - mobile does not send failure notification, fail on timeout. 136 */ onAirplaneModeChanged()137 private void onAirplaneModeChanged() { 138 if (mOnAirplaneModeChangedListener != null) { 139 mOnAirplaneModeChangedListener.onAirplaneModeChanged(isAirplaneModeOn()); 140 } 141 } 142 143 /** 144 * Check the status of ECM mode 145 * 146 * @return any subscription within device is under ECM mode 147 */ isInEcmMode()148 public boolean isInEcmMode() { 149 if (mTelephonyManager.getEmergencyCallbackMode()) { 150 return true; 151 } 152 final List<SubscriptionInfo> subInfoList = 153 ProxySubscriptionManager.getInstance(mContext).getActiveSubscriptionsInfo(); 154 if (subInfoList == null) { 155 return false; 156 } 157 for (SubscriptionInfo subInfo : subInfoList) { 158 final TelephonyManager telephonyManager = 159 mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId()); 160 if (telephonyManager != null) { 161 if (telephonyManager.getEmergencyCallbackMode()) { 162 return true; 163 } 164 } 165 } 166 return false; 167 } 168 setAirplaneMode(boolean isAirplaneModeOn)169 public void setAirplaneMode(boolean isAirplaneModeOn) { 170 if (isInEcmMode()) { 171 // In ECM mode, do not update database at this point 172 Log.d(LOG_TAG, "ECM airplane mode=" + isAirplaneModeOn); 173 } else { 174 mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AIRPLANE_TOGGLE, 175 isAirplaneModeOn); 176 setAirplaneModeOn(isAirplaneModeOn); 177 } 178 } 179 setAirplaneModeInECM(boolean isECMExit, boolean isAirplaneModeOn)180 public void setAirplaneModeInECM(boolean isECMExit, boolean isAirplaneModeOn) { 181 Log.d(LOG_TAG, "Exist ECM=" + isECMExit + ", with airplane mode=" + isAirplaneModeOn); 182 if (isECMExit) { 183 // update database based on the current checkbox state 184 setAirplaneModeOn(isAirplaneModeOn); 185 } else { 186 // update summary 187 onAirplaneModeChanged(); 188 } 189 } 190 isAirplaneModeOn()191 public boolean isAirplaneModeOn() { 192 return WirelessUtils.isAirplaneModeOn(mContext); 193 } 194 } 195