From e520ec60aa2fca5770e33c662afbbe7e5461a446 Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Thu, 26 Dec 2019 18:41:32 +0800 Subject: [PATCH] [Settings] Remove PhoneStateIntentReceiver 1. Replace PhoneStateIntentReceiver by adopting PhoneStateListener 2. Replace TelephonyProperties.in_ecm_mode() by TelephonyManager.getEmergencyCallbackMode() Bug: 144331663 Change-Id: Ib127cb165c65f50851c4390b05a16dfb8024fab1 Bug: 145830780 Test: Manual Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=AirplaneModeEnabler Merged-In: Ib39ab1881484f65bc5a3834b2828c6ba98198cca --- .../android/settings/AirplaneModeEnabler.java | 121 ++++++++++++------ .../AirplaneModePreferenceController.java | 21 ++- .../settings/AirplaneModeEnablerTest.java | 70 ++++++++++ 3 files changed, 157 insertions(+), 55 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java diff --git a/src/com/android/settings/AirplaneModeEnabler.java b/src/com/android/settings/AirplaneModeEnabler.java index dde7ce0fcf6..a843a046c98 100644 --- a/src/com/android/settings/AirplaneModeEnabler.java +++ b/src/com/android/settings/AirplaneModeEnabler.java @@ -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 { @@ -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) { @@ -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); } @@ -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 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); @@ -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); diff --git a/src/com/android/settings/network/AirplaneModePreferenceController.java b/src/com/android/settings/network/AirplaneModePreferenceController.java index 5c1913b575f..d7da909efbe 100644 --- a/src/com/android/settings/network/AirplaneModePreferenceController.java +++ b/src/com/android/settings/network/AirplaneModePreferenceController.java @@ -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; @@ -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; @@ -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) { @@ -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( @@ -80,9 +77,7 @@ public class AirplaneModePreferenceController extends TogglePreferenceController @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - if (isAvailable()) { - mAirplaneModePreference = screen.findPreference(getPreferenceKey()); - } + mAirplaneModePreference = screen.findPreference(getPreferenceKey()); } public static boolean isAvailable(Context context) { @@ -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()); diff --git a/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java b/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java new file mode 100644 index 00000000000..24abac9f258 --- /dev/null +++ b/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java @@ -0,0 +1,70 @@ +/* + * 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) {} + } +}