Create central TelephonyListenerManager.

The TelephonyManager doesn't like have "too many" listeners
registered on int at any given time. It will actually throw
exceptions when this happens. To lighten the load from the SystemUI
side, TelephonyListenerManager now ensures that only one listener is
ever subscribed at any point.

SystemUI can now use this class instead, piggy-backing on the
possibly already subscribed listener to retrieve the events it cares
about.

Also, use Executors in CarrierTextController instead of Handlers.

Bug: 179775696
Test: atest SystemUITests
Change-Id: I626e80a91396161022e1fc6387598521f77bf4fc
This commit is contained in:
Dave Mankoff
2021-03-22 15:29:20 -04:00
parent 9ac5677b49
commit deca9ea898
19 changed files with 690 additions and 134 deletions

View File

@@ -18,6 +18,7 @@ package com.android.keyguard;
import android.content.Context;
import android.content.res.TypedArray;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.method.SingleLineTransformationMethod;
import android.util.AttributeSet;
@@ -26,6 +27,7 @@ import android.widget.TextView;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.telephony.TelephonyListenerManager;
import java.util.Locale;
@@ -85,7 +87,10 @@ public class CarrierText extends TextView {
mSeparator = getResources().getString(
com.android.internal.R.string.kg_text_message_separator);
mCarrierTextController = new CarrierTextController(mContext, mSeparator, mShowAirplaneMode,
mShowMissingSim);
mShowMissingSim, mContext.getSystemService(TelephonyManager.class),
Dependency.get(TelephonyListenerManager.class),
Dependency.get(Dependency.MAIN_EXECUTOR),
Dependency.get(Dependency.BACKGROUND_EXECUTOR));
mShouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive();
setSelected(mShouldMarquee); // Allow marquee to work.
}

View File

@@ -16,20 +16,15 @@
package com.android.keyguard;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
import static android.telephony.PhoneStateListener.LISTEN_NONE;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -40,11 +35,14 @@ import androidx.annotation.VisibleForTesting;
import com.android.settingslib.WirelessUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.telephony.TelephonyListenerManager;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
@@ -59,8 +57,6 @@ public class CarrierTextController {
private static final String TAG = "CarrierTextController";
private final boolean mIsEmergencyCallCapable;
private final Handler mMainHandler;
private final Handler mBgHandler;
private boolean mTelephonyCapable;
private boolean mShowMissingSim;
private boolean mShowAirplaneMode;
@@ -73,6 +69,10 @@ public class CarrierTextController {
@Nullable // Check for nullability before dispatching
private CarrierTextCallback mCarrierTextCallback;
private Context mContext;
private final TelephonyManager mTelephonyManager;
private final TelephonyListenerManager mTelephonyListenerManager;
private final Executor mMainExecutor;
private final Executor mBgExecutor;
private CharSequence mSeparator;
private WakefulnessLifecycle mWakefulnessLifecycle;
private final WakefulnessLifecycle.Observer mWakefulnessObserver =
@@ -129,14 +129,13 @@ public class CarrierTextController {
}
};
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
private final ActiveDataSubscriptionIdListener mPhoneStateListener =
new ActiveDataSubscriptionIdListener() {
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
mActiveMobileDataSubscription = subId;
if (mNetworkSupported.get() && mCarrierTextCallback != null) {
updateCarrierText();
}
if (mNetworkSupported.get() && mCarrierTextCallback != null) {
updateCarrierText();
}
}
};
@@ -163,9 +162,15 @@ public class CarrierTextController {
* @param separator Separator between different parts of the text
*/
public CarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode,
boolean showMissingSim) {
boolean showMissingSim, TelephonyManager telephonyManager,
TelephonyListenerManager telephonyListenerManager,
@Main Executor mainExecutor, @Background Executor bgExecutor) {
mContext = context;
mIsEmergencyCallCapable = getTelephonyManager().isVoiceCapable();
mTelephonyManager = telephonyManager;
mTelephonyListenerManager = telephonyListenerManager;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
mIsEmergencyCallCapable = mTelephonyManager.isVoiceCapable();
mShowAirplaneMode = showAirplaneMode;
mShowMissingSim = showMissingSim;
@@ -173,12 +178,10 @@ public class CarrierTextController {
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mSeparator = separator;
mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
mSimSlotsNumber = getTelephonyManager().getSupportedModemCount();
mSimSlotsNumber = mTelephonyManager.getSupportedModemCount();
mSimErrorState = new boolean[mSimSlotsNumber];
mMainHandler = Dependency.get(Dependency.MAIN_HANDLER);
mBgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
mBgHandler.post(() -> {
mBgExecutor.execute(() -> {
boolean supported =
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
if (supported && mNetworkSupported.compareAndSet(false, supported)) {
@@ -208,7 +211,7 @@ public class CarrierTextController {
CharSequence carrierTextForSimIOError = getCarrierTextForSimState(
TelephonyManager.SIM_STATE_CARD_IO_ERROR, carrier);
// mSimErrorState has the state of each sim indexed by slotID.
for (int index = 0; index < getTelephonyManager().getActiveModemCount(); index++) {
for (int index = 0; index < mTelephonyManager.getActiveModemCount(); index++) {
if (!mSimErrorState[index]) {
continue;
}
@@ -247,26 +250,24 @@ public class CarrierTextController {
* This call will always be processed in a background thread.
*/
private void handleSetListening(CarrierTextCallback callback) {
TelephonyManager telephonyManager = getTelephonyManager();
if (callback != null) {
mCarrierTextCallback = callback;
if (mNetworkSupported.get()) {
// Keyguard update monitor expects callbacks from main thread
mMainHandler.post(() -> mKeyguardUpdateMonitor.registerCallback(mCallback));
mMainExecutor.execute(() -> mKeyguardUpdateMonitor.registerCallback(mCallback));
mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
telephonyManager.listen(mPhoneStateListener,
LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
} else {
// Don't listen and clear out the text when the device isn't a phone.
mMainHandler.post(() -> callback.updateCarrierInfo(
mMainExecutor.execute(() -> callback.updateCarrierInfo(
new CarrierTextCallbackInfo("", null, false, null)
));
}
} else {
mCarrierTextCallback = null;
mMainHandler.post(() -> mKeyguardUpdateMonitor.removeCallback(mCallback));
mMainExecutor.execute(() -> mKeyguardUpdateMonitor.removeCallback(mCallback));
mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
telephonyManager.listen(mPhoneStateListener, LISTEN_NONE);
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener);
}
}
@@ -277,7 +278,7 @@ public class CarrierTextController {
* @param callback Callback to provide text updates
*/
public void setListening(CarrierTextCallback callback) {
mBgHandler.post(() -> handleSetListening(callback));
mBgExecutor.execute(() -> handleSetListening(callback));
}
protected List<SubscriptionInfo> getSubscriptionInfo() {
@@ -400,7 +401,7 @@ public class CarrierTextController {
protected void postToCallback(CarrierTextCallbackInfo info) {
final CarrierTextCallback callback = mCarrierTextCallback;
if (callback != null) {
mMainHandler.post(() -> callback.updateCarrierInfo(info));
mMainExecutor.execute(() -> callback.updateCarrierInfo(info));
}
}
@@ -620,14 +621,25 @@ public class CarrierTextController {
public static class Builder {
private final Context mContext;
private final String mSeparator;
private final TelephonyManager mTelephonyManager;
private final TelephonyListenerManager mTelephonyListenerManager;
private final Executor mMainExecutor;
private final Executor mBgExecutor;
private boolean mShowAirplaneMode;
private boolean mShowMissingSim;
@Inject
public Builder(Context context, @Main Resources resources) {
public Builder(Context context, @Main Resources resources,
TelephonyManager telephonyManager,
TelephonyListenerManager telephonyListenerManager, @Main Executor mainExecutor,
@Background Executor bgExecutor) {
mContext = context;
mSeparator = resources.getString(
com.android.internal.R.string.kg_text_message_separator);
mTelephonyManager = telephonyManager;
mTelephonyListenerManager = telephonyListenerManager;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
}
@@ -643,7 +655,8 @@ public class CarrierTextController {
public CarrierTextController build() {
return new CarrierTextController(
mContext, mSeparator, mShowAirplaneMode, mShowMissingSim);
mContext, mSeparator, mShowAirplaneMode, mShowMissingSim, mTelephonyManager,
mTelephonyListenerManager, mMainExecutor, mBgExecutor);
}
}
/**

View File

@@ -22,7 +22,6 @@ import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_STOPPED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -76,11 +75,11 @@ import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.SparseArray;
@@ -107,6 +106,7 @@ import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.Assert;
import com.android.systemui.util.RingerModeTracker;
@@ -290,6 +290,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mDeviceInteractive;
private boolean mScreenOn;
private SubscriptionManager mSubscriptionManager;
private final TelephonyListenerManager mTelephonyListenerManager;
private List<SubscriptionInfo> mSubscriptionInfo;
private TrustManager mTrustManager;
private UserManager mUserManager;
@@ -358,7 +359,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
};
@VisibleForTesting
public PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
public TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener =
new TelephonyCallback.ActiveDataSubscriptionIdListener() {
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
mActiveMobileDataSubscription = subId;
@@ -1614,9 +1616,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
StatusBarStateController statusBarStateController,
LockPatternUtils lockPatternUtils,
AuthController authController,
TelephonyListenerManager telephonyListenerManager,
FeatureFlags featureFlags) {
mContext = context;
mSubscriptionManager = SubscriptionManager.from(context);
mTelephonyListenerManager = telephonyListenerManager;
mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged);
mBackgroundExecutor = backgroundExecutor;
@@ -1865,8 +1869,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mTelephonyManager =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephonyManager != null) {
mTelephonyManager.listen(mPhoneStateListener,
LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
// Set initial sim states values.
for (int slot = 0; slot < mTelephonyManager.getActiveModemCount(); slot++) {
int state = mTelephonyManager.getSimState(slot);
@@ -3123,7 +3126,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
TelephonyManager telephony =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if (telephony != null) {
telephony.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener);
}
mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener);

View File

@@ -120,6 +120,7 @@ import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tuner.TunablePadding.TunablePaddingService;
import com.android.systemui.tuner.TunerService;
@@ -350,6 +351,7 @@ public class Dependency {
@Inject Lazy<MediaOutputDialogFactory> mMediaOutputDialogFactory;
@Inject Lazy<DeviceConfigProxy> mDeviceConfigProxy;
@Inject Lazy<NavigationBarOverlayController> mNavbarButtonsControllerLazy;
@Inject Lazy<TelephonyListenerManager> mTelephonyListenerManager;
@Inject
public Dependency() {
@@ -545,6 +547,7 @@ public class Dependency {
mProviders.put(StatusBar.class, mStatusBar::get);
mProviders.put(ProtoTracer.class, mProtoTracer::get);
mProviders.put(DeviceConfigProxy.class, mDeviceConfigProxy::get);
mProviders.put(TelephonyListenerManager.class, mTelephonyListenerManager::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add

View File

@@ -73,8 +73,8 @@ import android.provider.Settings;
import android.service.dreams.IDreamManager;
import android.sysprop.TelephonyProperties;
import android.telecom.TelecomManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.transition.AutoTransition;
import android.transition.TransitionManager;
@@ -138,6 +138,7 @@ import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.EmergencyDialerConstants;
import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.leak.RotationUtils;
@@ -303,7 +304,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
AudioManager audioManager, IDreamManager iDreamManager,
DevicePolicyManager devicePolicyManager, LockPatternUtils lockPatternUtils,
BroadcastDispatcher broadcastDispatcher,
ConnectivityManager connectivityManager, TelephonyManager telephonyManager,
ConnectivityManager connectivityManager,
TelephonyListenerManager telephonyListenerManager,
ContentResolver contentResolver, @Nullable Vibrator vibrator, @Main Resources resources,
ConfigurationController configurationController, ActivityStarter activityStarter,
KeyguardStateController keyguardStateController, UserManager userManager,
@@ -361,7 +363,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
// get notified of phone state changes
telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
telephonyListenerManager.addServiceStateListener(mPhoneStateListener);
contentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
mAirplaneModeObserver);
@@ -2049,7 +2051,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
};
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
private final TelephonyCallback.ServiceStateListener mPhoneStateListener =
new TelephonyCallback.ServiceStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
if (!mHasTelephony) return;

View File

@@ -22,7 +22,6 @@ import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT;
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE;
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -44,11 +43,11 @@ import android.os.Looper;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.CellSignalStrength;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.FeatureFlagUtils;
@@ -74,6 +73,7 @@ import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.telephony.TelephonyListenerManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -108,6 +108,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
private final Context mContext;
private final TelephonyManager mPhone;
private final TelephonyListenerManager mTelephonyListenerManager;
private final WifiManager mWifiManager;
private final ConnectivityManager mConnectivityManager;
private final SubscriptionManager mSubscriptionManager;
@@ -121,7 +122,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
private final boolean mProviderModel;
private Config mConfig;
private PhoneStateListener mPhoneStateListener;
private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
// Subcontrollers.
@@ -201,12 +202,14 @@ public class NetworkControllerImpl extends BroadcastReceiver
BroadcastDispatcher broadcastDispatcher,
ConnectivityManager connectivityManager,
TelephonyManager telephonyManager,
TelephonyListenerManager telephonyListenerManager,
@Nullable WifiManager wifiManager,
NetworkScoreManager networkScoreManager,
AccessPointControllerImpl accessPointController,
DemoModeController demoModeController) {
this(context, connectivityManager,
telephonyManager,
telephonyListenerManager,
wifiManager,
networkScoreManager,
SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
@@ -222,7 +225,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
@VisibleForTesting
NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
TelephonyManager telephonyManager, WifiManager wifiManager,
TelephonyManager telephonyManager,
TelephonyListenerManager telephonyListenerManager,
WifiManager wifiManager,
NetworkScoreManager networkScoreManager,
SubscriptionManager subManager, Config config, Looper bgLooper,
CallbackHandler callbackHandler,
@@ -233,6 +238,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
BroadcastDispatcher broadcastDispatcher,
DemoModeController demoModeController) {
mContext = context;
mTelephonyListenerManager = telephonyListenerManager;
mConfig = config;
mReceiverHandler = new Handler(bgLooper);
mCallbackHandler = callbackHandler;
@@ -372,23 +378,20 @@ public class NetworkControllerImpl extends BroadcastReceiver
// exclusively for status bar icons.
mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler);
// Register the listener on our bg looper
mPhoneStateListener = new PhoneStateListener(mReceiverHandler::post) {
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
// For data switching from A to B, we assume B is validated for up to 2 seconds iff:
// 1) A and B are in the same subscription group e.g. CBRS data switch. And
// 2) A was validated before the switch.
// This is to provide smooth transition for UI without showing cross during data
// switch.
if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) {
if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true.");
mForceCellularValidated = true;
mReceiverHandler.removeCallbacks(mClearForceValidated);
mReceiverHandler.postDelayed(mClearForceValidated, 2000);
}
mActiveMobileDataSubscription = subId;
doUpdateMobileControllers();
mPhoneStateListener = subId -> {
// For data switching from A to B, we assume B is validated for up to 2 seconds iff:
// 1) A and B are in the same subscription group e.g. CBRS data switch. And
// 2) A was validated before the switch.
// This is to provide smooth transition for UI without showing cross during data
// switch.
if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) {
if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true.");
mForceCellularValidated = true;
mReceiverHandler.removeCallbacks(mClearForceValidated);
mReceiverHandler.postDelayed(mClearForceValidated, 2000);
}
mActiveMobileDataSubscription = subId;
doUpdateMobileControllers();
};
mDemoModeController.addCallback(this);
@@ -428,7 +431,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
mSubscriptionListener = new SubListener();
}
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
mPhone.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
// broadcasts
IntentFilter filter = new IntentFilter();

View File

@@ -42,8 +42,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyCallback;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -69,6 +68,7 @@ import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.qs.QSUserSwitcherEvent;
import com.android.systemui.qs.tiles.UserDetailView;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.user.CreateUserActivity;
import java.io.FileDescriptor;
@@ -105,6 +105,7 @@ public class UserSwitcherController implements Dumpable {
protected final Handler mHandler;
private final ActivityStarter mActivityStarter;
private final BroadcastDispatcher mBroadcastDispatcher;
private final TelephonyListenerManager mTelephonyListenerManager;
private final IActivityTaskManager mActivityTaskManager;
private ArrayList<UserRecord> mUsers = new ArrayList<>();
@@ -127,9 +128,11 @@ public class UserSwitcherController implements Dumpable {
public UserSwitcherController(Context context, KeyguardStateController keyguardStateController,
@Main Handler handler, ActivityStarter activityStarter,
BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger,
TelephonyListenerManager telephonyListenerManager,
IActivityTaskManager activityTaskManager) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mTelephonyListenerManager = telephonyListenerManager;
mActivityTaskManager = activityTaskManager;
mUiEventLogger = uiEventLogger;
mUserDetailAdapter = new UserDetailAdapter(this, mContext, mUiEventLogger);
@@ -458,18 +461,15 @@ public class UserSwitcherController implements Dumpable {
}
private void listenForCallState() {
final TelephonyManager tele =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if (tele != null) {
tele.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
mTelephonyListenerManager.addCallStateListener(mPhoneStateListener);
}
private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
private final TelephonyCallback.CallStateListener mPhoneStateListener =
new TelephonyCallback.CallStateListener() {
private int mCallState;
@Override
public void onCallStateChanged(int state, String incomingNumber) {
public void onCallStateChanged(int state) {
if (mCallState == state) return;
if (DEBUG) Log.v(TAG, "Call state changed: " + state);
mCallState = state;

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2021 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.systemui.telephony;
import android.telephony.ServiceState;
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import android.telephony.TelephonyCallback.CallStateListener;
import android.telephony.TelephonyCallback.ServiceStateListener;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
class TelephonyCallback extends android.telephony.TelephonyCallback
implements ActiveDataSubscriptionIdListener, CallStateListener, ServiceStateListener {
private final List<ActiveDataSubscriptionIdListener> mActiveDataSubscriptionIdListeners =
new ArrayList<>();
private final List<CallStateListener> mCallStateListeners = new ArrayList<>();
private final List<ServiceStateListener> mServiceStateListeners = new ArrayList<>();
@Inject
TelephonyCallback() {
}
boolean hasAnyListeners() {
return !mActiveDataSubscriptionIdListeners.isEmpty()
|| !mCallStateListeners.isEmpty()
|| !mServiceStateListeners.isEmpty();
}
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
mActiveDataSubscriptionIdListeners.forEach(listener -> {
listener.onActiveDataSubscriptionIdChanged(subId);
});
}
void addActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) {
mActiveDataSubscriptionIdListeners.add(listener);
}
void removeActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) {
mActiveDataSubscriptionIdListeners.remove(listener);
}
@Override
public void onCallStateChanged(int state) {
mCallStateListeners.forEach(listener -> {
listener.onCallStateChanged(state);
});
}
void addCallStateListener(CallStateListener listener) {
mCallStateListeners.add(listener);
}
void removeCallStateListener(CallStateListener listener) {
mCallStateListeners.remove(listener);
}
@Override
public void onServiceStateChanged(@NonNull ServiceState serviceState) {
mServiceStateListeners.forEach(listener -> {
listener.onServiceStateChanged(serviceState);
});
}
void addServiceStateListener(ServiceStateListener listener) {
mServiceStateListeners.add(listener);
}
void removeServiceStateListener(ServiceStateListener listener) {
mServiceStateListeners.remove(listener);
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2021 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.systemui.telephony;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import android.telephony.TelephonyCallback.CallStateListener;
import android.telephony.TelephonyCallback.ServiceStateListener;
import android.telephony.TelephonyManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import java.util.concurrent.Executor;
import javax.inject.Inject;
/**
* Wrapper around {@link TelephonyManager#listen(PhoneStateListener, int)}.
*
* The TelephonyManager complains if too many places in code register a listener. This class
* encapsulates SystemUI's usage of this function, reducing it down to a single listener.
*
* See also
* {@link TelephonyManager#registerTelephonyCallback(Executor, android.telephony.TelephonyCallback)}
*/
@SysUISingleton
public class TelephonyListenerManager {
private final TelephonyManager mTelephonyManager;
private final Executor mExecutor;
private final TelephonyCallback mTelephonyCallback;
private boolean mListening = false;
@Inject
public TelephonyListenerManager(TelephonyManager telephonyManager, @Main Executor executor,
TelephonyCallback telephonyCallback) {
mTelephonyManager = telephonyManager;
mExecutor = executor;
mTelephonyCallback = telephonyCallback;
}
/** */
public void addActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) {
mTelephonyCallback.addActiveDataSubscriptionIdListener(listener);
updateListening();
}
/** */
public void removeActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) {
mTelephonyCallback.removeActiveDataSubscriptionIdListener(listener);
updateListening();
}
/** */
public void addCallStateListener(CallStateListener listener) {
mTelephonyCallback.addCallStateListener(listener);
updateListening();
}
/** */
public void removeCallStateListener(CallStateListener listener) {
mTelephonyCallback.removeCallStateListener(listener);
updateListening();
}
/** */
public void addServiceStateListener(ServiceStateListener listener) {
mTelephonyCallback.addServiceStateListener(listener);
updateListening();
}
/** */
public void removeServiceStateListener(ServiceStateListener listener) {
mTelephonyCallback.removeServiceStateListener(listener);
updateListening();
}
private void updateListening() {
if (!mListening && mTelephonyCallback.hasAnyListeners()) {
mListening = true;
mTelephonyManager.registerTelephonyCallback(mExecutor, mTelephonyCallback);
} else if (mListening && !mTelephonyCallback.hasAnyListeners()) {
mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
mListening = false;
}
}
}

View File

@@ -21,12 +21,13 @@ import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.DATA_ROAMING_ENABLE;
import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -40,10 +41,6 @@ import static org.mockito.Mockito.when;
import android.content.pm.PackageManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
import android.provider.Settings;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
@@ -51,13 +48,14 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.text.TextUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -73,7 +71,6 @@ import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class CarrierTextControllerTest extends SysuiTestCase {
private static final CharSequence SEPARATOR = " \u2014 ";
@@ -103,24 +100,25 @@ public class CarrierTextControllerTest extends SysuiTestCase {
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private TelephonyListenerManager mTelephonyListenerManager;
private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
private FakeExecutor mBgExecutor = new FakeExecutor(mFakeSystemClock);
@Mock
private SubscriptionManager mSubscriptionManager;
private CarrierTextController.CarrierTextCallbackInfo mCarrierTextCallbackInfo;
private CarrierTextController mCarrierTextController;
private TestableLooper mTestableLooper;
private Void checkMainThread(InvocationOnMock inv) {
Looper mainLooper = Dependency.get(Dependency.MAIN_HANDLER).getLooper();
if (!mainLooper.isCurrentThread()) {
fail("This call should be done from the main thread");
}
assertThat(mMainExecutor.isExecuting()).isTrue();
assertThat(mBgExecutor.isExecuting()).isFalse();
return null;
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
mContext.addMockSystemService(WifiManager.class, mWifiManager);
mContext.addMockSystemService(PackageManager.class, mPackageManager);
@@ -132,9 +130,6 @@ public class CarrierTextControllerTest extends SysuiTestCase {
mContext.getOrCreateTestableResources().addOverride(
R.string.airplane_mode, AIRPLANE_MODE_TEXT);
mDependency.injectMockDependency(WakefulnessLifecycle.class);
mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
new Handler(mTestableLooper.getLooper()));
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
doAnswer(this::checkMainThread).when(mKeyguardUpdateMonitor)
@@ -147,30 +142,21 @@ public class CarrierTextControllerTest extends SysuiTestCase {
when(mTelephonyManager.getSupportedModemCount()).thenReturn(3);
when(mTelephonyManager.getActiveModemCount()).thenReturn(3);
mCarrierTextController = new CarrierTextController(mContext, SEPARATOR, true, true);
mCarrierTextController = new CarrierTextController(
mContext, SEPARATOR, true, true,
mTelephonyManager, mTelephonyListenerManager, mMainExecutor,
mBgExecutor);
// This should not start listening on any of the real dependencies but will test that
// callbacks in mKeyguardUpdateMonitor are done in the mTestableLooper thread
mCarrierTextController.setListening(mCarrierTextCallback);
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
}
@Test
public void testKeyguardUpdateMonitorCalledInMainThread() throws Exception {
// This test will run on the main looper (which is not the same as the looper set as MAIN
// for CarrierTextCallback. This will fail if calls to mKeyguardUpdateMonitor are not done
// through the looper set in the set up
HandlerThread thread = new HandlerThread("testThread",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
TestableLooper testableLooper = new TestableLooper(thread.getLooper());
Handler h = new Handler(testableLooper.getLooper());
h.post(() -> {
mCarrierTextController.setListening(null);
mCarrierTextController.setListening(mCarrierTextCallback);
});
testableLooper.processAllMessages();
mTestableLooper.processAllMessages();
thread.quitSafely();
mCarrierTextController.setListening(null);
mCarrierTextController.setListening(mCarrierTextCallback);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
}
@Test
@@ -189,7 +175,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(
CarrierTextController.CarrierTextCallbackInfo.class);
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
assertEquals(AIRPLANE_MODE_TEXT, captor.getValue().carrierText);
}
@@ -212,7 +198,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(
CarrierTextController.CarrierTextCallbackInfo.class);
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
assertEquals("TEST_CARRIER" + SEPARATOR + INVALID_CARD_TEXT, captor.getValue().carrierText);
// There's only one subscription in the list
@@ -224,7 +210,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
when(mTelephonyManager.getActiveModemCount()).thenReturn(1);
// Update carrier text. It should ignore error state of subId 3 in inactive slotId.
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
assertEquals("TEST_CARRIER", captor.getValue().carrierText);
}
@@ -260,7 +246,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
mCarrierTextController.mCallback.onSimStateChanged(0, 1,
TelephonyManager.SIM_STATE_CARD_IO_ERROR);
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(
any(CarrierTextController.CarrierTextCallbackInfo.class));
}
@@ -269,7 +255,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
public void testCallback() {
reset(mCarrierTextCallback);
mCarrierTextController.postToCallback(mCarrierTextCallbackInfo);
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor.forClass(
@@ -286,7 +272,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
mCarrierTextController.setListening(null);
// This shouldn't produce NPE
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(any());
}
@@ -306,7 +292,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
CarrierTextController.CarrierTextCallbackInfo.class);
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
CarrierTextController.CarrierTextCallbackInfo info = captor.getValue();
@@ -331,7 +317,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
CarrierTextController.CarrierTextCallbackInfo.class);
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
CarrierTextController.CarrierTextCallbackInfo info = captor.getValue();
@@ -356,7 +342,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
CarrierTextController.CarrierTextCallbackInfo.class);
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
assertTrue("Carrier text should be empty, instead it's " + captor.getValue().carrierText,
@@ -385,7 +371,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
CarrierTextController.CarrierTextCallbackInfo.class);
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
assertFalse("No SIM should be available", captor.getValue().anySimReady);
@@ -412,7 +398,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
CarrierTextController.CarrierTextCallbackInfo.class);
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
CarrierTextController.CarrierTextCallbackInfo info = captor.getValue();
@@ -438,7 +424,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
CarrierTextController.CarrierTextCallbackInfo.class);
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER,
@@ -463,7 +449,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
CarrierTextController.CarrierTextCallbackInfo.class);
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
assertEquals(TEST_CARRIER,
@@ -488,7 +474,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
CarrierTextController.CarrierTextCallbackInfo.class);
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
assertEquals(TEST_CARRIER,
@@ -514,7 +500,7 @@ public class CarrierTextControllerTest extends SysuiTestCase {
CarrierTextController.CarrierTextCallbackInfo.class);
mCarrierTextController.updateCarrierText();
mTestableLooper.processAllMessages();
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER,

View File

@@ -88,6 +88,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.RingerModeTracker;
import org.junit.After;
@@ -163,6 +164,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Mock
private AuthController mAuthController;
@Mock
private TelephonyListenerManager mTelephonyListenerManager;
@Mock
private FeatureFlags mFeatureFlags;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
@@ -883,7 +886,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mBroadcastDispatcher, mDumpManager,
mRingerModeTracker, mBackgroundExecutor,
mStatusBarStateController, mLockPatternUtils,
mAuthController, mFeatureFlags);
mAuthController, mTelephonyListenerManager, mFeatureFlags);
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}

View File

@@ -43,7 +43,6 @@ import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
import android.service.dreams.IDreamManager;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.IWindowManager;
@@ -75,6 +74,7 @@ import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.RingerModeLiveData;
import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.settings.SecureSettings;
@@ -106,7 +106,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
@Mock private LockPatternUtils mLockPatternUtils;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private ConnectivityManager mConnectivityManager;
@Mock private TelephonyManager mTelephonyManager;
@Mock private TelephonyListenerManager mTelephonyListenerManager;
@Mock private ContentResolver mContentResolver;
@Mock private Resources mResources;
@Mock private ConfigurationController mConfigurationController;
@@ -167,7 +167,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
mLockPatternUtils,
mBroadcastDispatcher,
mConnectivityManager,
mTelephonyManager,
mTelephonyListenerManager,
mContentResolver,
null,
mResources,

View File

@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.telephony.TelephonyListenerManager;
import org.junit.After;
import org.junit.Before;
@@ -113,6 +114,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected NetworkScoreManager mMockNsm;
protected SubscriptionManager mMockSm;
protected TelephonyManager mMockTm;
protected TelephonyListenerManager mTelephonyListenerManager;
protected BroadcastDispatcher mMockBd;
protected Config mConfig;
protected CallbackHandler mCallbackHandler;
@@ -164,6 +166,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
mDemoModeController = mock(DemoModeController.class);
mMockWm = mock(WifiManager.class);
mMockTm = mock(TelephonyManager.class);
mTelephonyListenerManager = mock(TelephonyListenerManager.class);
mMockSm = mock(SubscriptionManager.class);
mMockCm = mock(ConnectivityManager.class);
mMockBd = mock(BroadcastDispatcher.class);
@@ -213,6 +216,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
mNetworkController = new NetworkControllerImpl(mContext,
mMockCm,
mMockTm,
mTelephonyListenerManager,
mMockWm,
mMockNsm,
mMockSm,
@@ -285,7 +289,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected NetworkControllerImpl setUpNoMobileData() {
when(mMockTm.isDataCapable()).thenReturn(false);
NetworkControllerImpl networkControllerNoMobile =
new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockNsm, mMockSm,
new NetworkControllerImpl(mContext, mMockCm, mMockTm, mTelephonyListenerManager,
mMockWm, mMockNsm, mMockSm,
mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,

View File

@@ -106,7 +106,8 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
public void test4gDataIcon() {
// Switch to showing 4g icon and re-initialize the NetworkController.
mConfig.show4gForLte = true;
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm,
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
mTelephonyListenerManager, mMockWm,
mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,

View File

@@ -61,8 +61,9 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
// Turn off mobile network support.
when(mMockTm.isDataCapable()).thenReturn(false);
// Create a new NetworkController as this is currently handled in constructor.
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm,
mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler,
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig,
Looper.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
mDemoModeController);
@@ -80,8 +81,9 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
when(mMockTm.getServiceState()).thenReturn(mServiceState);
when(mMockSm.getCompleteActiveSubscriptionInfoList()).thenReturn(Collections.emptyList());
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm,
mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler,
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig,
Looper.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
mDemoModeController);
@@ -147,8 +149,9 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
// Turn off mobile network support.
when(mMockTm.isDataCapable()).thenReturn(false);
// Create a new NetworkController as this is currently handled in constructor.
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm,
mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler,
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig,
Looper.getMainLooper(), mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
mDemoModeController);

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2021 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.systemui.telephony;
import static com.google.common.truth.Truth.assertThat;
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import android.telephony.TelephonyCallback.CallStateListener;
import android.telephony.TelephonyCallback.ServiceStateListener;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TelephonyCallbackTest extends SysuiTestCase {
private TelephonyCallback mTelephonyCallback = new TelephonyCallback();
@Test
public void testAddListener_ActiveDataSubscriptionIdListener() {
assertThat(mTelephonyCallback.hasAnyListeners()).isFalse();
mTelephonyCallback.addActiveDataSubscriptionIdListener(subId -> {});
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
mTelephonyCallback.addActiveDataSubscriptionIdListener(subId -> {});
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
}
@Test
public void testAddListener_CallStateListener() {
assertThat(mTelephonyCallback.hasAnyListeners()).isFalse();
mTelephonyCallback.addCallStateListener(state -> {});
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
mTelephonyCallback.addCallStateListener(state -> {});
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
}
@Test
public void testAddListener_ServiceStateListener() {
assertThat(mTelephonyCallback.hasAnyListeners()).isFalse();
mTelephonyCallback.addServiceStateListener(serviceState -> {});
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
mTelephonyCallback.addServiceStateListener(serviceState -> {});
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
}
@Test
public void testRemoveListener_ActiveDataSubscriptionIdListener() {
ActiveDataSubscriptionIdListener listener = subId -> {};
mTelephonyCallback.addActiveDataSubscriptionIdListener(listener);
mTelephonyCallback.addActiveDataSubscriptionIdListener(listener);
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
mTelephonyCallback.removeActiveDataSubscriptionIdListener(listener);
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
mTelephonyCallback.removeActiveDataSubscriptionIdListener(listener);
assertThat(mTelephonyCallback.hasAnyListeners()).isFalse();
}
@Test
public void testRemoveListener_CallStateListener() {
CallStateListener listener = state -> {};
mTelephonyCallback.addCallStateListener(listener);
mTelephonyCallback.addCallStateListener(listener);
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
mTelephonyCallback.removeCallStateListener(listener);
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
mTelephonyCallback.removeCallStateListener(listener);
assertThat(mTelephonyCallback.hasAnyListeners()).isFalse();
}
@Test
public void testRemoveListener_ServiceStateListener() {
ServiceStateListener listener = serviceState -> {};
mTelephonyCallback.addServiceStateListener(listener);
mTelephonyCallback.addServiceStateListener(listener);
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
mTelephonyCallback.removeServiceStateListener(listener);
assertThat(mTelephonyCallback.hasAnyListeners()).isTrue();
mTelephonyCallback.removeServiceStateListener(listener);
assertThat(mTelephonyCallback.hasAnyListeners()).isFalse();
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright (C) 2021 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.systemui.telephony;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import android.telephony.TelephonyCallback.CallStateListener;
import android.telephony.TelephonyCallback.ServiceStateListener;
import android.telephony.TelephonyManager;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TelephonyListenerManagerTest extends SysuiTestCase {
@Mock
private TelephonyManager mTelephonyManager;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
@Mock
private TelephonyCallback mTelephonyCallback;
TelephonyListenerManager mTelephonyListenerManager;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mTelephonyListenerManager = new TelephonyListenerManager(
mTelephonyManager, mExecutor, mTelephonyCallback);
}
@Test
public void testAddListenerRegisters_ActiveDataSubscriptionIdListener() {
when(mTelephonyCallback.hasAnyListeners()).thenReturn(true);
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {});
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {});
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {});
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {});
verify(mTelephonyManager, times(1))
.registerTelephonyCallback(mExecutor, mTelephonyCallback);
}
@Test
public void testAddListenerRegisters_CallStateListener() {
when(mTelephonyCallback.hasAnyListeners()).thenReturn(true);
mTelephonyListenerManager.addCallStateListener(state -> {});
mTelephonyListenerManager.addCallStateListener(state -> {});
mTelephonyListenerManager.addCallStateListener(state -> {});
mTelephonyListenerManager.addCallStateListener(state -> {});
verify(mTelephonyManager, times(1))
.registerTelephonyCallback(mExecutor, mTelephonyCallback);
}
@Test
public void testAddListenerRegisters_ServiceStateListener() {
when(mTelephonyCallback.hasAnyListeners()).thenReturn(true);
mTelephonyListenerManager.addServiceStateListener(serviceState -> {});
mTelephonyListenerManager.addServiceStateListener(serviceState -> {});
mTelephonyListenerManager.addServiceStateListener(serviceState -> {});
mTelephonyListenerManager.addServiceStateListener(serviceState -> {});
verify(mTelephonyManager, times(1))
.registerTelephonyCallback(mExecutor, mTelephonyCallback);
}
@Test
public void testAddListenerRegisters_mixed() {
when(mTelephonyCallback.hasAnyListeners()).thenReturn(true);
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {});
mTelephonyListenerManager.addCallStateListener(state -> {});
mTelephonyListenerManager.addServiceStateListener(serviceState -> {});
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {});
mTelephonyListenerManager.addCallStateListener(state -> {});
mTelephonyListenerManager.addServiceStateListener(serviceState -> {});
verify(mTelephonyManager, times(1))
.registerTelephonyCallback(mExecutor, mTelephonyCallback);
}
@Test
public void testRemoveListenerUnregisters_ActiveDataSubscriptionIdListener() {
when(mTelephonyCallback.hasAnyListeners()).thenReturn(true);
ActiveDataSubscriptionIdListener mListener = subId -> { };
// Need to add one to actually register
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mListener);
verify(mTelephonyManager, times(1))
.registerTelephonyCallback(mExecutor, mTelephonyCallback);
reset(mTelephonyManager);
when(mTelephonyCallback.hasAnyListeners()).thenReturn(false);
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListener);
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListener);
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListener);
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListener);
verify(mTelephonyManager, times(1))
.unregisterTelephonyCallback(mTelephonyCallback);
}
@Test
public void testRemoveListenerUnregisters_CallStateListener() {
when(mTelephonyCallback.hasAnyListeners()).thenReturn(true);
CallStateListener mListener = state -> { };
// Need to add one to actually register
mTelephonyListenerManager.addCallStateListener(mListener);
verify(mTelephonyManager, times(1))
.registerTelephonyCallback(mExecutor, mTelephonyCallback);
reset(mTelephonyManager);
when(mTelephonyCallback.hasAnyListeners()).thenReturn(false);
mTelephonyListenerManager.removeCallStateListener(mListener);
mTelephonyListenerManager.removeCallStateListener(mListener);
mTelephonyListenerManager.removeCallStateListener(mListener);
mTelephonyListenerManager.removeCallStateListener(mListener);
verify(mTelephonyManager, times(1))
.unregisterTelephonyCallback(mTelephonyCallback);
}
@Test
public void testRemoveListenerUnregisters_ServiceStateListener() {
when(mTelephonyCallback.hasAnyListeners()).thenReturn(true);
ServiceStateListener mListener = serviceState -> { };
// Need to add one to actually register
mTelephonyListenerManager.addServiceStateListener(mListener);
verify(mTelephonyManager, times(1))
.registerTelephonyCallback(mExecutor, mTelephonyCallback);
reset(mTelephonyManager);
when(mTelephonyCallback.hasAnyListeners()).thenReturn(false);
mTelephonyListenerManager.removeServiceStateListener(mListener);
mTelephonyListenerManager.removeServiceStateListener(mListener);
mTelephonyListenerManager.removeServiceStateListener(mListener);
mTelephonyListenerManager.removeServiceStateListener(mListener);
verify(mTelephonyManager, times(1))
.unregisterTelephonyCallback(mTelephonyCallback);
}
@Test
public void testRemoveListenerUnregisters_mixed() {
when(mTelephonyCallback.hasAnyListeners()).thenReturn(true);
ActiveDataSubscriptionIdListener mListenerA = subId -> { };
ServiceStateListener mListenerB = serviceState -> { };
CallStateListener mListenerC = state -> { };
// Need to add one to actually register
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mListenerA);
verify(mTelephonyManager, times(1))
.registerTelephonyCallback(mExecutor, mTelephonyCallback);
reset(mTelephonyManager);
when(mTelephonyCallback.hasAnyListeners()).thenReturn(false);
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListenerA);
mTelephonyListenerManager.removeServiceStateListener(mListenerB);
mTelephonyListenerManager.removeCallStateListener(mListenerC);
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListenerA);
mTelephonyListenerManager.removeServiceStateListener(mListenerB);
mTelephonyListenerManager.removeCallStateListener(mListenerC);
verify(mTelephonyManager, times(1))
.unregisterTelephonyCallback(mTelephonyCallback);
}
@Test
public void testAddListener_noDoubleRegister() {
when(mTelephonyCallback.hasAnyListeners()).thenReturn(true);
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {});
verify(mTelephonyManager, times(1))
.registerTelephonyCallback(mExecutor, mTelephonyCallback);
reset(mTelephonyManager);
// A second call to add doesn't register another listener.
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {});
verify(mTelephonyManager, never()).registerTelephonyCallback(mExecutor, mTelephonyCallback);
}
}

View File

@@ -27,6 +27,7 @@ public class FakeExecutor implements DelayableExecutor {
private final FakeSystemClock mClock;
private PriorityQueue<QueuedRunnable> mQueuedRunnables = new PriorityQueue<>();
private boolean mIgnoreClockUpdates;
private boolean mExecuting;
/**
* Initializes a fake executor.
@@ -56,7 +57,9 @@ public class FakeExecutor implements DelayableExecutor {
*/
public boolean runNextReady() {
if (!mQueuedRunnables.isEmpty() && mQueuedRunnables.peek().mWhen <= mClock.uptimeMillis()) {
mExecuting = true;
mQueuedRunnables.poll().mRunnable.run();
mExecuting = false;
return true;
}
@@ -162,6 +165,10 @@ public class FakeExecutor implements DelayableExecutor {
executeDelayed(command, 0);
}
public boolean isExecuting() {
return mExecuting;
}
/**
* Run all Executors in a loop until they all report they have no ready work to do.
*

View File

@@ -16,6 +16,8 @@
package com.android.systemui.util.concurrency;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -319,6 +321,18 @@ public class FakeExecutorTest extends SysuiTestCase {
assertEquals(1, runnable.mRunCount);
}
@Test
public void testIsExecuting() {
FakeSystemClock clock = new FakeSystemClock();
FakeExecutor fakeExecutor = new FakeExecutor(clock);
Runnable runnable = () -> assertThat(fakeExecutor.isExecuting()).isTrue();
assertThat(fakeExecutor.isExecuting()).isFalse();
fakeExecutor.execute(runnable);
assertThat(fakeExecutor.isExecuting()).isFalse();
}
private static class RunnableImpl implements Runnable {
int mRunCount;