From e0aff5f686b0f0e54aada70959da259cae413d1e Mon Sep 17 00:00:00 2001 From: Aaron Liu Date: Tue, 21 Feb 2023 11:05:29 -0800 Subject: [PATCH 1/2] Remove lockpattern utils construction... where possible. By invoking the constructor, we are not reusing the cache that will mitigate binder calls for reading state. There is an instance of LockPatternUtils that is injectable via dagger. Some classes, however, cannot inject this. (i.e. view, service, or static method). I've removed the instances where I could to hopefully mitigate binder calls and jank. Fixes: 268192609 Test: Check to see if bouncer works properly mostly. Change-Id: I56a19fa6e419f1a7af28171edf4ebaccf55e9929 --- .../com/android/keyguard/EmergencyButton.java | 9 +++----- .../keyguard/EmergencyButtonController.java | 21 +++++++++++++------ .../src/com/android/keyguard/NumPadKey.java | 3 --- ...NotificationLockscreenUserManagerImpl.java | 5 +++-- ...NotificationLockscreenUserManagerTest.java | 4 +++- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java index a25b281f807c6..c5a06b48e0157 100644 --- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java +++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java @@ -24,7 +24,6 @@ import android.view.ViewConfiguration; import android.widget.Button; import com.android.internal.util.EmergencyAffordanceManager; -import com.android.internal.widget.LockPatternUtils; /** * This class implements a smart emergency button that updates itself based @@ -40,8 +39,6 @@ public class EmergencyButton extends Button { private int mDownY; private boolean mLongPressWasDragged; - private LockPatternUtils mLockPatternUtils; - private final boolean mEnableEmergencyCallWhileSimLocked; public EmergencyButton(Context context) { @@ -58,7 +55,6 @@ public class EmergencyButton extends Button { @Override protected void onFinishInflate() { super.onFinishInflate(); - mLockPatternUtils = new LockPatternUtils(mContext); if (mEmergencyAffordanceManager.needsEmergencyAffordance()) { setOnLongClickListener(v -> { if (!mLongPressWasDragged @@ -95,7 +91,8 @@ public class EmergencyButton extends Button { return super.performLongClick(); } - void updateEmergencyCallButton(boolean isInCall, boolean hasTelephonyRadio, boolean simLocked) { + void updateEmergencyCallButton(boolean isInCall, boolean hasTelephonyRadio, boolean simLocked, + boolean isSecure) { boolean visible = false; if (hasTelephonyRadio) { // Emergency calling requires a telephony radio. @@ -107,7 +104,7 @@ public class EmergencyButton extends Button { visible = mEnableEmergencyCallWhileSimLocked; } else { // Only show if there is a secure screen (pin/pattern/SIM pin/SIM puk); - visible = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()); + visible = isSecure; } } } diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java index ea808eb19b90e..62298f10d6b71 100644 --- a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java +++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java @@ -34,6 +34,7 @@ import androidx.annotation.Nullable; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.systemui.shade.ShadeController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -57,6 +58,7 @@ public class EmergencyButtonController extends ViewController { private final MetricsLogger mMetricsLogger; private EmergencyButtonCallback mEmergencyButtonCallback; + private LockPatternUtils mLockPatternUtils; private final KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { @@ -83,7 +85,8 @@ public class EmergencyButtonController extends ViewController { KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, PowerManager powerManager, ActivityTaskManager activityTaskManager, ShadeController shadeController, - @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) { + @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, + LockPatternUtils lockPatternUtils) { super(view); mConfigurationController = configurationController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -93,6 +96,7 @@ public class EmergencyButtonController extends ViewController { mShadeController = shadeController; mTelecomManager = telecomManager; mMetricsLogger = metricsLogger; + mLockPatternUtils = lockPatternUtils; } @Override @@ -116,10 +120,12 @@ public class EmergencyButtonController extends ViewController { private void updateEmergencyCallButton() { if (mView != null) { mView.updateEmergencyCallButton( - mTelecomManager != null && mTelecomManager.isInCall(), - getContext().getPackageManager().hasSystemFeature( + /* isInCall= */ mTelecomManager != null && mTelecomManager.isInCall(), + /* hasTelephonyRadio= */ getContext().getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY), - mKeyguardUpdateMonitor.isSimPinVoiceSecure()); + /* simLocked= */ mKeyguardUpdateMonitor.isSimPinVoiceSecure(), + /* isSecure= */ + mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())); } } @@ -178,13 +184,15 @@ public class EmergencyButtonController extends ViewController { @Nullable private final TelecomManager mTelecomManager; private final MetricsLogger mMetricsLogger; + private final LockPatternUtils mLockPatternUtils; @Inject public Factory(ConfigurationController configurationController, KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, PowerManager powerManager, ActivityTaskManager activityTaskManager, ShadeController shadeController, - @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) { + @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, + LockPatternUtils lockPatternUtils) { mConfigurationController = configurationController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -194,6 +202,7 @@ public class EmergencyButtonController extends ViewController { mShadeController = shadeController; mTelecomManager = telecomManager; mMetricsLogger = metricsLogger; + mLockPatternUtils = lockPatternUtils; } /** Construct an {@link com.android.keyguard.EmergencyButtonController}. */ @@ -201,7 +210,7 @@ public class EmergencyButtonController extends ViewController { return new EmergencyButtonController(view, mConfigurationController, mKeyguardUpdateMonitor, mTelephonyManager, mPowerManager, mActivityTaskManager, mShadeController, - mTelecomManager, mMetricsLogger); + mTelecomManager, mMetricsLogger, mLockPatternUtils); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java index 0a4880e1ce66b..3b0644eaab827 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java @@ -33,7 +33,6 @@ import android.widget.TextView; import androidx.annotation.Nullable; -import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.Utils; import com.android.systemui.R; @@ -46,7 +45,6 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { private final TextView mDigitText; private final TextView mKlondikeText; - private final LockPatternUtils mLockPatternUtils; private final PowerManager mPM; private int mDigit = -1; @@ -107,7 +105,6 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { setOnHoverListener(new LiftToActivateListener( (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE))); - mLockPatternUtils = new LockPatternUtils(context); mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index f4cd985adbdb8..51c5183ffee9e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -213,7 +213,8 @@ public class NotificationLockscreenUserManagerImpl implements DeviceProvisionedController deviceProvisionedController, KeyguardStateController keyguardStateController, SecureSettings secureSettings, - DumpManager dumpManager) { + DumpManager dumpManager, + LockPatternUtils lockPatternUtils) { mContext = context; mMainHandler = mainHandler; mDevicePolicyManager = devicePolicyManager; @@ -225,7 +226,7 @@ public class NotificationLockscreenUserManagerImpl implements mClickNotifier = clickNotifier; mOverviewProxyServiceLazy = overviewProxyServiceLazy; statusBarStateController.addCallback(this); - mLockPatternUtils = new LockPatternUtils(context); + mLockPatternUtils = lockPatternUtils; mKeyguardManager = keyguardManager; mBroadcastDispatcher = broadcastDispatcher; mDeviceProvisionedController = deviceProvisionedController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index 452606dfcca4d..8ee1ea8a99167 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -44,6 +44,7 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; +import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -354,7 +355,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { mDeviceProvisionedController, mKeyguardStateController, mSettings, - mock(DumpManager.class)); + mock(DumpManager.class), + mock(LockPatternUtils.class)); } public BroadcastReceiver getBaseBroadcastReceiverForTest() { From feb16cb218d66b6f0ea84b8d8b8764be0db3222c Mon Sep 17 00:00:00 2001 From: Aaron Liu Date: Wed, 22 Feb 2023 13:13:25 -0800 Subject: [PATCH 2/2] Add executors to handle binder call. Use background executor to handle TelecomManager#IsInCall binder call and LockpatternUtils#isSecure which can sometimes lead to binder call. Also added a unit test file. Fixes: 266482108 Test: Unit test and interact with emergency button on bouncer. Observe its visibility. Change-Id: If590f39ebdc622a89d7de36becff973bf116e355 --- .../keyguard/EmergencyButtonController.java | 107 +++++++++++------ .../keyguard/EmergencyButtonControllerTest.kt | 112 ++++++++++++++++++ 2 files changed, 184 insertions(+), 35 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java index 62298f10d6b71..f7e8eb492584b 100644 --- a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java +++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java @@ -18,6 +18,7 @@ package com.android.keyguard; import static com.android.systemui.DejankUtils.whitelistIpcs; +import android.annotation.SuppressLint; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.content.Intent; @@ -31,17 +32,22 @@ import android.telephony.TelephonyManager; import android.util.Log; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.dagger.KeyguardBouncerScope; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.shade.ShadeController; 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 java.util.concurrent.Executor; + import javax.inject.Inject; /** View Controller for {@link com.android.keyguard.EmergencyButton}. */ @@ -59,6 +65,8 @@ public class EmergencyButtonController extends ViewController { private EmergencyButtonCallback mEmergencyButtonCallback; private LockPatternUtils mLockPatternUtils; + private Executor mMainExecutor; + private Executor mBackgroundExecutor; private final KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { @@ -80,13 +88,15 @@ public class EmergencyButtonController extends ViewController { } }; - private EmergencyButtonController(@Nullable EmergencyButton view, + @VisibleForTesting + public EmergencyButtonController(@Nullable EmergencyButton view, ConfigurationController configurationController, KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, PowerManager powerManager, ActivityTaskManager activityTaskManager, ShadeController shadeController, @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, - LockPatternUtils lockPatternUtils) { + LockPatternUtils lockPatternUtils, + Executor mainExecutor, Executor backgroundExecutor) { super(view); mConfigurationController = configurationController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -97,6 +107,8 @@ public class EmergencyButtonController extends ViewController { mTelecomManager = telecomManager; mMetricsLogger = metricsLogger; mLockPatternUtils = lockPatternUtils; + mMainExecutor = mainExecutor; + mBackgroundExecutor = backgroundExecutor; } @Override @@ -117,15 +129,27 @@ public class EmergencyButtonController extends ViewController { mConfigurationController.removeCallback(mConfigurationListener); } - private void updateEmergencyCallButton() { + /** + * Updates the visibility of the emergency button. + * + * This method runs binder calls in a background thread. + */ + @VisibleForTesting + @SuppressLint("MissingPermission") + public void updateEmergencyCallButton() { if (mView != null) { - mView.updateEmergencyCallButton( - /* isInCall= */ mTelecomManager != null && mTelecomManager.isInCall(), - /* hasTelephonyRadio= */ getContext().getPackageManager().hasSystemFeature( - PackageManager.FEATURE_TELEPHONY), - /* simLocked= */ mKeyguardUpdateMonitor.isSimPinVoiceSecure(), - /* isSecure= */ - mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())); + // Run in bg thread to avoid throttling the main thread with binder call. + mBackgroundExecutor.execute(() -> { + boolean isInCall = mTelecomManager != null && mTelecomManager.isInCall(); + boolean isSecure = mLockPatternUtils + .isSecure(KeyguardUpdateMonitor.getCurrentUser()); + mMainExecutor.execute(() -> mView.updateEmergencyCallButton( + /* isInCall= */ isInCall, + /* hasTelephonyRadio= */ getContext().getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_TELEPHONY), + /* simLocked= */ mKeyguardUpdateMonitor.isSimPinVoiceSecure(), + /* isSecure= */ isSecure)); + }); } } @@ -135,6 +159,7 @@ public class EmergencyButtonController extends ViewController { /** * Shows the emergency dialer or returns the user to the existing call. */ + @SuppressLint("MissingPermission") public void takeEmergencyCallAction() { mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_CALL); if (mPowerManager != null) { @@ -142,29 +167,35 @@ public class EmergencyButtonController extends ViewController { } mActivityTaskManager.stopSystemLockTaskMode(); mShadeController.collapseShade(false); - 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); + // Run in bg thread to avoid throttling the main thread with binder call. + mBackgroundExecutor.execute(() -> { + boolean isInCall = mTelecomManager != null && mTelecomManager.isInCall(); + mMainExecutor.execute(() -> { + if (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())); - } + getContext().startActivityAsUser(emergencyDialIntent, + ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), + new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); + } + }); + }); } /** */ @@ -185,6 +216,8 @@ public class EmergencyButtonController extends ViewController { private final TelecomManager mTelecomManager; private final MetricsLogger mMetricsLogger; private final LockPatternUtils mLockPatternUtils; + private final Executor mMainExecutor; + private final Executor mBackgroundExecutor; @Inject public Factory(ConfigurationController configurationController, @@ -192,7 +225,9 @@ public class EmergencyButtonController extends ViewController { PowerManager powerManager, ActivityTaskManager activityTaskManager, ShadeController shadeController, @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, - LockPatternUtils lockPatternUtils) { + LockPatternUtils lockPatternUtils, + @Main Executor mainExecutor, + @Background Executor backgroundExecutor) { mConfigurationController = configurationController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -203,14 +238,16 @@ public class EmergencyButtonController extends ViewController { mTelecomManager = telecomManager; mMetricsLogger = metricsLogger; mLockPatternUtils = lockPatternUtils; + mMainExecutor = mainExecutor; + mBackgroundExecutor = backgroundExecutor; } /** Construct an {@link com.android.keyguard.EmergencyButtonController}. */ public EmergencyButtonController create(EmergencyButton view) { return new EmergencyButtonController(view, mConfigurationController, mKeyguardUpdateMonitor, mTelephonyManager, mPowerManager, mActivityTaskManager, - mShadeController, - mTelecomManager, mMetricsLogger, mLockPatternUtils); + mShadeController, mTelecomManager, mMetricsLogger, mLockPatternUtils, + mMainExecutor, mBackgroundExecutor); } } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt new file mode 100644 index 0000000000000..30fed0b0316fc --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2023 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.app.ActivityTaskManager +import android.content.pm.PackageManager +import android.os.PowerManager +import android.telecom.TelecomManager +import android.telephony.TelephonyManager +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.internal.logging.MetricsLogger +import com.android.internal.widget.LockPatternUtils +import com.android.systemui.SysuiTestCase +import com.android.systemui.shade.ShadeController +import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +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.Mockito +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class EmergencyButtonControllerTest : SysuiTestCase() { + lateinit var underTest: EmergencyButtonController + @Mock lateinit var emergencyButton: EmergencyButton + @Mock lateinit var configurationController: ConfigurationController + @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + @Mock lateinit var telephonyManager: TelephonyManager + @Mock lateinit var powerManager: PowerManager + @Mock lateinit var activityTaskManager: ActivityTaskManager + @Mock lateinit var shadeController: ShadeController + @Mock lateinit var telecomManager: TelecomManager + @Mock lateinit var metricsLogger: MetricsLogger + @Mock lateinit var lockPatternUtils: LockPatternUtils + @Mock lateinit var packageManager: PackageManager + val fakeSystemClock = FakeSystemClock() + val mainExecutor = FakeExecutor(fakeSystemClock) + val backgroundExecutor = FakeExecutor(fakeSystemClock) + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + underTest = + EmergencyButtonController( + emergencyButton, + configurationController, + keyguardUpdateMonitor, + telephonyManager, + powerManager, + activityTaskManager, + shadeController, + telecomManager, + metricsLogger, + lockPatternUtils, + mainExecutor, + backgroundExecutor + ) + context.setMockPackageManager(packageManager) + Mockito.`when`(emergencyButton.context).thenReturn(context) + } + + @Test + fun testUpdateEmergencyButton() { + Mockito.`when`(telecomManager.isInCall).thenReturn(true) + Mockito.`when`(lockPatternUtils.isSecure(anyInt())).thenReturn(true) + Mockito.`when`(packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) + .thenReturn(true) + underTest.updateEmergencyCallButton() + backgroundExecutor.runAllReady() + verify(emergencyButton, never()) + .updateEmergencyCallButton( + /* isInCall= */ any(), + /* hasTelephonyRadio= */ any(), + /* simLocked= */ any(), + /* isSecure= */ any() + ) + mainExecutor.runAllReady() + verify(emergencyButton) + .updateEmergencyCallButton( + /* isInCall= */ eq(true), + /* hasTelephonyRadio= */ eq(true), + /* simLocked= */ any(), + /* isSecure= */ eq(true) + ) + } +}