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