From deca9ea898151926fdb54b80b04a949b0e6f0e3b Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Mon, 22 Mar 2021 15:29:20 -0400 Subject: [PATCH 1/7] 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 --- .../src/com/android/keyguard/CarrierText.java | 7 +- .../keyguard/CarrierTextController.java | 77 ++++--- .../keyguard/KeyguardUpdateMonitor.java | 15 +- .../src/com/android/systemui/Dependency.java | 3 + .../globalactions/GlobalActionsDialog.java | 11 +- .../policy/NetworkControllerImpl.java | 45 ++-- .../policy/UserSwitcherController.java | 18 +- .../systemui/telephony/TelephonyCallback.java | 93 ++++++++ .../telephony/TelephonyListenerManager.java | 103 +++++++++ .../keyguard/CarrierTextControllerTest.java | 84 +++---- .../keyguard/KeyguardUpdateMonitorTest.java | 5 +- .../GlobalActionsDialogTest.java | 6 +- .../policy/NetworkControllerBaseTest.java | 7 +- .../policy/NetworkControllerDataTest.java | 3 +- .../policy/NetworkControllerSignalTest.java | 15 +- .../telephony/TelephonyCallbackTest.java | 102 +++++++++ .../TelephonyListenerManagerTest.java | 209 ++++++++++++++++++ .../util/concurrency/FakeExecutor.java | 7 + .../util/concurrency/FakeExecutorTest.java | 14 ++ 19 files changed, 690 insertions(+), 134 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java create mode 100644 packages/SystemUI/src/com/android/systemui/telephony/TelephonyListenerManager.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyCallbackTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java index f6b03c1fa0131..f1c044c0b5e6c 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java @@ -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. } diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index d52a25139ce75..a85d96f133b1d 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -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 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); } } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 69e6ed043172d..9abc1e7adf864 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -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 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); diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 06b486ec43d0b..a686fc086b401 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -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 mMediaOutputDialogFactory; @Inject Lazy mDeviceConfigProxy; @Inject Lazy mNavbarButtonsControllerLazy; + @Inject Lazy 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 diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 553e5a7c6d7dd..18627189f1884 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -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; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 8a86021423631..cfaeb0edec534 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -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(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index d4029e64036ed..d05d972a50e6b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -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 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; diff --git a/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java new file mode 100644 index 0000000000000..3bc26322e6cd1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java @@ -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 mActiveDataSubscriptionIdListeners = + new ArrayList<>(); + private final List mCallStateListeners = new ArrayList<>(); + private final List 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); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/telephony/TelephonyListenerManager.java b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyListenerManager.java new file mode 100644 index 0000000000000..4e1accacfb7f1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyListenerManager.java @@ -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; + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index 6f2c0af5384df..c54620248ceb3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -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 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, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 52e2016d6f0ed..160dae5799644 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -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 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); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java index eedf09936b4d0..8add93032caa5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java @@ -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, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 8f36415d60afa..ef3317288e4ce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -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, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index b108dd817bde5..f4ad819acf571 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -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, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 91e9f0622cbf8..3c5cbb69eef6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -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); diff --git a/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyCallbackTest.java new file mode 100644 index 0000000000000..463b33602c150 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyCallbackTest.java @@ -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(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java new file mode 100644 index 0000000000000..0d1ac7b96f0e8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java @@ -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); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java index 7c7ad5322d48d..d3d30f242dcff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java @@ -27,6 +27,7 @@ public class FakeExecutor implements DelayableExecutor { private final FakeSystemClock mClock; private PriorityQueue 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. * diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java index abc283f40b1c2..87206c5b1c80d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java @@ -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; From 78418476c4ad43503280038d1573e0f6a53004df Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Fri, 19 Feb 2021 16:38:09 +0000 Subject: [PATCH 2/7] Revert^2 "Add ViewController to CarrierText." 831715fdc26ac7d2a72bf6f471bba54a1bf1eda6 Change-Id: I4df58754737d1badccecc97bc3b27d8c3c09bbc8 --- .../src/com/android/keyguard/CarrierText.java | 70 +- .../keyguard/CarrierTextController.java | 707 +---------------- .../android/keyguard/CarrierTextManager.java | 721 ++++++++++++++++++ .../KeyguardStatusBarViewComponent.java | 42 + .../dagger/KeyguardStatusBarViewModule.java | 34 + .../dagger/KeyguardStatusBarViewScope.java | 32 + .../dagger/KeyguardStatusViewComponent.java | 2 + .../keyguard/dagger/KeyguardModule.java | 8 +- .../qs/carrier/QSCarrierGroupController.java | 29 +- .../KeyguardStatusBarViewController.java | 48 ++ .../NotificationPanelViewController.java | 22 +- ...rTest.java => CarrierTextManagerTest.java} | 126 +-- .../carrier/QSCarrierGroupControllerTest.java | 54 +- .../phone/NotificationPanelViewTest.java | 12 + 14 files changed, 1071 insertions(+), 836 deletions(-) create mode 100644 packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java create mode 100644 packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java create mode 100644 packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java create mode 100644 packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java rename packages/SystemUI/tests/src/com/android/keyguard/{CarrierTextControllerTest.java => CarrierTextManagerTest.java} (82%) diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java index f1c044c0b5e6c..e4f6e131258e3 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java @@ -18,49 +18,20 @@ 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; import android.view.View; import android.widget.TextView; -import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.telephony.TelephonyListenerManager; import java.util.Locale; public class CarrierText extends TextView { - private static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final String TAG = "CarrierText"; + private final boolean mShowMissingSim; - private static CharSequence mSeparator; - - private boolean mShowMissingSim; - - private boolean mShowAirplaneMode; - private boolean mShouldMarquee; - - private CarrierTextController mCarrierTextController; - - private CarrierTextController.CarrierTextCallback mCarrierTextCallback = - new CarrierTextController.CarrierTextCallback() { - @Override - public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { - setText(info.carrierText); - } - - @Override - public void startedGoingToSleep() { - setSelected(false); - } - - @Override - public void finishedWakingUp() { - setSelected(true); - } - }; + private final boolean mShowAirplaneMode; public CarrierText(Context context) { this(context, null); @@ -80,33 +51,6 @@ public class CarrierText extends TextView { } setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps)); } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mSeparator = getResources().getString( - com.android.internal.R.string.kg_text_message_separator); - mCarrierTextController = new CarrierTextController(mContext, mSeparator, mShowAirplaneMode, - 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. - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mCarrierTextController.setListening(mCarrierTextCallback); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mCarrierTextController.setListening(null); - } - @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); @@ -118,7 +62,15 @@ public class CarrierText extends TextView { } } - private class CarrierTextTransformationMethod extends SingleLineTransformationMethod { + public boolean getShowAirplaneMode() { + return mShowAirplaneMode; + } + + public boolean getShowMissingSim() { + return mShowMissingSim; + } + + private static class CarrierTextTransformationMethod extends SingleLineTransformationMethod { private final Locale mLocale; private final boolean mAllCaps; diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index a85d96f133b1d..997c5275a2fa7 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -16,693 +16,60 @@ package com.android.keyguard; -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.telephony.ServiceState; -import android.telephony.SubscriptionInfo; -import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.Nullable; -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 com.android.systemui.util.ViewController; import javax.inject.Inject; /** - * Controller that generates text including the carrier names and/or the status of all the SIM - * interfaces in the device. Through a callback, the updates can be retrieved either as a list or - * separated by a given separator {@link CharSequence}. + * Controller for {@link CarrierText}. */ -public class CarrierTextController { - private static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final String TAG = "CarrierTextController"; - - private final boolean mIsEmergencyCallCapable; - private boolean mTelephonyCapable; - private boolean mShowMissingSim; - private boolean mShowAirplaneMode; - private final AtomicBoolean mNetworkSupported = new AtomicBoolean(); - @VisibleForTesting - protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; - private WifiManager mWifiManager; - private boolean[] mSimErrorState; - private final int mSimSlotsNumber; - @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 = - new WakefulnessLifecycle.Observer() { +public class CarrierTextController extends ViewController { + private final CarrierTextManager mCarrierTextManager; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final CarrierTextManager.CarrierTextCallback mCarrierTextCallback = + new CarrierTextManager.CarrierTextCallback() { @Override - public void onFinishedWakingUp() { - final CarrierTextCallback callback = mCarrierTextCallback; - if (callback != null) callback.finishedWakingUp(); + public void updateCarrierInfo(CarrierTextManager.CarrierTextCallbackInfo info) { + mView.setText(info.carrierText); } @Override - public void onStartedGoingToSleep() { - final CarrierTextCallback callback = mCarrierTextCallback; - if (callback != null) callback.startedGoingToSleep(); + public void startedGoingToSleep() { + mView.setSelected(false); + } + + @Override + public void finishedWakingUp() { + mView.setSelected(true); } }; - @VisibleForTesting - protected final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { - @Override - public void onRefreshCarrierInfo() { - if (DEBUG) { - Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: " - + Boolean.toString(mTelephonyCapable)); - } - updateCarrierText(); - } + @Inject + public CarrierTextController(CarrierText view, + CarrierTextManager.Builder carrierTextManagerBuilder, + KeyguardUpdateMonitor keyguardUpdateMonitor) { + super(view); - @Override - public void onTelephonyCapable(boolean capable) { - if (DEBUG) { - Log.d(TAG, "onTelephonyCapable() mTelephonyCapable: " - + Boolean.toString(capable)); - } - mTelephonyCapable = capable; - updateCarrierText(); - } - - public void onSimStateChanged(int subId, int slotId, int simState) { - if (slotId < 0 || slotId >= mSimSlotsNumber) { - Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId - + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable)); - return; - } - - if (DEBUG) Log.d(TAG, "onSimStateChanged: " + getStatusForIccState(simState)); - if (getStatusForIccState(simState) == CarrierTextController.StatusMode.SimIoError) { - mSimErrorState[slotId] = true; - updateCarrierText(); - } else if (mSimErrorState[slotId]) { - mSimErrorState[slotId] = false; - updateCarrierText(); - } - } - }; - - private final ActiveDataSubscriptionIdListener mPhoneStateListener = - new ActiveDataSubscriptionIdListener() { - @Override - public void onActiveDataSubscriptionIdChanged(int subId) { - if (mNetworkSupported.get() && mCarrierTextCallback != null) { - updateCarrierText(); - } - } - }; - - /** - * The status of this lock screen. Primarily used for widgets on LockScreen. - */ - private enum StatusMode { - Normal, // Normal case (sim card present, it's not locked) - NetworkLocked, // SIM card is 'network locked'. - SimMissing, // SIM card is missing. - SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access - SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times - SimLocked, // SIM card is currently locked - SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure - SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM. - SimIoError, // SIM card is faulty - SimUnknown // SIM card is unknown + mCarrierTextManager = carrierTextManagerBuilder + .setShowAirplaneMode(mView.getShowAirplaneMode()) + .setShowMissingSim(mView.getShowMissingSim()) + .build(); + mKeyguardUpdateMonitor = keyguardUpdateMonitor; } - /** - * Controller that provides updates on text with carriers names or SIM status. - * Used by {@link CarrierText}. - * - * @param separator Separator between different parts of the text - */ - public CarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode, - boolean showMissingSim, TelephonyManager telephonyManager, - TelephonyListenerManager telephonyListenerManager, - @Main Executor mainExecutor, @Background Executor bgExecutor) { - mContext = context; - mTelephonyManager = telephonyManager; - mTelephonyListenerManager = telephonyListenerManager; - mMainExecutor = mainExecutor; - mBgExecutor = bgExecutor; - mIsEmergencyCallCapable = mTelephonyManager.isVoiceCapable(); - - mShowAirplaneMode = showAirplaneMode; - mShowMissingSim = showMissingSim; - - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - mSeparator = separator; - mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); - mSimSlotsNumber = mTelephonyManager.getSupportedModemCount(); - mSimErrorState = new boolean[mSimSlotsNumber]; - mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); - mBgExecutor.execute(() -> { - boolean supported = - mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY); - if (supported && mNetworkSupported.compareAndSet(false, supported)) { - // This will set/remove the listeners appropriately. Note that it will never double - // add the listeners. - handleSetListening(mCarrierTextCallback); - } - }); + @Override + protected void onInit() { + super.onInit(); + mView.setSelected(mKeyguardUpdateMonitor.isDeviceInteractive()); } - private TelephonyManager getTelephonyManager() { - return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + @Override + protected void onViewAttached() { + mCarrierTextManager.setListening(mCarrierTextCallback); } - /** - * Checks if there are faulty cards. Adds the text depending on the slot of the card - * - * @param text: current carrier text based on the sim state - * @param carrierNames names order by subscription order - * @param subOrderBySlot array containing the sub index for each slot ID - * @param noSims: whether a valid sim card is inserted - * @return text - */ - private CharSequence updateCarrierTextWithSimIoError(CharSequence text, - CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) { - final CharSequence carrier = ""; - 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 < mTelephonyManager.getActiveModemCount(); index++) { - if (!mSimErrorState[index]) { - continue; - } - // In the case when no sim cards are detected but a faulty card is inserted - // overwrite the text and only show "Invalid card" - if (noSims) { - return concatenate(carrierTextForSimIOError, - getContext().getText( - com.android.internal.R.string.emergency_calls_only), - mSeparator); - } else if (subOrderBySlot[index] != -1) { - int subIndex = subOrderBySlot[index]; - // prepend "Invalid card" when faulty card is inserted in slot 0 or 1 - carrierNames[subIndex] = concatenate(carrierTextForSimIOError, - carrierNames[subIndex], - mSeparator); - } else { - // concatenate "Invalid card" when faulty card is inserted in other slot - text = concatenate(text, carrierTextForSimIOError, mSeparator); - } - - } - return text; - } - - /** - * This may be called internally after retrieving the correct value of {@code mNetworkSupported} - * (assumed false to start). In that case, the following happens: - *
    - *
  • If there was a registered callback, and the network is supported, it will register - * listeners. - *
  • If there was not a registered callback, it will try to remove unregistered listeners - * which is a no-op - *
- * - * This call will always be processed in a background thread. - */ - private void handleSetListening(CarrierTextCallback callback) { - if (callback != null) { - mCarrierTextCallback = callback; - if (mNetworkSupported.get()) { - // Keyguard update monitor expects callbacks from main thread - mMainExecutor.execute(() -> mKeyguardUpdateMonitor.registerCallback(mCallback)); - mWakefulnessLifecycle.addObserver(mWakefulnessObserver); - mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener); - } else { - // Don't listen and clear out the text when the device isn't a phone. - mMainExecutor.execute(() -> callback.updateCarrierInfo( - new CarrierTextCallbackInfo("", null, false, null) - )); - } - } else { - mCarrierTextCallback = null; - mMainExecutor.execute(() -> mKeyguardUpdateMonitor.removeCallback(mCallback)); - mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); - mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener); - } - } - - /** - * Sets the listening status of this controller. If the callback is null, it is set to - * not listening. - * - * @param callback Callback to provide text updates - */ - public void setListening(CarrierTextCallback callback) { - mBgExecutor.execute(() -> handleSetListening(callback)); - } - - protected List getSubscriptionInfo() { - return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); - } - - protected void updateCarrierText() { - boolean allSimsMissing = true; - boolean anySimReadyAndInService = false; - CharSequence displayText = null; - List subs = getSubscriptionInfo(); - - final int numSubs = subs.size(); - final int[] subsIds = new int[numSubs]; - // This array will contain in position i, the index of subscription in slot ID i. - // -1 if no subscription in that slot - final int[] subOrderBySlot = new int[mSimSlotsNumber]; - for (int i = 0; i < mSimSlotsNumber; i++) { - subOrderBySlot[i] = -1; - } - final CharSequence[] carrierNames = new CharSequence[numSubs]; - if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs); - - for (int i = 0; i < numSubs; i++) { - int subId = subs.get(i).getSubscriptionId(); - carrierNames[i] = ""; - subsIds[i] = subId; - subOrderBySlot[subs.get(i).getSimSlotIndex()] = i; - int simState = mKeyguardUpdateMonitor.getSimState(subId); - CharSequence carrierName = subs.get(i).getCarrierName(); - CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName); - if (DEBUG) { - Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName); - } - if (carrierTextForSimState != null) { - allSimsMissing = false; - carrierNames[i] = carrierTextForSimState; - } - if (simState == TelephonyManager.SIM_STATE_READY) { - ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); - if (ss != null && ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE) { - // hack for WFC (IWLAN) not turning off immediately once - // Wi-Fi is disassociated or disabled - if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN - || (mWifiManager.isWifiEnabled() - && mWifiManager.getConnectionInfo() != null - && mWifiManager.getConnectionInfo().getBSSID() != null)) { - if (DEBUG) { - Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss); - } - anySimReadyAndInService = true; - } - } - } - } - // Only create "No SIM card" if no cards with CarrierName && no wifi when some sim is READY - // This condition will also be true always when numSubs == 0 - if (allSimsMissing && !anySimReadyAndInService) { - if (numSubs != 0) { - // Shows "No SIM card | Emergency calls only" on devices that are voice-capable. - // This depends on mPlmn containing the text "Emergency calls only" when the radio - // has some connectivity. Otherwise, it should be null or empty and just show - // "No SIM card" - // Grab the first subscripton, because they all should contain the emergency text, - // described above. - displayText = makeCarrierStringOnEmergencyCapable( - getMissingSimMessage(), subs.get(0).getCarrierName()); - } else { - // We don't have a SubscriptionInfo to get the emergency calls only from. - // Grab it from the old sticky broadcast if possible instead. We can use it - // here because no subscriptions are active, so we don't have - // to worry about MSIM clashing. - CharSequence text = - getContext().getText(com.android.internal.R.string.emergency_calls_only); - Intent i = getContext().registerReceiver(null, - new IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)); - if (i != null) { - String spn = ""; - String plmn = ""; - if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false)) { - spn = i.getStringExtra(TelephonyManager.EXTRA_SPN); - } - if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false)) { - plmn = i.getStringExtra(TelephonyManager.EXTRA_PLMN); - } - if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn); - if (Objects.equals(plmn, spn)) { - text = plmn; - } else { - text = concatenate(plmn, spn, mSeparator); - } - } - displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text); - } - } - - if (TextUtils.isEmpty(displayText)) displayText = joinNotEmpty(mSeparator, carrierNames); - - displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, - allSimsMissing); - - boolean airplaneMode = false; - // APM (airplane mode) != no carrier state. There are carrier services - // (e.g. WFC = Wi-Fi calling) which may operate in APM. - if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) { - displayText = getAirplaneModeMessage(); - airplaneMode = true; - } - - final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( - displayText, - carrierNames, - !allSimsMissing, - subsIds, - airplaneMode); - postToCallback(info); - } - - @VisibleForTesting - protected void postToCallback(CarrierTextCallbackInfo info) { - final CarrierTextCallback callback = mCarrierTextCallback; - if (callback != null) { - mMainExecutor.execute(() -> callback.updateCarrierInfo(info)); - } - } - - private Context getContext() { - return mContext; - } - - private String getMissingSimMessage() { - return mShowMissingSim && mTelephonyCapable - ? getContext().getString(R.string.keyguard_missing_sim_message_short) : ""; - } - - private String getAirplaneModeMessage() { - return mShowAirplaneMode - ? getContext().getString(R.string.airplane_mode) : ""; - } - - /** - * Top-level function for creating carrier text. Makes text based on simState, PLMN - * and SPN as well as device capabilities, such as being emergency call capable. - * - * @return Carrier text if not in missing state, null otherwise. - */ - private CharSequence getCarrierTextForSimState(int simState, CharSequence text) { - CharSequence carrierText = null; - CarrierTextController.StatusMode status = getStatusForIccState(simState); - switch (status) { - case Normal: - carrierText = text; - break; - - case SimNotReady: - // Null is reserved for denoting missing, in this case we have nothing to display. - carrierText = ""; // nothing to display yet. - break; - - case NetworkLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - mContext.getText(R.string.keyguard_network_locked_message), text); - break; - - case SimMissing: - carrierText = null; - break; - - case SimPermDisabled: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText( - R.string.keyguard_permanent_disabled_sim_message_short), - text); - break; - - case SimMissingLocked: - carrierText = null; - break; - - case SimLocked: - carrierText = makeCarrierStringOnLocked( - getContext().getText(R.string.keyguard_sim_locked_message), - text); - break; - - case SimPukLocked: - carrierText = makeCarrierStringOnLocked( - getContext().getText(R.string.keyguard_sim_puk_locked_message), - text); - break; - case SimIoError: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.keyguard_sim_error_message_short), - text); - break; - case SimUnknown: - carrierText = null; - break; - } - - return carrierText; - } - - /* - * Add emergencyCallMessage to carrier string only if phone supports emergency calls. - */ - private CharSequence makeCarrierStringOnEmergencyCapable( - CharSequence simMessage, CharSequence emergencyCallMessage) { - if (mIsEmergencyCallCapable) { - return concatenate(simMessage, emergencyCallMessage, mSeparator); - } - return simMessage; - } - - /* - * Add "SIM card is locked" in parenthesis after carrier name, so it is easily associated in - * DSDS - */ - private CharSequence makeCarrierStringOnLocked(CharSequence simMessage, - CharSequence carrierName) { - final boolean simMessageValid = !TextUtils.isEmpty(simMessage); - final boolean carrierNameValid = !TextUtils.isEmpty(carrierName); - if (simMessageValid && carrierNameValid) { - return mContext.getString(R.string.keyguard_carrier_name_with_sim_locked_template, - carrierName, simMessage); - } else if (simMessageValid) { - return simMessage; - } else if (carrierNameValid) { - return carrierName; - } else { - return ""; - } - } - - /** - * Determine the current status of the lock screen given the SIM state and other stuff. - */ - private CarrierTextController.StatusMode getStatusForIccState(int simState) { - final boolean missingAndNotProvisioned = - !mKeyguardUpdateMonitor.isDeviceProvisioned() - && (simState == TelephonyManager.SIM_STATE_ABSENT - || simState == TelephonyManager.SIM_STATE_PERM_DISABLED); - - // Assume we're NETWORK_LOCKED if not provisioned - simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState; - switch (simState) { - case TelephonyManager.SIM_STATE_ABSENT: - return CarrierTextController.StatusMode.SimMissing; - case TelephonyManager.SIM_STATE_NETWORK_LOCKED: - return CarrierTextController.StatusMode.SimMissingLocked; - case TelephonyManager.SIM_STATE_NOT_READY: - return CarrierTextController.StatusMode.SimNotReady; - case TelephonyManager.SIM_STATE_PIN_REQUIRED: - return CarrierTextController.StatusMode.SimLocked; - case TelephonyManager.SIM_STATE_PUK_REQUIRED: - return CarrierTextController.StatusMode.SimPukLocked; - case TelephonyManager.SIM_STATE_READY: - return CarrierTextController.StatusMode.Normal; - case TelephonyManager.SIM_STATE_PERM_DISABLED: - return CarrierTextController.StatusMode.SimPermDisabled; - case TelephonyManager.SIM_STATE_UNKNOWN: - return CarrierTextController.StatusMode.SimUnknown; - case TelephonyManager.SIM_STATE_CARD_IO_ERROR: - return CarrierTextController.StatusMode.SimIoError; - } - return CarrierTextController.StatusMode.SimUnknown; - } - - private static CharSequence concatenate(CharSequence plmn, CharSequence spn, - CharSequence separator) { - final boolean plmnValid = !TextUtils.isEmpty(plmn); - final boolean spnValid = !TextUtils.isEmpty(spn); - if (plmnValid && spnValid) { - return new StringBuilder().append(plmn).append(separator).append(spn).toString(); - } else if (plmnValid) { - return plmn; - } else if (spnValid) { - return spn; - } else { - return ""; - } - } - - /** - * Joins the strings in a sequence using a separator. Empty strings are discarded with no extra - * separator added so there are no extra separators that are not needed. - */ - private static CharSequence joinNotEmpty(CharSequence separator, CharSequence[] sequences) { - int length = sequences.length; - if (length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (!TextUtils.isEmpty(sequences[i])) { - if (!TextUtils.isEmpty(sb)) { - sb.append(separator); - } - sb.append(sequences[i]); - } - } - return sb.toString(); - } - - private static List append(List list, CharSequence string) { - if (!TextUtils.isEmpty(string)) { - list.add(string); - } - return list; - } - - private CharSequence getCarrierHelpTextForSimState(int simState, - String plmn, String spn) { - int carrierHelpTextId = 0; - CarrierTextController.StatusMode status = getStatusForIccState(simState); - switch (status) { - case NetworkLocked: - carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled; - break; - - case SimMissing: - carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long; - break; - - case SimPermDisabled: - carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions; - break; - - case SimMissingLocked: - carrierHelpTextId = R.string.keyguard_missing_sim_instructions; - break; - - case Normal: - case SimLocked: - case SimPukLocked: - break; - } - - return mContext.getText(carrierHelpTextId); - } - - 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, - 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; - } - - - public Builder setShowAirplaneMode(boolean showAirplaneMode) { - mShowAirplaneMode = showAirplaneMode; - return this; - } - - public Builder setShowMissingSim(boolean showMissingSim) { - mShowMissingSim = showMissingSim; - return this; - } - - public CarrierTextController build() { - return new CarrierTextController( - mContext, mSeparator, mShowAirplaneMode, mShowMissingSim, mTelephonyManager, - mTelephonyListenerManager, mMainExecutor, mBgExecutor); - } - } - /** - * Data structure for passing information to CarrierTextController subscribers - */ - public static final class CarrierTextCallbackInfo { - public final CharSequence carrierText; - public final CharSequence[] listOfCarriers; - public final boolean anySimReady; - public final int[] subscriptionIds; - public boolean airplaneMode; - - @VisibleForTesting - public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, - boolean anySimReady, int[] subscriptionIds) { - this(carrierText, listOfCarriers, anySimReady, subscriptionIds, false); - } - - @VisibleForTesting - public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, - boolean anySimReady, int[] subscriptionIds, boolean airplaneMode) { - this.carrierText = carrierText; - this.listOfCarriers = listOfCarriers; - this.anySimReady = anySimReady; - this.subscriptionIds = subscriptionIds; - this.airplaneMode = airplaneMode; - } - } - - /** - * Callback to communicate to Views - */ - public interface CarrierTextCallback { - /** - * Provides updated carrier information. - */ - default void updateCarrierInfo(CarrierTextCallbackInfo info) {}; - - /** - * Notifies the View that the device is going to sleep - */ - default void startedGoingToSleep() {}; - - /** - * Notifies the View that the device finished waking up - */ - default void finishedWakingUp() {}; + @Override + protected void onViewDetached() { + mCarrierTextManager.setListening(null); } } diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java new file mode 100644 index 0000000000000..bb1d9729ccc3d --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java @@ -0,0 +1,721 @@ +/* + * 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.keyguard; + +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.telephony.ServiceState; +import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.android.settingslib.WirelessUtils; +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; + +/** + * Controller that generates text including the carrier names and/or the status of all the SIM + * interfaces in the device. Through a callback, the updates can be retrieved either as a list or + * separated by a given separator {@link CharSequence}. + */ +public class CarrierTextManager { + private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final String TAG = "CarrierTextController"; + + private final boolean mIsEmergencyCallCapable; + private final Executor mMainExecutor; + private final Executor mBgExecutor; + private boolean mTelephonyCapable; + private final boolean mShowMissingSim; + private final boolean mShowAirplaneMode; + private final AtomicBoolean mNetworkSupported = new AtomicBoolean(); + @VisibleForTesting + protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final WifiManager mWifiManager; + private final boolean[] mSimErrorState; + private final int mSimSlotsNumber; + @Nullable // Check for nullability before dispatching + private CarrierTextCallback mCarrierTextCallback; + private final Context mContext; + private final TelephonyManager mTelephonyManager; + private final CharSequence mSeparator; + private final TelephonyListenerManager mTelephonyListenerManager; + private final WakefulnessLifecycle mWakefulnessLifecycle; + private final WakefulnessLifecycle.Observer mWakefulnessObserver = + new WakefulnessLifecycle.Observer() { + @Override + public void onFinishedWakingUp() { + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) callback.finishedWakingUp(); + } + + @Override + public void onStartedGoingToSleep() { + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) callback.startedGoingToSleep(); + } + }; + + @VisibleForTesting + protected final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onRefreshCarrierInfo() { + if (DEBUG) { + Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: " + + Boolean.toString(mTelephonyCapable)); + } + updateCarrierText(); + } + + @Override + public void onTelephonyCapable(boolean capable) { + if (DEBUG) { + Log.d(TAG, "onTelephonyCapable() mTelephonyCapable: " + + Boolean.toString(capable)); + } + mTelephonyCapable = capable; + updateCarrierText(); + } + + public void onSimStateChanged(int subId, int slotId, int simState) { + if (slotId < 0 || slotId >= mSimSlotsNumber) { + Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId + + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable)); + return; + } + + if (DEBUG) Log.d(TAG, "onSimStateChanged: " + getStatusForIccState(simState)); + if (getStatusForIccState(simState) == CarrierTextManager.StatusMode.SimIoError) { + mSimErrorState[slotId] = true; + updateCarrierText(); + } else if (mSimErrorState[slotId]) { + mSimErrorState[slotId] = false; + updateCarrierText(); + } + } + }; + + private final ActiveDataSubscriptionIdListener mPhoneStateListener = + new ActiveDataSubscriptionIdListener() { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + if (mNetworkSupported.get() && mCarrierTextCallback != null) { + updateCarrierText(); + } + } + }; + + /** + * The status of this lock screen. Primarily used for widgets on LockScreen. + */ + private enum StatusMode { + Normal, // Normal case (sim card present, it's not locked) + NetworkLocked, // SIM card is 'network locked'. + SimMissing, // SIM card is missing. + SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access + SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times + SimLocked, // SIM card is currently locked + SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure + SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM. + SimIoError, // SIM card is faulty + SimUnknown // SIM card is unknown + } + + /** + * Controller that provides updates on text with carriers names or SIM status. + * Used by {@link CarrierText}. + * + * @param separator Separator between different parts of the text + */ + private CarrierTextManager(Context context, CharSequence separator, boolean showAirplaneMode, + boolean showMissingSim, @Nullable WifiManager wifiManager, + TelephonyManager telephonyManager, TelephonyListenerManager telephonyListenerManager, + WakefulnessLifecycle wakefulnessLifecycle, @Main Executor mainExecutor, + @Background Executor bgExecutor, KeyguardUpdateMonitor keyguardUpdateMonitor) { + mContext = context; + mIsEmergencyCallCapable = telephonyManager.isVoiceCapable(); + + mShowAirplaneMode = showAirplaneMode; + mShowMissingSim = showMissingSim; + + mWifiManager = wifiManager; + mTelephonyManager = telephonyManager; + mSeparator = separator; + mTelephonyListenerManager = telephonyListenerManager; + mWakefulnessLifecycle = wakefulnessLifecycle; + mSimSlotsNumber = getTelephonyManager().getSupportedModemCount(); + mSimErrorState = new boolean[mSimSlotsNumber]; + mMainExecutor = mainExecutor; + mBgExecutor = bgExecutor; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mBgExecutor.execute(() -> { + boolean supported = mContext.getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_TELEPHONY); + if (supported && mNetworkSupported.compareAndSet(false, supported)) { + // This will set/remove the listeners appropriately. Note that it will never double + // add the listeners. + handleSetListening(mCarrierTextCallback); + } + }); + } + + private TelephonyManager getTelephonyManager() { + return mTelephonyManager; + } + + /** + * Checks if there are faulty cards. Adds the text depending on the slot of the card + * + * @param text: current carrier text based on the sim state + * @param carrierNames names order by subscription order + * @param subOrderBySlot array containing the sub index for each slot ID + * @param noSims: whether a valid sim card is inserted + * @return text + */ + private CharSequence updateCarrierTextWithSimIoError(CharSequence text, + CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) { + final CharSequence carrier = ""; + 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++) { + if (!mSimErrorState[index]) { + continue; + } + // In the case when no sim cards are detected but a faulty card is inserted + // overwrite the text and only show "Invalid card" + if (noSims) { + return concatenate(carrierTextForSimIOError, + getContext().getText( + com.android.internal.R.string.emergency_calls_only), + mSeparator); + } else if (subOrderBySlot[index] != -1) { + int subIndex = subOrderBySlot[index]; + // prepend "Invalid card" when faulty card is inserted in slot 0 or 1 + carrierNames[subIndex] = concatenate(carrierTextForSimIOError, + carrierNames[subIndex], + mSeparator); + } else { + // concatenate "Invalid card" when faulty card is inserted in other slot + text = concatenate(text, carrierTextForSimIOError, mSeparator); + } + + } + return text; + } + + /** + * This may be called internally after retrieving the correct value of {@code mNetworkSupported} + * (assumed false to start). In that case, the following happens: + *
    + *
  • If there was a registered callback, and the network is supported, it will register + * listeners. + *
  • If there was not a registered callback, it will try to remove unregistered listeners + * which is a no-op + *
+ * + * This call will always be processed in a background thread. + */ + private void handleSetListening(CarrierTextCallback callback) { + if (callback != null) { + mCarrierTextCallback = callback; + if (mNetworkSupported.get()) { + // Keyguard update monitor expects callbacks from main thread + mMainExecutor.execute(() -> mKeyguardUpdateMonitor.registerCallback(mCallback)); + mWakefulnessLifecycle.addObserver(mWakefulnessObserver); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener); + } else { + // Don't listen and clear out the text when the device isn't a phone. + mMainExecutor.execute(() -> callback.updateCarrierInfo( + new CarrierTextCallbackInfo("", null, false, null) + )); + } + } else { + mCarrierTextCallback = null; + mMainExecutor.execute(() -> mKeyguardUpdateMonitor.removeCallback(mCallback)); + mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); + mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener); + } + } + + /** + * Sets the listening status of this controller. If the callback is null, it is set to + * not listening. + * + * @param callback Callback to provide text updates + */ + public void setListening(CarrierTextCallback callback) { + mBgExecutor.execute(() -> handleSetListening(callback)); + } + + protected List getSubscriptionInfo() { + return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); + } + + protected void updateCarrierText() { + boolean allSimsMissing = true; + boolean anySimReadyAndInService = false; + CharSequence displayText = null; + List subs = getSubscriptionInfo(); + + final int numSubs = subs.size(); + final int[] subsIds = new int[numSubs]; + // This array will contain in position i, the index of subscription in slot ID i. + // -1 if no subscription in that slot + final int[] subOrderBySlot = new int[mSimSlotsNumber]; + for (int i = 0; i < mSimSlotsNumber; i++) { + subOrderBySlot[i] = -1; + } + final CharSequence[] carrierNames = new CharSequence[numSubs]; + if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs); + + for (int i = 0; i < numSubs; i++) { + int subId = subs.get(i).getSubscriptionId(); + carrierNames[i] = ""; + subsIds[i] = subId; + subOrderBySlot[subs.get(i).getSimSlotIndex()] = i; + int simState = mKeyguardUpdateMonitor.getSimState(subId); + CharSequence carrierName = subs.get(i).getCarrierName(); + CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName); + if (DEBUG) { + Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName); + } + if (carrierTextForSimState != null) { + allSimsMissing = false; + carrierNames[i] = carrierTextForSimState; + } + if (simState == TelephonyManager.SIM_STATE_READY) { + ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); + if (ss != null && ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE) { + // hack for WFC (IWLAN) not turning off immediately once + // Wi-Fi is disassociated or disabled + if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + || (mWifiManager != null && mWifiManager.isWifiEnabled() + && mWifiManager.getConnectionInfo() != null + && mWifiManager.getConnectionInfo().getBSSID() != null)) { + if (DEBUG) { + Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss); + } + anySimReadyAndInService = true; + } + } + } + } + // Only create "No SIM card" if no cards with CarrierName && no wifi when some sim is READY + // This condition will also be true always when numSubs == 0 + if (allSimsMissing && !anySimReadyAndInService) { + if (numSubs != 0) { + // Shows "No SIM card | Emergency calls only" on devices that are voice-capable. + // This depends on mPlmn containing the text "Emergency calls only" when the radio + // has some connectivity. Otherwise, it should be null or empty and just show + // "No SIM card" + // Grab the first subscripton, because they all should contain the emergency text, + // described above. + displayText = makeCarrierStringOnEmergencyCapable( + getMissingSimMessage(), subs.get(0).getCarrierName()); + } else { + // We don't have a SubscriptionInfo to get the emergency calls only from. + // Grab it from the old sticky broadcast if possible instead. We can use it + // here because no subscriptions are active, so we don't have + // to worry about MSIM clashing. + CharSequence text = + getContext().getText(com.android.internal.R.string.emergency_calls_only); + Intent i = getContext().registerReceiver(null, + new IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)); + if (i != null) { + String spn = ""; + String plmn = ""; + if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false)) { + spn = i.getStringExtra(TelephonyManager.EXTRA_SPN); + } + if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false)) { + plmn = i.getStringExtra(TelephonyManager.EXTRA_PLMN); + } + if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn); + if (Objects.equals(plmn, spn)) { + text = plmn; + } else { + text = concatenate(plmn, spn, mSeparator); + } + } + displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text); + } + } + + if (TextUtils.isEmpty(displayText)) displayText = joinNotEmpty(mSeparator, carrierNames); + + displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, + allSimsMissing); + + boolean airplaneMode = false; + // APM (airplane mode) != no carrier state. There are carrier services + // (e.g. WFC = Wi-Fi calling) which may operate in APM. + if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) { + displayText = getAirplaneModeMessage(); + airplaneMode = true; + } + + final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( + displayText, + carrierNames, + !allSimsMissing, + subsIds, + airplaneMode); + postToCallback(info); + } + + @VisibleForTesting + protected void postToCallback(CarrierTextCallbackInfo info) { + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) { + mMainExecutor.execute(() -> callback.updateCarrierInfo(info)); + } + } + + private Context getContext() { + return mContext; + } + + private String getMissingSimMessage() { + return mShowMissingSim && mTelephonyCapable + ? getContext().getString(R.string.keyguard_missing_sim_message_short) : ""; + } + + private String getAirplaneModeMessage() { + return mShowAirplaneMode + ? getContext().getString(R.string.airplane_mode) : ""; + } + + /** + * Top-level function for creating carrier text. Makes text based on simState, PLMN + * and SPN as well as device capabilities, such as being emergency call capable. + * + * @return Carrier text if not in missing state, null otherwise. + */ + private CharSequence getCarrierTextForSimState(int simState, CharSequence text) { + CharSequence carrierText = null; + CarrierTextManager.StatusMode status = getStatusForIccState(simState); + switch (status) { + case Normal: + carrierText = text; + break; + + case SimNotReady: + // Null is reserved for denoting missing, in this case we have nothing to display. + carrierText = ""; // nothing to display yet. + break; + + case NetworkLocked: + carrierText = makeCarrierStringOnEmergencyCapable( + mContext.getText(R.string.keyguard_network_locked_message), text); + break; + + case SimMissing: + carrierText = null; + break; + + case SimPermDisabled: + carrierText = makeCarrierStringOnEmergencyCapable( + getContext().getText( + R.string.keyguard_permanent_disabled_sim_message_short), + text); + break; + + case SimMissingLocked: + carrierText = null; + break; + + case SimLocked: + carrierText = makeCarrierStringOnLocked( + getContext().getText(R.string.keyguard_sim_locked_message), + text); + break; + + case SimPukLocked: + carrierText = makeCarrierStringOnLocked( + getContext().getText(R.string.keyguard_sim_puk_locked_message), + text); + break; + case SimIoError: + carrierText = makeCarrierStringOnEmergencyCapable( + getContext().getText(R.string.keyguard_sim_error_message_short), + text); + break; + case SimUnknown: + carrierText = null; + break; + } + + return carrierText; + } + + /* + * Add emergencyCallMessage to carrier string only if phone supports emergency calls. + */ + private CharSequence makeCarrierStringOnEmergencyCapable( + CharSequence simMessage, CharSequence emergencyCallMessage) { + if (mIsEmergencyCallCapable) { + return concatenate(simMessage, emergencyCallMessage, mSeparator); + } + return simMessage; + } + + /* + * Add "SIM card is locked" in parenthesis after carrier name, so it is easily associated in + * DSDS + */ + private CharSequence makeCarrierStringOnLocked(CharSequence simMessage, + CharSequence carrierName) { + final boolean simMessageValid = !TextUtils.isEmpty(simMessage); + final boolean carrierNameValid = !TextUtils.isEmpty(carrierName); + if (simMessageValid && carrierNameValid) { + return mContext.getString(R.string.keyguard_carrier_name_with_sim_locked_template, + carrierName, simMessage); + } else if (simMessageValid) { + return simMessage; + } else if (carrierNameValid) { + return carrierName; + } else { + return ""; + } + } + + /** + * Determine the current status of the lock screen given the SIM state and other stuff. + */ + private CarrierTextManager.StatusMode getStatusForIccState(int simState) { + final boolean missingAndNotProvisioned = + !mKeyguardUpdateMonitor.isDeviceProvisioned() + && (simState == TelephonyManager.SIM_STATE_ABSENT + || simState == TelephonyManager.SIM_STATE_PERM_DISABLED); + + // Assume we're NETWORK_LOCKED if not provisioned + simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState; + switch (simState) { + case TelephonyManager.SIM_STATE_ABSENT: + return CarrierTextManager.StatusMode.SimMissing; + case TelephonyManager.SIM_STATE_NETWORK_LOCKED: + return CarrierTextManager.StatusMode.SimMissingLocked; + case TelephonyManager.SIM_STATE_NOT_READY: + return CarrierTextManager.StatusMode.SimNotReady; + case TelephonyManager.SIM_STATE_PIN_REQUIRED: + return CarrierTextManager.StatusMode.SimLocked; + case TelephonyManager.SIM_STATE_PUK_REQUIRED: + return CarrierTextManager.StatusMode.SimPukLocked; + case TelephonyManager.SIM_STATE_READY: + return CarrierTextManager.StatusMode.Normal; + case TelephonyManager.SIM_STATE_PERM_DISABLED: + return CarrierTextManager.StatusMode.SimPermDisabled; + case TelephonyManager.SIM_STATE_UNKNOWN: + return CarrierTextManager.StatusMode.SimUnknown; + case TelephonyManager.SIM_STATE_CARD_IO_ERROR: + return CarrierTextManager.StatusMode.SimIoError; + } + return CarrierTextManager.StatusMode.SimUnknown; + } + + private static CharSequence concatenate(CharSequence plmn, CharSequence spn, + CharSequence separator) { + final boolean plmnValid = !TextUtils.isEmpty(plmn); + final boolean spnValid = !TextUtils.isEmpty(spn); + if (plmnValid && spnValid) { + return new StringBuilder().append(plmn).append(separator).append(spn).toString(); + } else if (plmnValid) { + return plmn; + } else if (spnValid) { + return spn; + } else { + return ""; + } + } + + /** + * Joins the strings in a sequence using a separator. Empty strings are discarded with no extra + * separator added so there are no extra separators that are not needed. + */ + private static CharSequence joinNotEmpty(CharSequence separator, CharSequence[] sequences) { + int length = sequences.length; + if (length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (!TextUtils.isEmpty(sequences[i])) { + if (!TextUtils.isEmpty(sb)) { + sb.append(separator); + } + sb.append(sequences[i]); + } + } + return sb.toString(); + } + + private static List append(List list, CharSequence string) { + if (!TextUtils.isEmpty(string)) { + list.add(string); + } + return list; + } + + private CharSequence getCarrierHelpTextForSimState(int simState, + String plmn, String spn) { + int carrierHelpTextId = 0; + CarrierTextManager.StatusMode status = getStatusForIccState(simState); + switch (status) { + case NetworkLocked: + carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled; + break; + + case SimMissing: + carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long; + break; + + case SimPermDisabled: + carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions; + break; + + case SimMissingLocked: + carrierHelpTextId = R.string.keyguard_missing_sim_instructions; + break; + + case Normal: + case SimLocked: + case SimPukLocked: + break; + } + + return mContext.getText(carrierHelpTextId); + } + + /** Injectable Buildeer for {@#link CarrierTextManager}. */ + public static class Builder { + private final Context mContext; + private final String mSeparator; + private final WifiManager mWifiManager; + private final TelephonyManager mTelephonyManager; + private final TelephonyListenerManager mTelephonyListenerManager; + private final WakefulnessLifecycle mWakefulnessLifecycle; + private final Executor mMainExecutor; + private final Executor mBgExecutor; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private boolean mShowAirplaneMode; + private boolean mShowMissingSim; + + @Inject + public Builder(Context context, @Main Resources resources, + @Nullable WifiManager wifiManager, + TelephonyManager telephonyManager, + TelephonyListenerManager telephonyListenerManager, + WakefulnessLifecycle wakefulnessLifecycle, + @Main Executor mainExecutor, @Background Executor bgExecutor, + KeyguardUpdateMonitor keyguardUpdateMonitor) { + mContext = context; + mSeparator = resources.getString( + com.android.internal.R.string.kg_text_message_separator); + mWifiManager = wifiManager; + mTelephonyManager = telephonyManager; + mTelephonyListenerManager = telephonyListenerManager; + mWakefulnessLifecycle = wakefulnessLifecycle; + mMainExecutor = mainExecutor; + mBgExecutor = bgExecutor; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + } + + /** */ + public Builder setShowAirplaneMode(boolean showAirplaneMode) { + mShowAirplaneMode = showAirplaneMode; + return this; + } + + /** */ + public Builder setShowMissingSim(boolean showMissingSim) { + mShowMissingSim = showMissingSim; + return this; + } + + /** Create a CarrierTextManager. */ + public CarrierTextManager build() { + return new CarrierTextManager( + mContext, mSeparator, mShowAirplaneMode, mShowMissingSim, mWifiManager, + mTelephonyManager, mTelephonyListenerManager, + mWakefulnessLifecycle, mMainExecutor, mBgExecutor, mKeyguardUpdateMonitor); + } + } + /** + * Data structure for passing information to CarrierTextController subscribers + */ + public static final class CarrierTextCallbackInfo { + public final CharSequence carrierText; + public final CharSequence[] listOfCarriers; + public final boolean anySimReady; + public final int[] subscriptionIds; + public boolean airplaneMode; + + @VisibleForTesting + public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, + boolean anySimReady, int[] subscriptionIds) { + this(carrierText, listOfCarriers, anySimReady, subscriptionIds, false); + } + + @VisibleForTesting + public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, + boolean anySimReady, int[] subscriptionIds, boolean airplaneMode) { + this.carrierText = carrierText; + this.listOfCarriers = listOfCarriers; + this.anySimReady = anySimReady; + this.subscriptionIds = subscriptionIds; + this.airplaneMode = airplaneMode; + } + } + + /** + * Callback to communicate to Views + */ + public interface CarrierTextCallback { + /** + * Provides updated carrier information. + */ + default void updateCarrierInfo(CarrierTextCallbackInfo info) {}; + + /** + * Notifies the View that the device is going to sleep + */ + default void startedGoingToSleep() {}; + + /** + * Notifies the View that the device finished waking up + */ + default void finishedWakingUp() {}; + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java new file mode 100644 index 0000000000000..49a617eeb6c09 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020 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.keyguard.dagger; + +import com.android.keyguard.KeyguardStatusViewController; +import com.android.systemui.statusbar.phone.KeyguardStatusBarView; +import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController; + +import dagger.BindsInstance; +import dagger.Subcomponent; + +/** + * Subcomponent for helping work with KeyguardStatusView and its children. + * + * TODO: unify this with {@link KeyguardStatusViewComponent} + */ +@Subcomponent(modules = {KeyguardStatusBarViewModule.class}) +@KeyguardStatusBarViewScope +public interface KeyguardStatusBarViewComponent { + /** Simple factory for {@link KeyguardStatusBarViewComponent}. */ + @Subcomponent.Factory + interface Factory { + KeyguardStatusBarViewComponent build(@BindsInstance KeyguardStatusBarView view); + } + + /** Builds a {@link KeyguardStatusViewController}. */ + KeyguardStatusBarViewController getKeyguardStatusBarViewController(); +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java new file mode 100644 index 0000000000000..a6725234e4af1 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020 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.keyguard.dagger; + +import com.android.keyguard.CarrierText; +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.KeyguardStatusBarView; + +import dagger.Module; +import dagger.Provides; + +/** Dagger module for {@link KeyguardStatusBarViewComponent}. */ +@Module +public abstract class KeyguardStatusBarViewModule { + @Provides + @KeyguardStatusBarViewScope + static CarrierText getCarrierText(KeyguardStatusBarView view) { + return view.findViewById(R.id.keyguard_carrier_text); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java new file mode 100644 index 0000000000000..ba0642f57a887 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 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.keyguard.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the StatusBarComponent. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface KeyguardStatusBarViewScope {} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java index 1b6476ce74df7..d342377da49b3 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java @@ -25,6 +25,8 @@ import dagger.Subcomponent; /** * Subcomponent for helping work with KeyguardStatusView and its children. + * + * TODO: unify this with {@link KeyguardStatusBarViewComponent} */ @Subcomponent(modules = {KeyguardStatusViewModule.class}) @KeyguardStatusViewScope diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index de2e7c476e185..a747edd0580a7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -30,6 +30,7 @@ import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; +import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -63,8 +64,11 @@ import dagger.Provides; /** * Dagger Module providing {@link StatusBar}. */ -@Module(subcomponents = {KeyguardStatusViewComponent.class, - KeyguardQsUserSwitchComponent.class, KeyguardUserSwitcherComponent.class}, +@Module(subcomponents = { + KeyguardQsUserSwitchComponent.class, + KeyguardStatusBarViewComponent.class, + KeyguardStatusViewComponent.class, + KeyguardUserSwitcherComponent.class}, includes = {FalsingModule.class}) public class KeyguardModule { /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java index 0dc0b30748aa0..5afe1c87121da 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java @@ -34,7 +34,7 @@ import android.widget.TextView; import androidx.annotation.VisibleForTesting; -import com.android.keyguard.CarrierTextController; +import com.android.keyguard.CarrierTextManager; import com.android.settingslib.AccessibilityContentDescriptions; import com.android.settingslib.mobile.TelephonyIcons; import com.android.systemui.R; @@ -59,7 +59,7 @@ public class QSCarrierGroupController { private final ActivityStarter mActivityStarter; private final Handler mBgHandler; private final NetworkController mNetworkController; - private final CarrierTextController mCarrierTextController; + private final CarrierTextManager mCarrierTextManager; private final TextView mNoSimTextView; private final H mMainHandler; private final Callback mCallback; @@ -149,7 +149,7 @@ public class QSCarrierGroupController { } }; - private static class Callback implements CarrierTextController.CarrierTextCallback { + private static class Callback implements CarrierTextManager.CarrierTextCallback { private H mHandler; Callback(H handler) { @@ -157,7 +157,7 @@ public class QSCarrierGroupController { } @Override - public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { + public void updateCarrierInfo(CarrierTextManager.CarrierTextCallbackInfo info) { mHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget(); } } @@ -165,7 +165,7 @@ public class QSCarrierGroupController { private QSCarrierGroupController(QSCarrierGroup view, ActivityStarter activityStarter, @Background Handler bgHandler, @Main Looper mainLooper, NetworkController networkController, - CarrierTextController.Builder carrierTextControllerBuilder, Context context) { + CarrierTextManager.Builder carrierTextManagerBuilder, Context context) { if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) { mProviderModel = true; } else { @@ -174,7 +174,7 @@ public class QSCarrierGroupController { mActivityStarter = activityStarter; mBgHandler = bgHandler; mNetworkController = networkController; - mCarrierTextController = carrierTextControllerBuilder + mCarrierTextManager = carrierTextManagerBuilder .setShowAirplaneMode(false) .setShowMissingSim(false) .build(); @@ -192,7 +192,6 @@ public class QSCarrierGroupController { mMainHandler = new H(mainLooper, this::handleUpdateCarrierInfo, this::handleUpdateState); mCallback = new Callback(mMainHandler); - mCarrierGroups[0] = view.getCarrier1View(); mCarrierGroups[1] = view.getCarrier2View(); mCarrierGroups[2] = view.getCarrier3View(); @@ -243,10 +242,10 @@ public class QSCarrierGroupController { if (mNetworkController.hasVoiceCallingFeature()) { mNetworkController.addCallback(mSignalCallback); } - mCarrierTextController.setListening(mCallback); + mCarrierTextManager.setListening(mCallback); } else { mNetworkController.removeCallback(mSignalCallback); - mCarrierTextController.setListening(null); + mCarrierTextManager.setListening(null); } } @@ -273,7 +272,7 @@ public class QSCarrierGroupController { } @MainThread - private void handleUpdateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { + private void handleUpdateCarrierInfo(CarrierTextManager.CarrierTextCallbackInfo info) { if (!mMainHandler.getLooper().isCurrentThread()) { mMainHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget(); return; @@ -327,13 +326,13 @@ public class QSCarrierGroupController { } private static class H extends Handler { - private Consumer mUpdateCarrierInfo; + private Consumer mUpdateCarrierInfo; private Runnable mUpdateState; static final int MSG_UPDATE_CARRIER_INFO = 0; static final int MSG_UPDATE_STATE = 1; H(Looper looper, - Consumer updateCarrierInfo, + Consumer updateCarrierInfo, Runnable updateState) { super(looper); mUpdateCarrierInfo = updateCarrierInfo; @@ -345,7 +344,7 @@ public class QSCarrierGroupController { switch (msg.what) { case MSG_UPDATE_CARRIER_INFO: mUpdateCarrierInfo.accept( - (CarrierTextController.CarrierTextCallbackInfo) msg.obj); + (CarrierTextManager.CarrierTextCallbackInfo) msg.obj); break; case MSG_UPDATE_STATE: mUpdateState.run(); @@ -362,13 +361,13 @@ public class QSCarrierGroupController { private final Handler mHandler; private final Looper mLooper; private final NetworkController mNetworkController; - private final CarrierTextController.Builder mCarrierTextControllerBuilder; + private final CarrierTextManager.Builder mCarrierTextControllerBuilder; private final Context mContext; @Inject public Builder(ActivityStarter activityStarter, @Background Handler handler, @Main Looper looper, NetworkController networkController, - CarrierTextController.Builder carrierTextControllerBuilder, Context context) { + CarrierTextManager.Builder carrierTextControllerBuilder, Context context) { mActivityStarter = activityStarter; mHandler = handler; mLooper = looper; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java new file mode 100644 index 0000000000000..377fb92ac6bad --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -0,0 +1,48 @@ +/* + * 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.statusbar.phone; + +import com.android.keyguard.CarrierTextController; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */ +public class KeyguardStatusBarViewController extends ViewController { + private final CarrierTextController mCarrierTextController; + + @Inject + public KeyguardStatusBarViewController( + KeyguardStatusBarView view, CarrierTextController carrierTextController) { + super(view); + mCarrierTextController = carrierTextController; + } + + @Override + protected void onInit() { + super.onInit(); + mCarrierTextController.init(); + } + + @Override + protected void onViewAttached() { + } + + @Override + protected void onViewDetached() { + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 415cfff3713b8..d3da0bce0a155 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -83,6 +83,7 @@ import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; +import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.DejankUtils; @@ -298,6 +299,7 @@ public class NotificationPanelViewController extends PanelViewController { private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; + private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; private final QSDetailDisplayer mQSDetailDisplayer; private final FeatureFlags mFeatureFlags; private final ScrimController mScrimController; @@ -313,6 +315,7 @@ public class NotificationPanelViewController extends PanelViewController { private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; private KeyguardUserSwitcherController mKeyguardUserSwitcherController; private KeyguardStatusBarView mKeyguardStatusBar; + private KeyguardStatusBarViewController mKeyguarStatusBarViewController; private ViewGroup mBigClockContainer; private QS mQs; private FrameLayout mQsFrame; @@ -565,6 +568,7 @@ public class NotificationPanelViewController extends PanelViewController { KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory, KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory, + KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory, QSDetailDisplayer qsDetailDisplayer, NotificationGroupManagerLegacy groupManager, NotificationIconAreaController notificationIconAreaController, @@ -589,6 +593,7 @@ public class NotificationPanelViewController extends PanelViewController { mGroupManager = groupManager; mNotificationIconAreaController = notificationIconAreaController; mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; + mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory; mFeatureFlags = featureFlags; mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory; mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory; @@ -693,7 +698,9 @@ public class NotificationPanelViewController extends PanelViewController { } updateViewControllers(mView.findViewById(R.id.keyguard_status_view), - userAvatarView, keyguardUserSwitcherView); + userAvatarView, + mKeyguardStatusBar, + keyguardUserSwitcherView); mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); NotificationStackScrollLayout stackScrollLayout = mView.findViewById( R.id.notification_stack_scroller); @@ -773,13 +780,21 @@ public class NotificationPanelViewController extends PanelViewController { } private void updateViewControllers(KeyguardStatusView keyguardStatusView, - UserAvatarView userAvatarView, KeyguardUserSwitcherView keyguardUserSwitcherView) { + UserAvatarView userAvatarView, + KeyguardStatusBarView keyguardStatusBarView, + KeyguardUserSwitcherView keyguardUserSwitcherView) { // Re-associate the KeyguardStatusViewController KeyguardStatusViewComponent statusViewComponent = mKeyguardStatusViewComponentFactory.build(keyguardStatusView); mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController(); mKeyguardStatusViewController.init(); + KeyguardStatusBarViewComponent statusBarViewComponent = + mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView); + mKeyguarStatusBarViewController = + statusBarViewComponent.getKeyguardStatusBarViewController(); + mKeyguarStatusBarViewController.init(); + // Re-associate the clock container with the keyguard clock switch. KeyguardClockSwitchController keyguardClockSwitchController = statusViewComponent.getKeyguardClockSwitchController(); @@ -919,7 +934,8 @@ public class NotificationPanelViewController extends PanelViewController { showKeyguardUserSwitcher /* enabled */); mBigClockContainer.removeAllViews(); - updateViewControllers(keyguardStatusView, userAvatarView, keyguardUserSwitcherView); + updateViewControllers( + keyguardStatusView, userAvatarView, mKeyguardStatusBar, keyguardUserSwitcherView); // Update keyguard bottom area index = mView.indexOfChild(mKeyguardBottomArea); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java similarity index 82% rename from packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java rename to packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java index c54620248ceb3..c2c7dde562a23 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java @@ -71,7 +71,7 @@ import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) -public class CarrierTextControllerTest extends SysuiTestCase { +public class CarrierTextManagerTest extends SysuiTestCase { private static final CharSequence SEPARATOR = " \u2014 "; private static final CharSequence INVALID_CARD_TEXT = "Invalid card"; @@ -92,7 +92,9 @@ public class CarrierTextControllerTest extends SysuiTestCase { @Mock private WifiManager mWifiManager; @Mock - private CarrierTextController.CarrierTextCallback mCarrierTextCallback; + private WakefulnessLifecycle mWakefulnessLifecycle; + @Mock + private CarrierTextManager.CarrierTextCallback mCarrierTextCallback; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock @@ -106,9 +108,9 @@ public class CarrierTextControllerTest extends SysuiTestCase { private FakeExecutor mBgExecutor = new FakeExecutor(mFakeSystemClock); @Mock private SubscriptionManager mSubscriptionManager; - private CarrierTextController.CarrierTextCallbackInfo mCarrierTextCallbackInfo; + private CarrierTextManager.CarrierTextCallbackInfo mCarrierTextCallbackInfo; - private CarrierTextController mCarrierTextController; + private CarrierTextManager mCarrierTextManager; private Void checkMainThread(InvocationOnMock inv) { assertThat(mMainExecutor.isExecuting()).isTrue(); @@ -137,25 +139,29 @@ public class CarrierTextControllerTest extends SysuiTestCase { doAnswer(this::checkMainThread).when(mKeyguardUpdateMonitor) .removeCallback(any(KeyguardUpdateMonitorCallback.class)); - mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("", + mCarrierTextCallbackInfo = new CarrierTextManager.CarrierTextCallbackInfo("", new CharSequence[]{}, false, new int[]{}); when(mTelephonyManager.getSupportedModemCount()).thenReturn(3); when(mTelephonyManager.getActiveModemCount()).thenReturn(3); - mCarrierTextController = new CarrierTextController( - mContext, SEPARATOR, true, true, - mTelephonyManager, mTelephonyListenerManager, mMainExecutor, - mBgExecutor); + mCarrierTextManager = new CarrierTextManager.Builder( + mContext, mContext.getResources(), mWifiManager, + mTelephonyManager, mTelephonyListenerManager, mWakefulnessLifecycle, mMainExecutor, + mBgExecutor, mKeyguardUpdateMonitor) + .setShowAirplaneMode(true) + .setShowMissingSim(true) + .build(); + // 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); + mCarrierTextManager.setListening(mCarrierTextCallback); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); } @Test public void testKeyguardUpdateMonitorCalledInMainThread() throws Exception { - mCarrierTextController.setListening(null); - mCarrierTextController.setListening(mCarrierTextCallback); + mCarrierTextManager.setListening(null); + mCarrierTextManager.setListening(mCarrierTextCallback); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); } @@ -169,11 +175,11 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(TelephonyManager.SIM_STATE_READY); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -191,12 +197,12 @@ public class CarrierTextControllerTest extends SysuiTestCase { TelephonyManager.SIM_STATE_CARD_IO_ERROR); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - mCarrierTextController.mCallback.onSimStateChanged(3, 1, + mCarrierTextManager.mCallback.onSimStateChanged(3, 1, TelephonyManager.SIM_STATE_CARD_IO_ERROR); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -209,7 +215,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { reset(mCarrierTextCallback); when(mTelephonyManager.getActiveModemCount()).thenReturn(1); // Update carrier text. It should ignore error state of subId 3 in inactive slotId. - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals("TEST_CARRIER", captor.getValue().carrierText); @@ -223,9 +229,9 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( TelephonyManager.SIM_STATE_CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions - mCarrierTextController.mCallback.onSimStateChanged(0, -3, + mCarrierTextManager.mCallback.onSimStateChanged(0, -3, TelephonyManager.SIM_STATE_CARD_IO_ERROR); - mCarrierTextController.mCallback.onSimStateChanged(0, 3, TelephonyManager.SIM_STATE_READY); + mCarrierTextManager.mCallback.onSimStateChanged(0, 3, TelephonyManager.SIM_STATE_READY); verify(mCarrierTextCallback, never()).updateCarrierInfo(any()); } @@ -243,23 +249,23 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( TelephonyManager.SIM_STATE_CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions - mCarrierTextController.mCallback.onSimStateChanged(0, 1, + mCarrierTextManager.mCallback.onSimStateChanged(0, 1, TelephonyManager.SIM_STATE_CARD_IO_ERROR); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo( - any(CarrierTextController.CarrierTextCallbackInfo.class)); + any(CarrierTextManager.CarrierTextCallbackInfo.class)); } @Test public void testCallback() { reset(mCarrierTextCallback); - mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); + mCarrierTextManager.postToCallback(mCarrierTextCallbackInfo); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(mCarrierTextCallbackInfo, captor.getValue()); } @@ -268,8 +274,8 @@ public class CarrierTextControllerTest extends SysuiTestCase { public void testNullingCallback() { reset(mCarrierTextCallback); - mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); - mCarrierTextController.setListening(null); + mCarrierTextManager.postToCallback(mCarrierTextCallbackInfo); + mCarrierTextManager.setListening(null); // This shouldn't produce NPE FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); @@ -287,15 +293,15 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); + CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertEquals(TEST_CARRIER, info.listOfCarriers[0]); assertEquals(1, info.subscriptionIds.length); @@ -312,15 +318,15 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); + CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertTrue(info.listOfCarriers[0].toString().contains(TEST_CARRIER)); assertEquals(1, info.subscriptionIds.length); @@ -332,16 +338,16 @@ public class CarrierTextControllerTest extends SysuiTestCase { List list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION_NULL); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( - TelephonyManager.SIM_STATE_READY); + TelephonyManager.SIM_STATE_READY); when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -366,11 +372,11 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(ss.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); mKeyguardUpdateMonitor.mServiceStates.put(TEST_SUBSCRIPTION_NULL.getSubscriptionId(), ss); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -393,15 +399,15 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); + CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(0, info.listOfCarriers.length); assertEquals(0, info.subscriptionIds.length); @@ -414,16 +420,16 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION); list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( - TelephonyManager.SIM_STATE_READY); + TelephonyManager.SIM_STATE_READY); when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -444,11 +450,11 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -469,11 +475,11 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -495,11 +501,11 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java index 5a1bd5f72a024..59a5f03da5302 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java @@ -33,7 +33,7 @@ import android.widget.TextView; import androidx.test.filters.SmallTest; -import com.android.keyguard.CarrierTextController; +import com.android.keyguard.CarrierTextManager; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators; @@ -55,7 +55,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { private QSCarrierGroupController mQSCarrierGroupController; private NetworkController.SignalCallback mSignalCallback; - private CarrierTextController.CarrierTextCallback mCallback; + private CarrierTextManager.CarrierTextCallback mCallback; @Mock private QSCarrierGroup mQSCarrierGroup; @Mock @@ -63,9 +63,9 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { @Mock private NetworkController mNetworkController; @Mock - private CarrierTextController.Builder mCarrierTextControllerBuilder; + private CarrierTextManager.Builder mCarrierTextControllerBuilder; @Mock - private CarrierTextController mCarrierTextController; + private CarrierTextManager mCarrierTextManager; private TestableLooper mTestableLooper; @Before @@ -84,11 +84,11 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { .thenReturn(mCarrierTextControllerBuilder); when(mCarrierTextControllerBuilder.setShowMissingSim(anyBoolean())) .thenReturn(mCarrierTextControllerBuilder); - when(mCarrierTextControllerBuilder.build()).thenReturn(mCarrierTextController); + when(mCarrierTextControllerBuilder.build()).thenReturn(mCarrierTextManager); doAnswer(invocation -> mCallback = invocation.getArgument(0)) - .when(mCarrierTextController) - .setListening(any(CarrierTextController.CarrierTextCallback.class)); + .when(mCarrierTextManager) + .setListening(any(CarrierTextManager.CarrierTextCallback.class)); when(mQSCarrierGroup.getNoSimTextView()).thenReturn(new TextView(mContext)); when(mQSCarrierGroup.getCarrier1View()).thenReturn(mock(QSCarrier.class)); @@ -114,8 +114,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { (Answer) invocationOnMock -> invocationOnMock.getArgument(0)); // listOfCarriers length 1, subscriptionIds length 1, anySims false - CarrierTextController.CarrierTextCallbackInfo - c1 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c1 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, false, @@ -123,8 +123,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c1); // listOfCarriers length 1, subscriptionIds length 1, anySims true - CarrierTextController.CarrierTextCallbackInfo - c2 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c2 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, true, @@ -132,8 +132,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c2); // listOfCarriers length 2, subscriptionIds length 2, anySims false - CarrierTextController.CarrierTextCallbackInfo - c3 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c3 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, false, @@ -141,8 +141,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c3); // listOfCarriers length 2, subscriptionIds length 2, anySims true - CarrierTextController.CarrierTextCallbackInfo - c4 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c4 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, true, @@ -160,8 +160,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { (Answer) invocationOnMock -> invocationOnMock.getArgument(0)); // listOfCarriers length 2, subscriptionIds length 1, anySims false - CarrierTextController.CarrierTextCallbackInfo - c1 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c1 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, false, @@ -169,8 +169,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c1); // listOfCarriers length 2, subscriptionIds length 1, anySims true - CarrierTextController.CarrierTextCallbackInfo - c2 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c2 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, true, @@ -178,8 +178,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c2); // listOfCarriers length 1, subscriptionIds length 2, anySims false - CarrierTextController.CarrierTextCallbackInfo - c3 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c3 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, false, @@ -187,8 +187,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c3); // listOfCarriers length 1, subscriptionIds length 2, anySims true - CarrierTextController.CarrierTextCallbackInfo - c4 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c4 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, true, @@ -204,8 +204,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenReturn( SubscriptionManager.INVALID_SIM_SLOT_INDEX); - CarrierTextController.CarrierTextCallbackInfo - c4 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c4 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, true, @@ -225,8 +225,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { @Test public void testNoEmptyVisibleView_airplaneMode() { - CarrierTextController.CarrierTextCallbackInfo - info = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + info = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, true, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 91f3611d548d4..6a5e6e8f98725 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -66,6 +66,7 @@ import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; +import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.R; @@ -206,10 +207,16 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent; @Mock + private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; + @Mock + private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent; + @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; @Mock private KeyguardStatusViewController mKeyguardStatusViewController; @Mock + private KeyguardStatusBarViewController mKeyguardStatusBarViewController; + @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; @Mock private AuthController mAuthController; @@ -296,6 +303,10 @@ public class NotificationPanelViewTest extends SysuiTestCase { .thenReturn(mKeyguardClockSwitchController); when(mKeyguardStatusViewComponent.getKeyguardStatusViewController()) .thenReturn(mKeyguardStatusViewController); + when(mKeyguardStatusBarViewComponentFactory.build(any())) + .thenReturn(mKeyguardStatusBarViewComponent); + when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController()) + .thenReturn(mKeyguardStatusBarViewController); mNotificationPanelViewController = new NotificationPanelViewController(mView, mResources, @@ -314,6 +325,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mKeyguardStatusViewComponentFactory, mKeyguardQsUserSwitchComponentFactory, mKeyguardUserSwitcherComponentFactory, + mKeyguardStatusBarViewComponentFactory, mQSDetailDisplayer, mGroupManager, mNotificationAreaController, From db4ee91dced6e586fa73b055ffac6718cbe6854e Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Fri, 19 Feb 2021 16:38:09 +0000 Subject: [PATCH 3/7] Revert^2 "Add Controller for Emergency Button." f23acf33ff3684586b7dc66026b518ada77eed84 Change-Id: Id555c35af9a5ed2570504cd6b4e3ca3b5892c340 --- .../com/android/keyguard/EmergencyButton.java | 140 +------------ .../keyguard/EmergencyButtonController.java | 196 ++++++++++++++++++ .../KeyguardAbsKeyInputViewController.java | 15 +- .../keyguard/KeyguardInputViewController.java | 30 ++- .../KeyguardPasswordViewController.java | 4 +- .../KeyguardPatternViewController.java | 18 +- .../KeyguardPinBasedInputViewController.java | 4 +- .../keyguard/KeyguardPinViewController.java | 3 +- ...KeyguardSecurityViewFlipperController.java | 13 +- .../KeyguardSimPinViewController.java | 4 +- .../KeyguardSimPukViewController.java | 4 +- ...KeyguardAbsKeyInputViewControllerTest.java | 5 +- .../KeyguardPatternViewControllerTest.kt | 5 +- ...yguardPinBasedInputViewControllerTest.java | 4 +- ...yguardSecurityContainerControllerTest.java | 8 +- ...uardSecurityViewFlipperControllerTest.java | 9 +- 16 files changed, 284 insertions(+), 178 deletions(-) create mode 100644 packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java index 707ee298a55a9..c4b02f62f2914 100644 --- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java +++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java @@ -16,34 +16,16 @@ package com.android.keyguard; -import static com.android.systemui.DejankUtils.whitelistIpcs; - -import android.app.ActivityOptions; -import android.app.ActivityTaskManager; import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.UserHandle; -import android.telecom.TelecomManager; -import android.telephony.TelephonyManager; import android.util.AttributeSet; -import android.util.Log; -import android.util.Slog; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.Button; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.EmergencyAffordanceManager; import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.Utils; -import com.android.systemui.Dependency; -import com.android.systemui.util.EmergencyDialerConstants; /** * This class implements a smart emergency button that updates itself based @@ -53,34 +35,14 @@ import com.android.systemui.util.EmergencyDialerConstants; */ public class EmergencyButton extends Button { - private static final String LOG_TAG = "EmergencyButton"; private final EmergencyAffordanceManager mEmergencyAffordanceManager; private int mDownX; private int mDownY; - KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - - @Override - public void onSimStateChanged(int subId, int slotId, int simState) { - updateEmergencyCallButton(); - } - - @Override - public void onPhoneStateChanged(int phoneState) { - updateEmergencyCallButton(); - } - }; private boolean mLongPressWasDragged; - public interface EmergencyButtonCallback { - public void onEmergencyButtonClickedWhenInCall(); - } - private LockPatternUtils mLockPatternUtils; - private PowerManager mPowerManager; - private EmergencyButtonCallback mEmergencyButtonCallback; - private final boolean mIsVoiceCapable; private final boolean mEnableEmergencyCallWhileSimLocked; public EmergencyButton(Context context) { @@ -89,34 +51,15 @@ public class EmergencyButton extends Button { public EmergencyButton(Context context, AttributeSet attrs) { super(context, attrs); - mIsVoiceCapable = getTelephonyManager().isVoiceCapable(); mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked); mEmergencyAffordanceManager = new EmergencyAffordanceManager(context); } - private TelephonyManager getTelephonyManager() { - return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mInfoCallback); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mInfoCallback); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); mLockPatternUtils = new LockPatternUtils(mContext); - mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - setOnClickListener(v -> takeEmergencyCallAction()); if (mEmergencyAffordanceManager.needsEmergencyAffordance()) { setOnLongClickListener(v -> { if (!mLongPressWasDragged @@ -127,7 +70,6 @@ public class EmergencyButton extends Button { return false; }); } - whitelistIpcs(this::updateEmergencyCallButton); } @Override @@ -165,65 +107,13 @@ public class EmergencyButton extends Button { return super.performLongClick(); } - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - updateEmergencyCallButton(); - } - - /** - * Shows the emergency dialer or returns the user to the existing call. - */ - public void takeEmergencyCallAction() { - MetricsLogger.action(mContext, MetricsEvent.ACTION_EMERGENCY_CALL); - if (mPowerManager != null) { - mPowerManager.userActivity(SystemClock.uptimeMillis(), true); - } - try { - ActivityTaskManager.getService().stopSystemLockTaskMode(); - } catch (RemoteException e) { - Slog.w(LOG_TAG, "Failed to stop app pinning"); - } - if (isInCall()) { - resumeCall(); - if (mEmergencyButtonCallback != null) { - mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall(); - } - } else { - KeyguardUpdateMonitor updateMonitor = Dependency.get(KeyguardUpdateMonitor.class); - if (updateMonitor != null) { - updateMonitor.reportEmergencyCallAction(true /* bypassHandler */); - } else { - Log.w(LOG_TAG, "KeyguardUpdateMonitor was null, launching intent anyway."); - } - TelecomManager telecomManager = getTelecommManager(); - if (telecomManager == null) { - Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer"); - return; - } - Intent emergencyDialIntent = - telecomManager.createLaunchEmergencyDialerIntent(null /* number*/) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - | Intent.FLAG_ACTIVITY_CLEAR_TOP) - .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE, - EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON); - - getContext().startActivityAsUser(emergencyDialIntent, - ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), - new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); - } - } - - private void updateEmergencyCallButton() { + void updateEmergencyCallButton(boolean isInCall, boolean isVoiceCapable, boolean simLocked) { boolean visible = false; - if (mIsVoiceCapable) { + if (isVoiceCapable) { // Emergency calling requires voice capability. - if (isInCall()) { + if (isInCall) { visible = true; // always show "return to call" if phone is off-hook } else { - final boolean simLocked = Dependency.get(KeyguardUpdateMonitor.class) - .isSimPinVoiceSecure(); if (simLocked) { // Some countries can't handle emergency calls while SIM is locked. visible = mEnableEmergencyCallWhileSimLocked; @@ -237,7 +127,7 @@ public class EmergencyButton extends Button { setVisibility(View.VISIBLE); int textId; - if (isInCall()) { + if (isInCall) { textId = com.android.internal.R.string.lockscreen_return_to_call; } else { textId = com.android.internal.R.string.lockscreen_emergency_call; @@ -247,26 +137,4 @@ public class EmergencyButton extends Button { setVisibility(View.GONE); } } - - public void setCallback(EmergencyButtonCallback callback) { - mEmergencyButtonCallback = callback; - } - - /** - * Resumes a call in progress. - */ - private void resumeCall() { - getTelecommManager().showInCallScreen(false); - } - - /** - * @return {@code true} if there is a call currently in progress. - */ - private boolean isInCall() { - return getTelecommManager().isInCall(); - } - - private TelecomManager getTelecommManager() { - return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); - } } diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java new file mode 100644 index 0000000000000..4275189cfe267 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java @@ -0,0 +1,196 @@ +/* + * 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.keyguard; + +import static com.android.systemui.DejankUtils.whitelistIpcs; + +import android.app.ActivityOptions; +import android.app.ActivityTaskManager; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.PowerManager; +import android.os.SystemClock; +import android.os.UserHandle; +import android.telecom.TelecomManager; +import android.telephony.TelephonyManager; +import android.util.Log; + +import androidx.annotation.Nullable; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.keyguard.dagger.KeyguardBouncerScope; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import com.android.systemui.util.EmergencyDialerConstants; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** View Controller for {@link com.android.keyguard.EmergencyButton}. */ +@KeyguardBouncerScope +public class EmergencyButtonController extends ViewController { + static final String LOG_TAG = "EmergencyButton"; + private final ConfigurationController mConfigurationController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final TelephonyManager mTelephonyManager; + private final PowerManager mPowerManager; + private final ActivityTaskManager mActivityTaskManager; + private final TelecomManager mTelecomManager; + private final MetricsLogger mMetricsLogger; + + private EmergencyButtonCallback mEmergencyButtonCallback; + + private final KeyguardUpdateMonitorCallback mInfoCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onSimStateChanged(int subId, int slotId, int simState) { + updateEmergencyCallButton(); + } + + @Override + public void onPhoneStateChanged(int phoneState) { + updateEmergencyCallButton(); + } + }; + + private final ConfigurationListener mConfigurationListener = new ConfigurationListener() { + @Override + public void onConfigChanged(Configuration newConfig) { + updateEmergencyCallButton(); + } + }; + + private EmergencyButtonController(@Nullable EmergencyButton view, + ConfigurationController configurationController, + KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, + PowerManager powerManager, ActivityTaskManager activityTaskManager, + @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) { + super(view); + mConfigurationController = configurationController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mTelephonyManager = telephonyManager; + mPowerManager = powerManager; + mActivityTaskManager = activityTaskManager; + mTelecomManager = telecomManager; + mMetricsLogger = metricsLogger; + } + + @Override + protected void onInit() { + whitelistIpcs(this::updateEmergencyCallButton); + } + + @Override + protected void onViewAttached() { + mKeyguardUpdateMonitor.registerCallback(mInfoCallback); + mConfigurationController.addCallback(mConfigurationListener); + mView.setOnClickListener(v -> takeEmergencyCallAction()); + } + + @Override + protected void onViewDetached() { + mKeyguardUpdateMonitor.removeCallback(mInfoCallback); + mConfigurationController.removeCallback(mConfigurationListener); + } + + private void updateEmergencyCallButton() { + if (mView != null) { + mView.updateEmergencyCallButton( + mTelecomManager != null && mTelecomManager.isInCall(), + mTelephonyManager.isVoiceCapable(), + mKeyguardUpdateMonitor.isSimPinVoiceSecure()); + } + } + + public void setEmergencyButtonCallback(EmergencyButtonCallback callback) { + mEmergencyButtonCallback = callback; + } + /** + * Shows the emergency dialer or returns the user to the existing call. + */ + public void takeEmergencyCallAction() { + mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_CALL); + if (mPowerManager != null) { + mPowerManager.userActivity(SystemClock.uptimeMillis(), true); + } + mActivityTaskManager.stopSystemLockTaskMode(); + if (mTelecomManager != null && mTelecomManager.isInCall()) { + mTelecomManager.showInCallScreen(false); + if (mEmergencyButtonCallback != null) { + mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall(); + } + } else { + mKeyguardUpdateMonitor.reportEmergencyCallAction(true /* bypassHandler */); + if (mTelecomManager == null) { + Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer"); + return; + } + Intent emergencyDialIntent = + mTelecomManager.createLaunchEmergencyDialerIntent(null /* number*/) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_CLEAR_TOP) + .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE, + EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON); + + getContext().startActivityAsUser(emergencyDialIntent, + ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), + new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); + } + } + + /** */ + public interface EmergencyButtonCallback { + /** */ + void onEmergencyButtonClickedWhenInCall(); + } + + /** Injectable Factory for creating {@link EmergencyButtonController}. */ + public static class Factory { + private final ConfigurationController mConfigurationController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final TelephonyManager mTelephonyManager; + private final PowerManager mPowerManager; + private final ActivityTaskManager mActivityTaskManager; + @Nullable + private final TelecomManager mTelecomManager; + private final MetricsLogger mMetricsLogger; + + @Inject + public Factory(ConfigurationController configurationController, + KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, + PowerManager powerManager, ActivityTaskManager activityTaskManager, + @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) { + + mConfigurationController = configurationController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mTelephonyManager = telephonyManager; + mPowerManager = powerManager; + mActivityTaskManager = activityTaskManager; + mTelecomManager = telecomManager; + mMetricsLogger = metricsLogger; + } + + /** Construct an {@link com.android.keyguard.EmergencyButtonController}. */ + public EmergencyButtonController create(EmergencyButton view) { + return new EmergencyButtonController(view, mConfigurationController, + mKeyguardUpdateMonitor, mTelephonyManager, mPowerManager, mActivityTaskManager, + mTelecomManager, mMetricsLogger); + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 9f32c03d1de4a..e41d5a3e34a75 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -31,7 +31,7 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; -import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; +import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback; import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; @@ -44,6 +44,7 @@ public abstract class KeyguardAbsKeyInputViewController private final SecurityMode mSecurityMode; private final KeyguardSecurityCallback mKeyguardSecurityCallback; private final EmergencyButton mEmergencyButton; + private final EmergencyButtonController mEmergencyButtonController; private boolean mPaused; @@ -69,11 +70,18 @@ public abstract class KeyguardInputViewController }; protected KeyguardInputViewController(T view, SecurityMode securityMode, - KeyguardSecurityCallback keyguardSecurityCallback) { + KeyguardSecurityCallback keyguardSecurityCallback, + EmergencyButtonController emergencyButtonController) { super(view); mSecurityMode = securityMode; mKeyguardSecurityCallback = keyguardSecurityCallback; mEmergencyButton = view == null ? null : view.findViewById(R.id.emergency_call_button); + mEmergencyButtonController = emergencyButtonController; + } + + @Override + protected void onInit() { + mEmergencyButtonController.init(); } @Override @@ -157,6 +165,7 @@ public abstract class KeyguardInputViewController private final Resources mResources; private final LiftToActivateListener mLiftToActivateListener; private final TelephonyManager mTelephonyManager; + private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory; private final FalsingCollector mFalsingCollector; private final boolean mIsNewLayoutEnabled; @@ -168,6 +177,7 @@ public abstract class KeyguardInputViewController InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor, @Main Resources resources, LiftToActivateListener liftToActivateListener, TelephonyManager telephonyManager, FalsingCollector falsingCollector, + EmergencyButtonController.Factory emergencyButtonControllerFactory, FeatureFlags featureFlags) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; @@ -178,6 +188,7 @@ public abstract class KeyguardInputViewController mResources = resources; mLiftToActivateListener = liftToActivateListener; mTelephonyManager = telephonyManager; + mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; mFalsingCollector = falsingCollector; mIsNewLayoutEnabled = featureFlags.isKeyguardLayoutEnabled(); } @@ -185,33 +196,40 @@ public abstract class KeyguardInputViewController /** Create a new {@link KeyguardInputViewController}. */ public KeyguardInputViewController create(KeyguardInputView keyguardInputView, SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback) { + EmergencyButtonController emergencyButtonController = + mEmergencyButtonControllerFactory.create( + keyguardInputView.findViewById(R.id.emergency_call_button)); + if (keyguardInputView instanceof KeyguardPatternView) { return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mLatencyTracker, mFalsingCollector, - mMessageAreaControllerFactory); + emergencyButtonController, mMessageAreaControllerFactory); } else if (keyguardInputView instanceof KeyguardPasswordView) { return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mInputMethodManager, mMainExecutor, mResources, mFalsingCollector); + mInputMethodManager, emergencyButtonController, mMainExecutor, mResources, + mFalsingCollector); + } else if (keyguardInputView instanceof KeyguardPINView) { return new KeyguardPinViewController((KeyguardPINView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mLiftToActivateListener, mFalsingCollector, mIsNewLayoutEnabled); + mLiftToActivateListener, emergencyButtonController, mFalsingCollector, + mIsNewLayoutEnabled); } else if (keyguardInputView instanceof KeyguardSimPinView) { return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, mTelephonyManager, mFalsingCollector, - mIsNewLayoutEnabled); + emergencyButtonController, mIsNewLayoutEnabled); } else if (keyguardInputView instanceof KeyguardSimPukView) { return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, mTelephonyManager, mFalsingCollector, - mIsNewLayoutEnabled); + emergencyButtonController, mIsNewLayoutEnabled); } throw new RuntimeException("Unable to find controller for " + keyguardInputView); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index e45dd8baa1d84..933a919efaad7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -112,11 +112,13 @@ public class KeyguardPasswordViewController KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, InputMethodManager inputMethodManager, + EmergencyButtonController emergencyButtonController, @Main DelayableExecutor mainExecutor, @Main Resources resources, FalsingCollector falsingCollector) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, - messageAreaControllerFactory, latencyTracker, falsingCollector); + messageAreaControllerFactory, latencyTracker, falsingCollector, + emergencyButtonController); mKeyguardSecurityCallback = keyguardSecurityCallback; mInputMethodManager = inputMethodManager; mMainExecutor = mainExecutor; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index e16c01a4aa365..f0d1e02ce8724 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -32,7 +32,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import com.android.internal.widget.LockscreenCredential; -import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; +import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.settingslib.Utils; import com.android.systemui.R; @@ -54,6 +54,7 @@ public class KeyguardPatternViewController private final LockPatternUtils mLockPatternUtils; private final LatencyTracker mLatencyTracker; private final FalsingCollector mFalsingCollector; + private final EmergencyButtonController mEmergencyButtonController; private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory; private KeyguardMessageAreaController mMessageAreaController; @@ -189,12 +190,14 @@ public class KeyguardPatternViewController KeyguardSecurityCallback keyguardSecurityCallback, LatencyTracker latencyTracker, FalsingCollector falsingCollector, + EmergencyButtonController emergencyButtonController, KeyguardMessageAreaController.Factory messageAreaControllerFactory) { - super(view, securityMode, keyguardSecurityCallback); + super(view, securityMode, keyguardSecurityCallback, emergencyButtonController); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; mFalsingCollector = falsingCollector; + mEmergencyButtonController = emergencyButtonController; mMessageAreaControllerFactory = messageAreaControllerFactory; KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); mMessageAreaController = mMessageAreaControllerFactory.create(kma); @@ -222,11 +225,7 @@ public class KeyguardPatternViewController } return false; }); - - EmergencyButton button = mView.findViewById(R.id.emergency_call_button); - if (button != null) { - button.setCallback(mEmergencyButtonCallback); - } + mEmergencyButtonController.setEmergencyButtonCallback(mEmergencyButtonCallback); View cancelBtn = mView.findViewById(R.id.cancel_button); if (cancelBtn != null) { @@ -242,10 +241,7 @@ public class KeyguardPatternViewController super.onViewDetached(); mLockPatternView.setOnPatternListener(null); mLockPatternView.setOnTouchListener(null); - EmergencyButton button = mView.findViewById(R.id.emergency_call_button); - if (button != null) { - button.setCallback(null); - } + mEmergencyButtonController.setEmergencyButtonCallback(null); View cancelBtn = mView.findViewById(R.id.cancel_button); if (cancelBtn != null) { cancelBtn.setOnClickListener(null); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java index b156f8169b509..8de4e7b557f3f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -57,9 +57,11 @@ public abstract class KeyguardPinBasedInputViewController> mChildren = new ArrayList<>(); private final LayoutInflater mLayoutInflater; + private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory; private final Factory mKeyguardSecurityViewControllerFactory; @Inject protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view, LayoutInflater layoutInflater, - KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory) { + KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory, + EmergencyButtonController.Factory emergencyButtonControllerFactory) { super(view); mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; mLayoutInflater = layoutInflater; + mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; } @Override @@ -111,7 +114,8 @@ public class KeyguardSecurityViewFlipperController if (childController == null) { childController = new NullKeyguardInputViewController( - securityMode, keyguardSecurityCallback); + securityMode, keyguardSecurityCallback, + mEmergencyButtonControllerFactory.create(null)); } return childController; @@ -140,8 +144,9 @@ public class KeyguardSecurityViewFlipperController private static class NullKeyguardInputViewController extends KeyguardInputViewController { protected NullKeyguardInputViewController(SecurityMode securityMode, - KeyguardSecurityCallback keyguardSecurityCallback) { - super(null, securityMode, keyguardSecurityCallback); + KeyguardSecurityCallback keyguardSecurityCallback, + EmergencyButtonController emergencyButtonController) { + super(null, securityMode, keyguardSecurityCallback, emergencyButtonController); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java index b2bf2e674b338..fddbb3cdfc845 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -79,10 +79,10 @@ public class KeyguardSimPinViewController KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, TelephonyManager telephonyManager, FalsingCollector falsingCollector, - boolean isNewLayoutEnabled) { + EmergencyButtonController emergencyButtonController, boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - falsingCollector); + emergencyButtonController, falsingCollector); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java index 620db481e4a2a..722fd9a096939 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -86,10 +86,10 @@ public class KeyguardSimPukViewController KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, TelephonyManager telephonyManager, FalsingCollector falsingCollector, - boolean isNewLayoutEnabled) { + EmergencyButtonController emergencyButtonController, boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - falsingCollector); + emergencyButtonController, falsingCollector); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index 0cf343c2d3c44..90f7fda696638 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -72,6 +72,8 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { @Mock private LatencyTracker mLatencyTracker; private final FalsingCollector mFalsingCollector = new FalsingCollectorFake(); + @Mock + private EmergencyButtonController mEmergencyButtonController; private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController; @@ -87,7 +89,8 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { .thenReturn(mKeyguardMessageArea); mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector) { + mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector, + mEmergencyButtonController) { @Override void resetState() { } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index fc93dedc4e8e4..bb71bed84f43d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -52,6 +52,8 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { private lateinit var mLatencyTracker: LatencyTracker private var mFalsingCollector: FalsingCollector = FalsingCollectorFake() @Mock + private lateinit var mEmergencyButtonController: EmergencyButtonController + @Mock private lateinit var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory @Mock @@ -75,7 +77,8 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { .thenReturn(mKeyguardMessageAreaController) mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mLatencyTracker, mFalsingCollector, mKeyguardMessageAreaControllerFactory) + mLatencyTracker, mFalsingCollector, mEmergencyButtonController, + mKeyguardMessageAreaControllerFactory) } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index 33a0dcd048ae1..9597cabb2eb8d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -68,6 +68,8 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { private LatencyTracker mLatencyTracker; @Mock private LiftToActivateListener mLiftToactivateListener; + @Mock + private EmergencyButtonController mEmergencyButtonController; private FalsingCollector mFalsingCollector = new FalsingCollectorFake(); @Mock private SingleTapClassifier mSingleTapClassifier; @@ -97,7 +99,7 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener, - mFalsingCollector) { + mEmergencyButtonController, mFalsingCollector) { @Override public void onResume(int reason) { super.onResume(reason); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index 096ce0f9de275..084c0b496c162 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -94,6 +94,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { private KeyguardMessageArea mKeyguardMessageArea; @Mock private ConfigurationController mConfigurationController; + @Mock + private EmergencyButtonController mEmergencyButtonController; private KeyguardSecurityContainerController mKeyguardSecurityContainerController; private KeyguardPasswordViewController mKeyguardPasswordViewController; @@ -112,11 +114,11 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mKeyguardPasswordViewController = new KeyguardPasswordViewController( (KeyguardPasswordView) mKeyguardPasswordView, mKeyguardUpdateMonitor, SecurityMode.Password, mLockPatternUtils, null, - mKeyguardMessageAreaControllerFactory, null, null, null, mock(Resources.class), - null); + mKeyguardMessageAreaControllerFactory, null, null, mEmergencyButtonController, + null, mock(Resources.class), null); mKeyguardSecurityContainerController = new KeyguardSecurityContainerController.Factory( - mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, + mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardStateController, mKeyguardSecurityViewFlipperController, mConfigurationController) diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index 3b7f4b8398537..9296d3d5ec820 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -59,6 +59,10 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { @Mock private KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory; @Mock + private EmergencyButtonController.Factory mEmergencyButtonControllerFactory; + @Mock + private EmergencyButtonController mEmergencyButtonController; + @Mock private KeyguardInputViewController mKeyguardInputViewController; @Mock private KeyguardInputView mInputView; @@ -76,9 +80,12 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { any(KeyguardSecurityCallback.class))) .thenReturn(mKeyguardInputViewController); when(mView.getWindowInsetsController()).thenReturn(mWindowInsetsController); + when(mEmergencyButtonControllerFactory.create(any(EmergencyButton.class))) + .thenReturn(mEmergencyButtonController); mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView, - mLayoutInflater, mKeyguardSecurityViewControllerFactory); + mLayoutInflater, mKeyguardSecurityViewControllerFactory, + mEmergencyButtonControllerFactory); } @Test From 03bfd50a681cceb65f640747daa63809f843f299 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Fri, 19 Feb 2021 16:38:09 +0000 Subject: [PATCH 4/7] Revert^2 "Remove Dependency.get from KeyguardSliceTextView." 5f65ded5af704ad6f41716a635649e79b557bab8 Change-Id: I2e83420b119858930489f2a74756c64f953a4a8c --- .../android/keyguard/KeyguardSliceView.java | 34 +++++++++---------- .../keyguard/KeyguardSliceViewController.java | 4 +++ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index 83c2d1e7f6849..96e69ad019b9a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -49,10 +49,8 @@ import androidx.slice.widget.SliceContent; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.settingslib.Utils; -import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.wakelock.KeepAwakeAnimationListener; import java.io.FileDescriptor; @@ -299,8 +297,23 @@ public class KeyguardSliceView extends LinearLayout { void onDensityOrFontScaleChanged() { mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.widget_icon_size); mIconSizeWithHeader = (int) mContext.getResources().getDimension(R.dimen.header_icon_size); + + for (int i = 0; i < mRow.getChildCount(); i++) { + View child = mRow.getChildAt(i); + if (child instanceof KeyguardSliceTextView) { + ((KeyguardSliceTextView) child).onDensityOrFontScaleChanged(); + } + } } + void onOverlayChanged() { + for (int i = 0; i < mRow.getChildCount(); i++) { + View child = mRow.getChildAt(i); + if (child instanceof KeyguardSliceTextView) { + ((KeyguardSliceTextView) child).onOverlayChanged(); + } + } + } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("KeyguardSliceView:"); pw.println(" mTitle: " + (mTitle == null ? "null" : mTitle.getVisibility() == VISIBLE)); @@ -466,8 +479,7 @@ public class KeyguardSliceView extends LinearLayout { * Representation of an item that appears under the clock on main keyguard message. */ @VisibleForTesting - static class KeyguardSliceTextView extends TextView implements - ConfigurationController.ConfigurationListener { + static class KeyguardSliceTextView extends TextView { private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; @StyleRes @@ -479,24 +491,10 @@ public class KeyguardSliceView extends LinearLayout { setEllipsize(TruncateAt.END); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - Dependency.get(ConfigurationController.class).addCallback(this); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Dependency.get(ConfigurationController.class).removeCallback(this); - } - - @Override public void onDensityOrFontScaleChanged() { updatePadding(); } - @Override public void onOverlayChanged() { setTextAppearance(sStyleId); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java index 1b0a7faeddab7..8038ce4c7b691 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java @@ -83,6 +83,10 @@ public class KeyguardSliceViewController extends ViewController mObserver = new Observer() { From cb56bacf2b1743331a3e5c0526303eead987a1c6 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Fri, 19 Feb 2021 16:38:09 +0000 Subject: [PATCH 5/7] Revert^2 "Add injection to ClockProvider." 07b572188310d53e38771aca80614a04f457c22a Change-Id: I87c5edcb8c713b0364c0fe9f744357824eeb8e9d --- .../android/keyguard/clock/ClockModule.java | 33 +++++++++++++++++++ .../keyguard/clock/ClockOptionsProvider.java | 20 +++++------ .../systemui/dagger/SysUIComponent.java | 6 ++++ .../systemui/dagger/SystemUIModule.java | 2 ++ 4 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 packages/SystemUI/src/com/android/keyguard/clock/ClockModule.java diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockModule.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockModule.java new file mode 100644 index 0000000000000..c4be1ba535039 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockModule.java @@ -0,0 +1,33 @@ +/* + * 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.keyguard.clock; + +import java.util.List; + +import dagger.Module; +import dagger.Provides; + +/** Dagger Module for clock package. */ +@Module +public abstract class ClockModule { + + /** */ + @Provides + public static List provideClockInfoList(ClockManager clockManager) { + return clockManager.getClockInfos(); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java index 5ef35be8df51a..b6413cb61deb6 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java @@ -28,11 +28,12 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Dependency; import java.io.FileNotFoundException; import java.util.List; -import java.util.function.Supplier; + +import javax.inject.Inject; +import javax.inject.Provider; /** * Exposes custom clock face options and provides realistic preview images. @@ -65,15 +66,12 @@ public final class ClockOptionsProvider extends ContentProvider { private static final String CONTENT_SCHEME = "content"; private static final String AUTHORITY = "com.android.keyguard.clock"; - private final Supplier> mClocksSupplier; - - public ClockOptionsProvider() { - this(() -> Dependency.get(ClockManager.class).getClockInfos()); - } + @Inject + public Provider> mClockInfosProvider; @VisibleForTesting - ClockOptionsProvider(Supplier> clocksSupplier) { - mClocksSupplier = clocksSupplier; + ClockOptionsProvider(Provider> clockInfosProvider) { + mClockInfosProvider = clockInfosProvider; } @Override @@ -99,7 +97,7 @@ public final class ClockOptionsProvider extends ContentProvider { } MatrixCursor cursor = new MatrixCursor(new String[] { COLUMN_NAME, COLUMN_TITLE, COLUMN_ID, COLUMN_THUMBNAIL, COLUMN_PREVIEW}); - List clocks = mClocksSupplier.get(); + List clocks = mClockInfosProvider.get(); for (int i = 0; i < clocks.size(); i++) { ClockInfo clock = clocks.get(i); cursor.newRow() @@ -139,7 +137,7 @@ public final class ClockOptionsProvider extends ContentProvider { throw new FileNotFoundException("Invalid preview url, missing id"); } ClockInfo clock = null; - List clocks = mClocksSupplier.get(); + List clocks = mClockInfosProvider.get(); for (int i = 0; i < clocks.size(); i++) { if (id.equals(clocks.get(i).getId())) { clock = clocks.get(i); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index ed3d5ec33b41e..8e4e3081aff25 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -16,6 +16,7 @@ package com.android.systemui.dagger; +import com.android.keyguard.clock.ClockOptionsProvider; import com.android.systemui.BootCompleteCacheImpl; import com.android.systemui.Dependency; import com.android.systemui.InitController; @@ -150,4 +151,9 @@ public interface SysUIComponent { * Member injection into the supplied argument. */ void inject(KeyguardSliceProvider keyguardSliceProvider); + + /** + * Member injection into the supplied argument. + */ + void inject(ClockOptionsProvider clockOptionsProvider); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index b0067cd15c1ba..b67db03a743ca 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -22,6 +22,7 @@ import android.content.Context; import androidx.annotation.Nullable; import com.android.internal.statusbar.IStatusBarService; +import com.android.keyguard.clock.ClockModule; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.BootCompleteCache; import com.android.systemui.BootCompleteCacheImpl; @@ -90,6 +91,7 @@ import dagger.Provides; @Module(includes = { AppOpsModule.class, AssistModule.class, + ClockModule.class, ControlsModule.class, DemoModeModule.class, FalsingModule.class, From 9d947fb625e44729777c7fe4424a7c4d03932d6c Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Fri, 19 Feb 2021 16:38:09 +0000 Subject: [PATCH 6/7] Revert^2 "Remove Dependency.get from KeyguardStatusView." 3f652cb990b991552dfc7057e3b3552655f236c7 Change-Id: Idcd16ba8f1260dead0c0c2a1e60f13eceb57c1aa --- .../android/keyguard/KeyguardStatusView.java | 19 ++----------------- .../KeyguardStatusViewController.java | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index fea152abe36ae..5db4f9e61140d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -34,7 +34,6 @@ import android.widget.TextView; import androidx.core.graphics.ColorUtils; import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.Dependency; import com.android.systemui.R; import java.io.FileDescriptor; @@ -56,7 +55,6 @@ public class KeyguardStatusView extends GridLayout { private final IActivityManager mIActivityManager; private TextView mLogoutView; - private boolean mCanShowLogout = true; // by default, try to show the logout button here private KeyguardClockSwitch mClockView; private TextView mOwnerInfo; private boolean mCanShowOwnerInfo = true; // by default, try to show the owner information here @@ -130,11 +128,6 @@ public class KeyguardStatusView extends GridLayout { } } - void setCanShowLogout(boolean canShowLogout) { - mCanShowLogout = canShowLogout; - updateLogoutView(); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -159,10 +152,7 @@ public class KeyguardStatusView extends GridLayout { mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged); onSliceContentChanged(); - boolean shouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive(); - setEnableMarquee(shouldMarquee); updateOwnerInfo(); - updateLogoutView(); updateDark(); } @@ -209,11 +199,11 @@ public class KeyguardStatusView extends GridLayout { return mOwnerInfo.getVisibility() == VISIBLE ? mOwnerInfo.getHeight() : 0; } - void updateLogoutView() { + void updateLogoutView(boolean shouldShowLogout) { if (mLogoutView == null) { return; } - mLogoutView.setVisibility(mCanShowLogout && shouldShowLogout() ? VISIBLE : GONE); + mLogoutView.setVisibility(shouldShowLogout ? VISIBLE : GONE); // Logout button will stay in language of user 0 if we don't set that manually. mLogoutView.setText(mContext.getResources().getString( com.android.internal.R.string.global_action_logout)); @@ -313,11 +303,6 @@ public class KeyguardStatusView extends GridLayout { } } - private boolean shouldShowLogout() { - return Dependency.get(KeyguardUpdateMonitor.class).isLogoutEnabled() - && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM; - } - private void onLogoutClicked(View view) { int currentUserId = KeyguardUpdateMonitor.getCurrentUser(); try { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 934e768f9ba8b..31ec00378135b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -16,6 +16,7 @@ package com.android.keyguard; +import android.os.UserHandle; import android.util.Slog; import android.view.View; @@ -78,6 +79,8 @@ public class KeyguardStatusViewController extends ViewController Date: Fri, 19 Feb 2021 16:38:09 +0000 Subject: [PATCH 7/7] Revert^2 "Remove final calls to Dependency.get from keyguard." bfec35b4f4e7fc70cfa2c4c209c9edf3cacb7f95 Change-Id: I423b0aa056a5f6ad601874f4bff41299b35f0a7f --- .../android/keyguard/KeyguardDisplayManager.java | 8 ++++++-- .../android/keyguard/KeyguardSecurityModel.java | 14 ++++++++------ .../keyguard/KeyguardSimPukViewController.java | 4 +--- .../keyguard/KeyguardDisplayManagerTest.java | 9 ++++----- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 276036c400e10..76a7473e25e83 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -36,7 +36,6 @@ import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.dagger.KeyguardStatusViewComponent; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.navigationbar.NavigationBarController; @@ -46,12 +45,15 @@ import java.util.concurrent.Executor; import javax.inject.Inject; +import dagger.Lazy; + public class KeyguardDisplayManager { protected static final String TAG = "KeyguardDisplayManager"; private static boolean DEBUG = KeyguardConstants.DEBUG; private MediaRouter mMediaRouter = null; private final DisplayManager mDisplayService; + private final Lazy mNavigationBarControllerLazy; private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; private final Context mContext; @@ -85,9 +87,11 @@ public class KeyguardDisplayManager { @Inject public KeyguardDisplayManager(Context context, + Lazy navigationBarControllerLazy, KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, @UiBackground Executor uiBgExecutor) { mContext = context; + mNavigationBarControllerLazy = navigationBarControllerLazy; mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; uiBgExecutor.execute(() -> mMediaRouter = mContext.getSystemService(MediaRouter.class)); mDisplayService = mContext.getSystemService(DisplayManager.class); @@ -240,7 +244,7 @@ public class KeyguardDisplayManager { // Leave this task to {@link StatusBarKeyguardViewManager} if (displayId == DEFAULT_DISPLAY) return; - NavigationBarView navBarView = Dependency.get(NavigationBarController.class) + NavigationBarView navBarView = mNavigationBarControllerLazy.get() .getNavigationBarView(displayId); // We may not have nav bar on a display. if (navBarView == null) return; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java index 631c248444173..69328cd5d3444 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java @@ -23,7 +23,6 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.Dependency; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; @@ -49,24 +48,27 @@ public class KeyguardSecurityModel { private final boolean mIsPukScreenAvailable; private final LockPatternUtils mLockPatternUtils; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Inject - KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils) { + KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor keyguardUpdateMonitor) { mIsPukScreenAvailable = resources.getBoolean( com.android.internal.R.bool.config_enable_puk_unlock_screen); mLockPatternUtils = lockPatternUtils; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; } public SecurityMode getSecurityMode(int userId) { - KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class); - if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId( - monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED))) { + mKeyguardUpdateMonitor.getNextSubIdForState( + TelephonyManager.SIM_STATE_PUK_REQUIRED))) { return SecurityMode.SimPuk; } if (SubscriptionManager.isValidSubscriptionId( - monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED))) { + mKeyguardUpdateMonitor.getNextSubIdForState( + TelephonyManager.SIM_STATE_PIN_REQUIRED))) { return SecurityMode.SimPin; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java index 722fd9a096939..50bd0c71752b6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -37,7 +37,6 @@ import android.widget.ImageView; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; @@ -198,8 +197,7 @@ public class KeyguardSimPukViewController if (count < 2) { msg = rez.getString(R.string.kg_puk_enter_puk_hint); } else { - SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class) - .getSubscriptionInfoForSubId(mSubId); + SubscriptionInfo info = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(mSubId); CharSequence displayName = info != null ? info.getDisplayName() : ""; msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName); if (info != null) { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java index 826be2ba0d832..4beec574cd2a5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java @@ -53,12 +53,12 @@ import java.util.concurrent.Executor; @TestableLooper.RunWithLooper public class KeyguardDisplayManagerTest extends SysuiTestCase { + @Mock + private NavigationBarController mNavigationBarController; @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; - @Mock private DisplayManager mDisplayManager; - @Mock private KeyguardDisplayManager.KeyguardPresentation mKeyguardPresentation; @@ -76,9 +76,8 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mContext.addMockSystemService(DisplayManager.class, mDisplayManager); - mDependency.injectMockDependency(NavigationBarController.class); - mManager = spy(new KeyguardDisplayManager(mContext, mKeyguardStatusViewComponentFactory, - mBackgroundExecutor)); + mManager = spy(new KeyguardDisplayManager(mContext, () -> mNavigationBarController, + mKeyguardStatusViewComponentFactory, mBackgroundExecutor)); doReturn(mKeyguardPresentation).when(mManager).createPresentation(any()); mDefaultDisplay = new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY,