diff options
6 files changed, 201 insertions, 46 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java index a25b281f807c..c5a06b48e015 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 ea808eb19b90..f7e8eb492584 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,16 +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}. */ @@ -57,6 +64,9 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> { private final MetricsLogger mMetricsLogger; private EmergencyButtonCallback mEmergencyButtonCallback; + private LockPatternUtils mLockPatternUtils; + private Executor mMainExecutor; + private Executor mBackgroundExecutor; private final KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { @@ -78,12 +88,15 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> { } }; - 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) { + @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, + LockPatternUtils lockPatternUtils, + Executor mainExecutor, Executor backgroundExecutor) { super(view); mConfigurationController = configurationController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -93,6 +106,9 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> { mShadeController = shadeController; mTelecomManager = telecomManager; mMetricsLogger = metricsLogger; + mLockPatternUtils = lockPatternUtils; + mMainExecutor = mainExecutor; + mBackgroundExecutor = backgroundExecutor; } @Override @@ -113,13 +129,27 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> { 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( - mTelecomManager != null && mTelecomManager.isInCall(), - getContext().getPackageManager().hasSystemFeature( - PackageManager.FEATURE_TELEPHONY), - mKeyguardUpdateMonitor.isSimPinVoiceSecure()); + // 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)); + }); } } @@ -129,6 +159,7 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> { /** * 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) { @@ -136,29 +167,35 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> { } 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); - - getContext().startActivityAsUser(emergencyDialIntent, - ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), - new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); - } + // 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())); + } + }); + }); } /** */ @@ -178,13 +215,19 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> { @Nullable 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, KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, PowerManager powerManager, ActivityTaskManager activityTaskManager, ShadeController shadeController, - @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) { + @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, + LockPatternUtils lockPatternUtils, + @Main Executor mainExecutor, + @Background Executor backgroundExecutor) { mConfigurationController = configurationController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -194,14 +237,17 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> { mShadeController = shadeController; 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); + mShadeController, mTelecomManager, mMetricsLogger, mLockPatternUtils, + mMainExecutor, mBackgroundExecutor); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java index 0a4880e1ce66..3b0644eaab82 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 f4cd985adbdb..51c5183ffee9 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/keyguard/EmergencyButtonControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt new file mode 100644 index 000000000000..30fed0b0316f --- /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) + ) + } +} 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 452606dfcca4..8ee1ea8a9916 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() { |