Loading src/com/android/settings/AirplaneModeEnabler.java +79 −42 Original line number Diff line number Diff line Loading @@ -19,28 +19,34 @@ package com.android.settings; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; import android.database.ContentObserver; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.telephony.PhoneStateIntentReceiver; import com.android.internal.telephony.TelephonyProperties; import androidx.annotation.VisibleForTesting; import com.android.settings.network.GlobalSettingsChangeListener; import com.android.settings.network.ProxySubscriptionManager; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.WirelessUtils; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class AirplaneModeEnabler { import java.util.List; private static final int EVENT_SERVICE_STATE_CHANGED = 3; /** * Monitor and update configuration of airplane mode settings */ public class AirplaneModeEnabler extends GlobalSettingsChangeListener { private static final String LOG_TAG = "AirplaneModeEnabler"; private static final boolean DEBUG = false; private final Context mContext; private final MetricsFeatureProvider mMetricsFeatureProvider; private PhoneStateIntentReceiver mPhoneStateReceiver; private OnAirplaneModeChangedListener mOnAirplaneModeChangedListener; public interface OnAirplaneModeChangedListener { Loading @@ -52,46 +58,50 @@ public class AirplaneModeEnabler { void onAirplaneModeChanged(boolean isAirplaneModeOn); } private Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_SERVICE_STATE_CHANGED: onAirplaneModeChanged(); break; } } }; private TelephonyManager mTelephonyManager; @VisibleForTesting PhoneStateListener mPhoneStateListener; private ContentObserver mAirplaneModeObserver = new ContentObserver( new Handler(Looper.getMainLooper())) { @Override public void onChange(boolean selfChange) { onAirplaneModeChanged(); } }; private GlobalSettingsChangeListener mAirplaneModeObserver; public AirplaneModeEnabler(Context context, MetricsFeatureProvider metricsFeatureProvider, OnAirplaneModeChangedListener listener) { public AirplaneModeEnabler(Context context, OnAirplaneModeChangedListener listener) { super(context, Settings.Global.AIRPLANE_MODE_ON); mContext = context; mMetricsFeatureProvider = metricsFeatureProvider; mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); mOnAirplaneModeChangedListener = listener; mPhoneStateReceiver = new PhoneStateIntentReceiver(mContext, mHandler); mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED); mTelephonyManager = context.getSystemService(TelephonyManager.class); mPhoneStateListener = new PhoneStateListener() { @Override public void onRadioPowerStateChanged(int state) { if (DEBUG) { Log.d(LOG_TAG, "RadioPower: " + state); } onAirplaneModeChanged(); } }; } /** * Implementation of GlobalSettingsChangeListener.onChanged */ public void onChanged(String field) { if (DEBUG) { Log.d(LOG_TAG, "Airplane mode configuration update"); } onAirplaneModeChanged(); } public void resume() { mPhoneStateReceiver.registerIntent(); mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true, mAirplaneModeObserver); mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED); } public void pause() { mPhoneStateReceiver.unregisterIntent(); mContext.getContentResolver().unregisterContentObserver(mAirplaneModeObserver); mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); } private void setAirplaneModeOn(boolean enabling) { Loading @@ -105,7 +115,7 @@ public class AirplaneModeEnabler { } // Post the intent Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); intent.putExtra("state", enabling); mContext.sendBroadcastAsUser(intent, UserHandle.ALL); } Loading @@ -124,10 +134,36 @@ public class AirplaneModeEnabler { } } /** * Check the status of ECM mode * * @return any subscription within device is under ECM mode */ public boolean isInEcmMode() { if (mTelephonyManager.getEmergencyCallbackMode()) { return true; } final List<SubscriptionInfo> subInfoList = ProxySubscriptionManager.getInstance(mContext).getActiveSubscriptionsInfo(); if (subInfoList == null) { return false; } for (SubscriptionInfo subInfo : subInfoList) { final TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId()); if (telephonyManager != null) { if (telephonyManager.getEmergencyCallbackMode()) { return true; } } } return false; } public void setAirplaneMode(boolean isAirplaneModeOn) { if (Boolean.parseBoolean( SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { if (isInEcmMode()) { // In ECM mode, do not update database at this point Log.d(LOG_TAG, "ECM airplane mode=" + isAirplaneModeOn); } else { mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AIRPLANE_TOGGLE, isAirplaneModeOn); Loading @@ -136,6 +172,7 @@ public class AirplaneModeEnabler { } public void setAirplaneModeInECM(boolean isECMExit, boolean isAirplaneModeOn) { Log.d(LOG_TAG, "Exist ECM=" + isECMExit + ", with airplane mode=" + isAirplaneModeOn); if (isECMExit) { // update database based on the current checkbox state setAirplaneModeOn(isAirplaneModeOn); Loading src/com/android/settings/network/AirplaneModePreferenceController.java +8 −13 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import static android.provider.SettingsSlicesContract.KEY_AIRPLANE_MODE; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.SystemProperties; import androidx.fragment.app.Fragment; import androidx.preference.Preference; Loading @@ -28,12 +27,9 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import com.android.settings.AirplaneModeEnabler; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; Loading @@ -47,14 +43,15 @@ public class AirplaneModePreferenceController extends TogglePreferenceController private static final String EXIT_ECM_RESULT = "exit_ecm_result"; private Fragment mFragment; private final MetricsFeatureProvider mMetricsFeatureProvider; private AirplaneModeEnabler mAirplaneModeEnabler; private SwitchPreference mAirplaneModePreference; public AirplaneModePreferenceController(Context context, String key) { super(context, key); mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, mMetricsFeatureProvider, this); if (isAvailable(mContext)) { mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, this); } } public void setFragment(Fragment hostFragment) { Loading @@ -63,8 +60,8 @@ public class AirplaneModePreferenceController extends TogglePreferenceController @Override public boolean handlePreferenceTreeClick(Preference preference) { if (KEY_AIRPLANE_MODE.equals(preference.getKey()) && Boolean.parseBoolean( SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { if (KEY_AIRPLANE_MODE.equals(preference.getKey()) && mAirplaneModeEnabler.isInEcmMode()) { // In ECM mode launch ECM app dialog if (mFragment != null) { mFragment.startActivityForResult( Loading @@ -80,10 +77,8 @@ public class AirplaneModePreferenceController extends TogglePreferenceController @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); if (isAvailable()) { mAirplaneModePreference = screen.findPreference(getPreferenceKey()); } } public static boolean isAvailable(Context context) { return context.getResources().getBoolean(R.bool.config_show_toggle_airplane) Loading Loading @@ -117,7 +112,7 @@ public class AirplaneModePreferenceController extends TogglePreferenceController public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_EXIT_ECM) { Boolean isChoiceYes = data.getBooleanExtra(EXIT_ECM_RESULT, false); final boolean isChoiceYes = data.getBooleanExtra(EXIT_ECM_RESULT, false); // Set Airplane mode based on the return value and checkbox state mAirplaneModeEnabler.setAirplaneModeInECM(isChoiceYes, mAirplaneModePreference.isChecked()); Loading tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java 0 → 100644 +70 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; import android.telephony.TelephonyManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowSettings; @RunWith(AndroidJUnit4.class) public final class AirplaneModeEnablerTest { private Context mContext; @Mock private AirplaneModeChangedListener mAirplaneModeChangedListener; private AirplaneModeEnabler mAirplaneModeEnabler; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application.getBaseContext(); mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, mAirplaneModeChangedListener); } @Test public void onRadioPowerStateChanged_beenInvoke_invokeOnAirplaneModeChanged() { mAirplaneModeEnabler.resume(); ShadowSettings.setAirplaneMode(true); mAirplaneModeEnabler.mPhoneStateListener.onRadioPowerStateChanged( TelephonyManager.RADIO_POWER_OFF); verify(mAirplaneModeChangedListener, times(1)).onAirplaneModeChanged(true); } private class AirplaneModeChangedListener implements AirplaneModeEnabler.OnAirplaneModeChangedListener { public void onAirplaneModeChanged(boolean isAirplaneModeOn) {} } } Loading
src/com/android/settings/AirplaneModeEnabler.java +79 −42 Original line number Diff line number Diff line Loading @@ -19,28 +19,34 @@ package com.android.settings; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; import android.database.ContentObserver; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.telephony.PhoneStateIntentReceiver; import com.android.internal.telephony.TelephonyProperties; import androidx.annotation.VisibleForTesting; import com.android.settings.network.GlobalSettingsChangeListener; import com.android.settings.network.ProxySubscriptionManager; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.WirelessUtils; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class AirplaneModeEnabler { import java.util.List; private static final int EVENT_SERVICE_STATE_CHANGED = 3; /** * Monitor and update configuration of airplane mode settings */ public class AirplaneModeEnabler extends GlobalSettingsChangeListener { private static final String LOG_TAG = "AirplaneModeEnabler"; private static final boolean DEBUG = false; private final Context mContext; private final MetricsFeatureProvider mMetricsFeatureProvider; private PhoneStateIntentReceiver mPhoneStateReceiver; private OnAirplaneModeChangedListener mOnAirplaneModeChangedListener; public interface OnAirplaneModeChangedListener { Loading @@ -52,46 +58,50 @@ public class AirplaneModeEnabler { void onAirplaneModeChanged(boolean isAirplaneModeOn); } private Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_SERVICE_STATE_CHANGED: onAirplaneModeChanged(); break; } } }; private TelephonyManager mTelephonyManager; @VisibleForTesting PhoneStateListener mPhoneStateListener; private ContentObserver mAirplaneModeObserver = new ContentObserver( new Handler(Looper.getMainLooper())) { @Override public void onChange(boolean selfChange) { onAirplaneModeChanged(); } }; private GlobalSettingsChangeListener mAirplaneModeObserver; public AirplaneModeEnabler(Context context, MetricsFeatureProvider metricsFeatureProvider, OnAirplaneModeChangedListener listener) { public AirplaneModeEnabler(Context context, OnAirplaneModeChangedListener listener) { super(context, Settings.Global.AIRPLANE_MODE_ON); mContext = context; mMetricsFeatureProvider = metricsFeatureProvider; mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); mOnAirplaneModeChangedListener = listener; mPhoneStateReceiver = new PhoneStateIntentReceiver(mContext, mHandler); mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED); mTelephonyManager = context.getSystemService(TelephonyManager.class); mPhoneStateListener = new PhoneStateListener() { @Override public void onRadioPowerStateChanged(int state) { if (DEBUG) { Log.d(LOG_TAG, "RadioPower: " + state); } onAirplaneModeChanged(); } }; } /** * Implementation of GlobalSettingsChangeListener.onChanged */ public void onChanged(String field) { if (DEBUG) { Log.d(LOG_TAG, "Airplane mode configuration update"); } onAirplaneModeChanged(); } public void resume() { mPhoneStateReceiver.registerIntent(); mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true, mAirplaneModeObserver); mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED); } public void pause() { mPhoneStateReceiver.unregisterIntent(); mContext.getContentResolver().unregisterContentObserver(mAirplaneModeObserver); mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); } private void setAirplaneModeOn(boolean enabling) { Loading @@ -105,7 +115,7 @@ public class AirplaneModeEnabler { } // Post the intent Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); intent.putExtra("state", enabling); mContext.sendBroadcastAsUser(intent, UserHandle.ALL); } Loading @@ -124,10 +134,36 @@ public class AirplaneModeEnabler { } } /** * Check the status of ECM mode * * @return any subscription within device is under ECM mode */ public boolean isInEcmMode() { if (mTelephonyManager.getEmergencyCallbackMode()) { return true; } final List<SubscriptionInfo> subInfoList = ProxySubscriptionManager.getInstance(mContext).getActiveSubscriptionsInfo(); if (subInfoList == null) { return false; } for (SubscriptionInfo subInfo : subInfoList) { final TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId()); if (telephonyManager != null) { if (telephonyManager.getEmergencyCallbackMode()) { return true; } } } return false; } public void setAirplaneMode(boolean isAirplaneModeOn) { if (Boolean.parseBoolean( SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { if (isInEcmMode()) { // In ECM mode, do not update database at this point Log.d(LOG_TAG, "ECM airplane mode=" + isAirplaneModeOn); } else { mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AIRPLANE_TOGGLE, isAirplaneModeOn); Loading @@ -136,6 +172,7 @@ public class AirplaneModeEnabler { } public void setAirplaneModeInECM(boolean isECMExit, boolean isAirplaneModeOn) { Log.d(LOG_TAG, "Exist ECM=" + isECMExit + ", with airplane mode=" + isAirplaneModeOn); if (isECMExit) { // update database based on the current checkbox state setAirplaneModeOn(isAirplaneModeOn); Loading
src/com/android/settings/network/AirplaneModePreferenceController.java +8 −13 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import static android.provider.SettingsSlicesContract.KEY_AIRPLANE_MODE; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.SystemProperties; import androidx.fragment.app.Fragment; import androidx.preference.Preference; Loading @@ -28,12 +27,9 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import com.android.settings.AirplaneModeEnabler; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; Loading @@ -47,14 +43,15 @@ public class AirplaneModePreferenceController extends TogglePreferenceController private static final String EXIT_ECM_RESULT = "exit_ecm_result"; private Fragment mFragment; private final MetricsFeatureProvider mMetricsFeatureProvider; private AirplaneModeEnabler mAirplaneModeEnabler; private SwitchPreference mAirplaneModePreference; public AirplaneModePreferenceController(Context context, String key) { super(context, key); mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, mMetricsFeatureProvider, this); if (isAvailable(mContext)) { mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, this); } } public void setFragment(Fragment hostFragment) { Loading @@ -63,8 +60,8 @@ public class AirplaneModePreferenceController extends TogglePreferenceController @Override public boolean handlePreferenceTreeClick(Preference preference) { if (KEY_AIRPLANE_MODE.equals(preference.getKey()) && Boolean.parseBoolean( SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { if (KEY_AIRPLANE_MODE.equals(preference.getKey()) && mAirplaneModeEnabler.isInEcmMode()) { // In ECM mode launch ECM app dialog if (mFragment != null) { mFragment.startActivityForResult( Loading @@ -80,10 +77,8 @@ public class AirplaneModePreferenceController extends TogglePreferenceController @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); if (isAvailable()) { mAirplaneModePreference = screen.findPreference(getPreferenceKey()); } } public static boolean isAvailable(Context context) { return context.getResources().getBoolean(R.bool.config_show_toggle_airplane) Loading Loading @@ -117,7 +112,7 @@ public class AirplaneModePreferenceController extends TogglePreferenceController public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_EXIT_ECM) { Boolean isChoiceYes = data.getBooleanExtra(EXIT_ECM_RESULT, false); final boolean isChoiceYes = data.getBooleanExtra(EXIT_ECM_RESULT, false); // Set Airplane mode based on the return value and checkbox state mAirplaneModeEnabler.setAirplaneModeInECM(isChoiceYes, mAirplaneModePreference.isChecked()); Loading
tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java 0 → 100644 +70 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; import android.telephony.TelephonyManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowSettings; @RunWith(AndroidJUnit4.class) public final class AirplaneModeEnablerTest { private Context mContext; @Mock private AirplaneModeChangedListener mAirplaneModeChangedListener; private AirplaneModeEnabler mAirplaneModeEnabler; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application.getBaseContext(); mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, mAirplaneModeChangedListener); } @Test public void onRadioPowerStateChanged_beenInvoke_invokeOnAirplaneModeChanged() { mAirplaneModeEnabler.resume(); ShadowSettings.setAirplaneMode(true); mAirplaneModeEnabler.mPhoneStateListener.onRadioPowerStateChanged( TelephonyManager.RADIO_POWER_OFF); verify(mAirplaneModeChangedListener, times(1)).onAirplaneModeChanged(true); } private class AirplaneModeChangedListener implements AirplaneModeEnabler.OnAirplaneModeChangedListener { public void onAirplaneModeChanged(boolean isAirplaneModeOn) {} } }