diff options
36 files changed, 1217 insertions, 661 deletions
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp index 587902221826..d7afa0e166b3 100644 --- a/libs/WindowManager/Shell/tests/flicker/Android.bp +++ b/libs/WindowManager/Shell/tests/flicker/Android.bp @@ -18,7 +18,7 @@ android_test { name: "WMShellFlickerTests", srcs: ["src/**/*.java", "src/**/*.kt"], manifest: "AndroidManifest.xml", - test_config: "AndroidTest.xml", + test_config: "AndroidTestPhysicalDevices.xml", platform_apis: true, certificate: "platform", test_suites: ["device-tests"], @@ -32,3 +32,21 @@ android_test { "launcher-aosp-tapl" ], } + +android_test { + name: "WMShellFlickerTestsVirtual", + srcs: ["src/**/*.java", "src/**/*.kt"], + manifest: "AndroidManifest.xml", + test_config: "AndroidTestVirtualDevices.xml", + platform_apis: true, + certificate: "platform", + libs: ["android.test.runner"], + static_libs: [ + "androidx.test.ext.junit", + "flickerlib", + "truth-prebuilt", + "app-helpers-core", + "launcher-helper-lib", + "launcher-aosp-tapl" + ], +} diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestPhysicalDevices.xml index 526fc502c0fb..9dd9f42bdf81 100644 --- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml +++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestPhysicalDevices.xml @@ -27,6 +27,7 @@ </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest"> <option name="package" value="com.android.wm.shell.flicker"/> + <option name="include-annotation" value="androidx.test.filters.RequiresDevice" /> <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" /> <option name="shell-timeout" value="6600s" /> <option name="test-timeout" value="6000s" /> @@ -37,4 +38,4 @@ <option name="collect-on-run-ended-only" value="true" /> <option name="clean-up" value="true" /> </metrics_collector> -</configuration> +</configuration>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml new file mode 100644 index 000000000000..afb1166415fc --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright 2020 Google Inc. All Rights Reserved. + --> +<configuration description="Runs WindowManager Shell Flicker Tests"> + <option name="test-tag" value="FlickerTests" /> + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <!-- keeps the screen on during tests --> + <option name="screen-always-on" value="on" /> + <!-- prevents the phone from restarting --> + <option name="force-skip-system-props" value="true" /> + <!-- set WM tracing verbose level to all --> + <option name="run-command" value="cmd window tracing level all" /> + <!-- inform WM to log all transactions --> + <option name="run-command" value="cmd window tracing transaction" /> + <!-- restart launcher to activate TAPL --> + <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner"> + <!-- reboot the device to teardown any crashed tests --> + <option name="cleanup-action" value="REBOOT" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true"/> + <option name="test-file-name" value="WMShellFlickerTests.apk"/> + <option name="test-file-name" value="WMShellFlickerTestApp.apk" /> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.wm.shell.flicker"/> + <option name="exclude-annotation" value="androidx.test.filters.RequiresDevice" /> + <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" /> + <option name="shell-timeout" value="6600s" /> + <option name="test-timeout" value="6000s" /> + <option name="hidden-api-checks" value="false" /> + </test> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.wm.shell.flicker/files" /> + <option name="collect-on-run-ended-only" value="true" /> + <option name="clean-up" value="true" /> + </metrics_collector> +</configuration>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt index 308a36efef87..47a62ce92d11 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation import android.support.test.launcherhelper.ILauncherStrategy -import com.android.server.wm.flicker.StandardAppHelper +import com.android.server.wm.flicker.helpers.StandardAppHelper abstract class FlickerAppHelper( instr: Instrumentation, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt index 4b04449bdbc2..c3c576d3f28c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.pip import android.view.Surface import androidx.test.filters.FlakyTest -import androidx.test.filters.LargeTest +import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.dsl.flicker import com.android.server.wm.flicker.helpers.closePipWindow import com.android.server.wm.flicker.helpers.expandPipWindow @@ -41,7 +41,7 @@ import org.junit.runners.Parameterized * Test Pip launch. * To run this test: `atest FlickerTests:PipToAppTest` */ -@LargeTest +@RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @FlakyTest(bugId = 152738416) diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java index dadbc22760b9..3af7507ae2b4 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java @@ -30,7 +30,6 @@ import androidx.annotation.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.ViewMediatorCallback; -import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.R; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.navigationbar.CarNavigationBarController; @@ -40,6 +39,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.KeyguardBouncer; +import com.android.systemui.statusbar.phone.KeyguardBouncer.Factory; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.StatusBar; @@ -66,7 +66,7 @@ public class CarKeyguardViewController extends OverlayViewController implements private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; private final ViewMediatorCallback mViewMediatorCallback; private final CarNavigationBarController mCarNavigationBarController; - private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; + private final Factory mKeyguardBouncerFactory; // Needed to instantiate mBouncer. private final KeyguardBouncer.BouncerExpansionCallback mExpansionCallback = new KeyguardBouncer.BouncerExpansionCallback() { @@ -107,7 +107,7 @@ public class CarKeyguardViewController extends OverlayViewController implements Lazy<BiometricUnlockController> biometricUnlockControllerLazy, ViewMediatorCallback viewMediatorCallback, CarNavigationBarController carNavigationBarController, - KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { + KeyguardBouncer.Factory keyguardBouncerFactory) { super(R.id.keyguard_stub, overlayViewGlobalStateController); @@ -118,7 +118,7 @@ public class CarKeyguardViewController extends OverlayViewController implements mBiometricUnlockControllerLazy = biometricUnlockControllerLazy; mViewMediatorCallback = viewMediatorCallback; mCarNavigationBarController = carNavigationBarController; - mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; + mKeyguardBouncerFactory = keyguardBouncerFactory; registerUserSwitchedListener(); } @@ -130,9 +130,8 @@ public class CarKeyguardViewController extends OverlayViewController implements @Override public void onFinishInflate() { - mBouncer = mKeyguardBouncerComponentFactory - .build(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback) - .createKeyguardBouncer(); + mBouncer = mKeyguardBouncerFactory + .create(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback); mBiometricUnlockControllerLazy.get().setKeyguardViewController(this); } diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java index 63d4004fb640..062ab4115263 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java @@ -36,7 +36,6 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; -import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarServiceProvider; @@ -67,9 +66,7 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { @Mock private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener; @Mock - private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; - @Mock - private KeyguardBouncerComponent mKeyguardBouncerComponent; + private KeyguardBouncer.Factory mKeyguardBouncerFactory; @Mock private KeyguardBouncer mBouncer; @@ -77,11 +74,10 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); - when(mKeyguardBouncerComponentFactory.build( + when(mKeyguardBouncerFactory.create( any(ViewGroup.class), any(KeyguardBouncer.BouncerExpansionCallback.class))) - .thenReturn(mKeyguardBouncerComponent); - when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer); + .thenReturn(mBouncer); mCarKeyguardViewController = new CarKeyguardViewController( Handler.getMain(), @@ -92,7 +88,7 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { () -> mock(BiometricUnlockController.class), mock(ViewMediatorCallback.class), mock(CarNavigationBarController.class), - mKeyguardBouncerComponentFactory + mKeyguardBouncerFactory ); mCarKeyguardViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate( R.layout.sysui_overlay_window, /* root= */ null)); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java index 57b3761c294f..08e9cf60a65a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java @@ -16,32 +16,11 @@ package com.android.keyguard; -import android.app.ActivityManager; import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Resources; import android.graphics.Canvas; -import android.media.AudioManager; -import android.os.SystemClock; -import android.service.trust.TrustAgentService; -import android.telephony.TelephonyManager; import android.util.AttributeSet; -import android.util.Log; -import android.view.KeyEvent; import android.widget.FrameLayout; -import androidx.annotation.VisibleForTesting; - -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback; -import com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import com.android.settingslib.Utils; -import com.android.systemui.Dependency; -import com.android.systemui.R; -import com.android.systemui.plugins.ActivityStarter.OnDismissAction; - -import java.io.File; - /** * Base class for keyguard view. {@link #reset} is where you should * reset the state of your view. Use the {@link KeyguardViewCallback} via @@ -51,59 +30,10 @@ import java.io.File; * Handles intercepting of media keys that still work when the keyguard is * showing. */ -public class KeyguardHostView extends FrameLayout implements SecurityCallback { +public class KeyguardHostView extends FrameLayout { - private AudioManager mAudioManager; - private TelephonyManager mTelephonyManager = null; protected ViewMediatorCallback mViewMediatorCallback; - protected LockPatternUtils mLockPatternUtils; - private OnDismissAction mDismissAction; - private Runnable mCancelAction; - private final KeyguardUpdateMonitorCallback mUpdateCallback = - new KeyguardUpdateMonitorCallback() { - - @Override - public void onUserSwitchComplete(int userId) { - getSecurityContainer().showPrimarySecurityScreen(false /* turning off */); - } - - @Override - public void onTrustGrantedWithFlags(int flags, int userId) { - if (userId != KeyguardUpdateMonitor.getCurrentUser()) return; - if (!isAttachedToWindow()) return; - boolean bouncerVisible = isVisibleToUser(); - boolean initiatedByUser = - (flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0; - boolean dismissKeyguard = - (flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0; - - if (initiatedByUser || dismissKeyguard) { - if (mViewMediatorCallback.isScreenOn() && (bouncerVisible || dismissKeyguard)) { - if (!bouncerVisible) { - // The trust agent dismissed the keyguard without the user proving - // that they are present (by swiping up to show the bouncer). That's fine if - // the user proved presence via some other way to the trust agent. - Log.i(TAG, "TrustAgent dismissed Keyguard."); - } - dismiss(false /* authenticated */, userId, - /* bypassSecondaryLockScreen */ false); - } else { - mViewMediatorCallback.playTrustedSound(); - } - } - } - }; - - // Whether the volume keys should be handled by keyguard. If true, then - // they will be handled here for specific media types such as music, otherwise - // the audio service will bring up the volume dialog. - private static final boolean KEYGUARD_MANAGES_VOLUME = false; - public static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final String TAG = "KeyguardViewBase"; - - @VisibleForTesting - protected KeyguardSecurityContainer mSecurityContainer; public KeyguardHostView(Context context) { this(context, null); @@ -111,7 +41,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { public KeyguardHostView(Context context, AttributeSet attrs) { super(context, attrs); - Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateCallback); } @Override @@ -122,337 +51,7 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { } } - /** - * Sets an action to run when keyguard finishes. - * - * @param action - */ - public void setOnDismissAction(OnDismissAction action, Runnable cancelAction) { - if (mCancelAction != null) { - mCancelAction.run(); - mCancelAction = null; - } - mDismissAction = action; - mCancelAction = cancelAction; - } - - public boolean hasDismissActions() { - return mDismissAction != null || mCancelAction != null; - } - - public void cancelDismissAction() { - setOnDismissAction(null, null); - } - - @Override - protected void onFinishInflate() { - mSecurityContainer = - findViewById(R.id.keyguard_security_container); - mLockPatternUtils = new LockPatternUtils(mContext); - mSecurityContainer.setLockPatternUtils(mLockPatternUtils); - mSecurityContainer.setSecurityCallback(this); - mSecurityContainer.showPrimarySecurityScreen(false); - } - - /** - * Called when the view needs to be shown. - */ - public void showPrimarySecurityScreen() { - if (DEBUG) Log.d(TAG, "show()"); - mSecurityContainer.showPrimarySecurityScreen(false); - } - - public KeyguardSecurityView getCurrentSecurityView() { - return mSecurityContainer != null ? mSecurityContainer.getCurrentSecurityView() : null; - } - - /** - * Show a string explaining why the security view needs to be solved. - * - * @param reason a flag indicating which string should be shown, see - * {@link KeyguardSecurityView#PROMPT_REASON_NONE}, - * {@link KeyguardSecurityView#PROMPT_REASON_RESTART}, - * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and - * {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}. - */ - public void showPromptReason(int reason) { - mSecurityContainer.showPromptReason(reason); - } - - public void showMessage(CharSequence message, ColorStateList colorState) { - mSecurityContainer.showMessage(message, colorState); - } - - public void showErrorMessage(CharSequence message) { - showMessage(message, Utils.getColorError(mContext)); - } - - /** - * Dismisses the keyguard by going to the next screen or making it gone. - * @param targetUserId a user that needs to be the foreground user at the dismissal completion. - * @return True if the keyguard is done. - */ - public boolean dismiss(int targetUserId) { - return dismiss(false, targetUserId, false); - } - - public boolean handleBackKey() { - if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) { - mSecurityContainer.dismiss(false, KeyguardUpdateMonitor.getCurrentUser()); - return true; - } - return false; - } - - protected KeyguardSecurityContainer getSecurityContainer() { - return mSecurityContainer; - } - - @Override - public boolean dismiss(boolean authenticated, int targetUserId, - boolean bypassSecondaryLockScreen) { - return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId, - bypassSecondaryLockScreen); - } - - /** - * Authentication has happened and it's time to dismiss keyguard. This function - * should clean up and inform KeyguardViewMediator. - * - * @param strongAuth whether the user has authenticated with strong authentication like - * pattern, password or PIN but not by trust agents or fingerprint - * @param targetUserId a user that needs to be the foreground user at the dismissal completion. - */ - @Override - public void finish(boolean strongAuth, int targetUserId) { - // If there's a pending runnable because the user interacted with a widget - // and we're leaving keyguard, then run it. - boolean deferKeyguardDone = false; - if (mDismissAction != null) { - deferKeyguardDone = mDismissAction.onDismiss(); - mDismissAction = null; - mCancelAction = null; - } - if (mViewMediatorCallback != null) { - if (deferKeyguardDone) { - mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId); - } else { - mViewMediatorCallback.keyguardDone(strongAuth, targetUserId); - } - } - } - - @Override - public void reset() { - mViewMediatorCallback.resetKeyguard(); - } - - @Override - public void onCancelClicked() { - mViewMediatorCallback.onCancelClicked(); - } - - public void resetSecurityContainer() { - mSecurityContainer.reset(); - } - - @Override - public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) { - if (mViewMediatorCallback != null) { - mViewMediatorCallback.setNeedsInput(needsInput); - } - } - - public CharSequence getAccessibilityTitleForCurrentMode() { - return mSecurityContainer.getTitle(); - } - - public void userActivity() { - if (mViewMediatorCallback != null) { - mViewMediatorCallback.userActivity(); - } - } - - /** - * Called when the Keyguard is not actively shown anymore on the screen. - */ - public void onPause() { - if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s", - Integer.toHexString(hashCode()), SystemClock.uptimeMillis())); - mSecurityContainer.showPrimarySecurityScreen(true); - mSecurityContainer.onPause(); - clearFocus(); - } - - /** - * Called when the Keyguard is actively shown on the screen. - */ - public void onResume() { - if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); - mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON); - requestFocus(); - } - - /** - * Starts the animation when the Keyguard gets shown. - */ - public void startAppearAnimation() { - mSecurityContainer.startAppearAnimation(); - } - - public void startDisappearAnimation(Runnable finishRunnable) { - if (!mSecurityContainer.startDisappearAnimation(finishRunnable) && finishRunnable != null) { - finishRunnable.run(); - } - } - - /** - * Called before this view is being removed. - */ - public void cleanUp() { - getSecurityContainer().onPause(); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - if (interceptMediaKey(event)) { - return true; - } - return super.dispatchKeyEvent(event); - } - - /** - * Allows the media keys to work when the keyguard is showing. - * The media keys should be of no interest to the actual keyguard view(s), - * so intercepting them here should not be of any harm. - * @param event The key event - * @return whether the event was consumed as a media key. - */ - public boolean interceptMediaKey(KeyEvent event) { - final int keyCode = event.getKeyCode(); - if (event.getAction() == KeyEvent.ACTION_DOWN) { - switch (keyCode) { - case KeyEvent.KEYCODE_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - /* Suppress PLAY/PAUSE toggle when phone is ringing or - * in-call to avoid music playback */ - if (mTelephonyManager == null) { - mTelephonyManager = (TelephonyManager) getContext().getSystemService( - Context.TELEPHONY_SERVICE); - } - if (mTelephonyManager != null && - mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) { - return true; // suppress key event - } - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: - case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: - case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { - handleMediaKeyEvent(event); - return true; - } - - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - case KeyEvent.KEYCODE_VOLUME_MUTE: { - if (KEYGUARD_MANAGES_VOLUME) { - synchronized (this) { - if (mAudioManager == null) { - mAudioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - } - } - // Volume buttons should only function for music (local or remote). - // TODO: Actually handle MUTE. - mAudioManager.adjustSuggestedStreamVolume( - keyCode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER /* direction */, - AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */); - // Don't execute default volume behavior - return true; - } else { - return false; - } - } - } - } else if (event.getAction() == KeyEvent.ACTION_UP) { - switch (keyCode) { - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: - case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: - case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { - handleMediaKeyEvent(event); - return true; - } - } - } - return false; - } - - private void handleMediaKeyEvent(KeyEvent keyEvent) { - synchronized (this) { - if (mAudioManager == null) { - mAudioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - } - } - mAudioManager.dispatchMediaKeyEvent(keyEvent); - } - - /** - * In general, we enable unlocking the insecure keyguard with the menu key. However, there are - * some cases where we wish to disable it, notably when the menu button placement or technology - * is prone to false positives. - * - * @return true if the menu key should be enabled - */ - private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; - public boolean shouldEnableMenuKey() { - final Resources res = getResources(); - final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); - final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); - final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); - return !configDisabled || isTestHarness || fileOverride; - } - public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) { mViewMediatorCallback = viewMediatorCallback; - // Update ViewMediator with the current input method requirements - mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput()); - } - - public void setLockPatternUtils(LockPatternUtils utils) { - mLockPatternUtils = utils; - mSecurityContainer.setLockPatternUtils(utils); - } - - public SecurityMode getSecurityMode() { - return mSecurityContainer.getSecurityMode(); - } - - public SecurityMode getCurrentSecurityMode() { - return mSecurityContainer.getCurrentSecurityMode(); - } - - /** - * When bouncer was visible and is starting to become hidden. - */ - public void onStartingToHide() { - mSecurityContainer.onStartingToHide(); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java new file mode 100644 index 000000000000..7aabb17de90c --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java @@ -0,0 +1,460 @@ +/* + * 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; + +import android.app.ActivityManager; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.media.AudioManager; +import android.os.SystemClock; +import android.service.trust.TrustAgentService; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.util.MathUtils; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnKeyListener; +import android.view.ViewTreeObserver; + +import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.keyguard.dagger.KeyguardBouncerScope; +import com.android.settingslib.Utils; +import com.android.systemui.R; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.phone.KeyguardBouncer; +import com.android.systemui.util.ViewController; + +import java.io.File; + +import javax.inject.Inject; + +/** Controller for a {@link KeyguardHostView}. */ +@KeyguardBouncerScope +public class KeyguardHostViewController extends ViewController<KeyguardHostView> { + private static final String TAG = "KeyguardViewBase"; + public static final boolean DEBUG = KeyguardConstants.DEBUG; + // Whether the volume keys should be handled by keyguard. If true, then + // they will be handled here for specific media types such as music, otherwise + // the audio service will bring up the volume dialog. + private static final boolean KEYGUARD_MANAGES_VOLUME = false; + + private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; + + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final KeyguardSecurityContainerController mKeyguardSecurityContainerController; + private final TelephonyManager mTelephonyManager; + private final ViewMediatorCallback mViewMediatorCallback; + private final AudioManager mAudioManager; + + private ActivityStarter.OnDismissAction mDismissAction; + private Runnable mCancelAction; + + private final KeyguardUpdateMonitorCallback mUpdateCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onUserSwitchComplete(int userId) { + mKeyguardSecurityContainerController.showPrimarySecurityScreen( + false /* turning off */); + } + + @Override + public void onTrustGrantedWithFlags(int flags, int userId) { + if (userId != KeyguardUpdateMonitor.getCurrentUser()) return; + boolean bouncerVisible = mView.isVisibleToUser(); + boolean initiatedByUser = + (flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0; + boolean dismissKeyguard = + (flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0; + + if (initiatedByUser || dismissKeyguard) { + if (mViewMediatorCallback.isScreenOn() + && (bouncerVisible || dismissKeyguard)) { + if (!bouncerVisible) { + // The trust agent dismissed the keyguard without the user proving + // that they are present (by swiping up to show the bouncer). That's + // fine if the user proved presence via some other way to the trust + //agent. + Log.i(TAG, "TrustAgent dismissed Keyguard."); + } + mSecurityCallback.dismiss(false /* authenticated */, userId, + /* bypassSecondaryLockScreen */ false); + } else { + mViewMediatorCallback.playTrustedSound(); + } + } + } + }; + + private final SecurityCallback mSecurityCallback = new SecurityCallback() { + + @Override + public boolean dismiss(boolean authenticated, int targetUserId, + boolean bypassSecondaryLockScreen) { + return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish( + authenticated, targetUserId, bypassSecondaryLockScreen); + } + + @Override + public void userActivity() { + mViewMediatorCallback.userActivity(); + } + + @Override + public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) { + mViewMediatorCallback.setNeedsInput(needsInput); + } + + /** + * Authentication has happened and it's time to dismiss keyguard. This function + * should clean up and inform KeyguardViewMediator. + * + * @param strongAuth whether the user has authenticated with strong authentication like + * pattern, password or PIN but not by trust agents or fingerprint + * @param targetUserId a user that needs to be the foreground user at the dismissal + * completion. + */ + @Override + public void finish(boolean strongAuth, int targetUserId) { + // If there's a pending runnable because the user interacted with a widget + // and we're leaving keyguard, then run it. + boolean deferKeyguardDone = false; + if (mDismissAction != null) { + deferKeyguardDone = mDismissAction.onDismiss(); + mDismissAction = null; + mCancelAction = null; + } + if (mViewMediatorCallback != null) { + if (deferKeyguardDone) { + mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId); + } else { + mViewMediatorCallback.keyguardDone(strongAuth, targetUserId); + } + } + } + + @Override + public void reset() { + mViewMediatorCallback.resetKeyguard(); + } + + @Override + public void onCancelClicked() { + mViewMediatorCallback.onCancelClicked(); + } + }; + + private OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event); + + @Inject + public KeyguardHostViewController(KeyguardHostView view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + KeyguardSecurityContainerController keyguardSecurityContainerController, + AudioManager audioManager, + TelephonyManager telephonyManager, + ViewMediatorCallback viewMediatorCallback) { + super(view); + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mKeyguardSecurityContainerController = keyguardSecurityContainerController; + mAudioManager = audioManager; + mTelephonyManager = telephonyManager; + mViewMediatorCallback = viewMediatorCallback; + } + + /** Initialize the Controller. */ + public void init() { + super.init(); + mView.setViewMediatorCallback(mViewMediatorCallback); + // Update ViewMediator with the current input method requirements + mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput()); + mKeyguardSecurityContainerController.init(); + mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback); + mKeyguardSecurityContainerController.showPrimarySecurityScreen(false); + } + + @Override + protected void onViewAttached() { + mKeyguardUpdateMonitor.registerCallback(mUpdateCallback); + mView.setOnKeyListener(mOnKeyListener); + } + + @Override + protected void onViewDetached() { + mKeyguardUpdateMonitor.removeCallback(mUpdateCallback); + mView.setOnKeyListener(null); + } + + /** Called before this view is being removed. */ + public void cleanUp() { + mKeyguardSecurityContainerController.onPause(); + } + + public void resetSecurityContainer() { + mKeyguardSecurityContainerController.reset(); + } + + /** + * Dismisses the keyguard by going to the next screen or making it gone. + * @param targetUserId a user that needs to be the foreground user at the dismissal completion. + * @return True if the keyguard is done. + */ + public boolean dismiss(int targetUserId) { + return mSecurityCallback.dismiss(false, targetUserId, false); + } + + /** + * Called when the Keyguard is actively shown on the screen. + */ + public void onResume() { + if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); + mKeyguardSecurityContainerController.onResume(KeyguardSecurityView.SCREEN_ON); + mView.requestFocus(); + } + + public CharSequence getAccessibilityTitleForCurrentMode() { + return mKeyguardSecurityContainerController.getTitle(); + } + + /** + * Starts the animation when the Keyguard gets shown. + */ + public void appear(int statusBarHeight) { + // We might still be collapsed and the view didn't have time to layout yet or still + // be small, let's wait on the predraw to do the animation in that case. + if (mView.getHeight() != 0 && mView.getHeight() != statusBarHeight) { + mKeyguardSecurityContainerController.startAppearAnimation(); + } else { + mView.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + mView.getViewTreeObserver().removeOnPreDrawListener(this); + mKeyguardSecurityContainerController.startAppearAnimation(); + return true; + } + }); + mView.requestLayout(); + } + } + + /** + * Show a string explaining why the security view needs to be solved. + * + * @param reason a flag indicating which string should be shown, see + * {@link KeyguardSecurityView#PROMPT_REASON_NONE}, + * {@link KeyguardSecurityView#PROMPT_REASON_RESTART}, + * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and + * {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}. + */ + public void showPromptReason(int reason) { + mKeyguardSecurityContainerController.showPromptReason(reason); + } + + public void showMessage(CharSequence message, ColorStateList colorState) { + mKeyguardSecurityContainerController.showMessage(message, colorState); + } + + public void showErrorMessage(CharSequence customMessage) { + showMessage(customMessage, Utils.getColorError(mView.getContext())); + } + + /** + * Sets an action to run when keyguard finishes. + * + * @param action + */ + public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) { + if (mCancelAction != null) { + mCancelAction.run(); + mCancelAction = null; + } + mDismissAction = action; + mCancelAction = cancelAction; + } + + public void cancelDismissAction() { + setOnDismissAction(null, null); + } + + public void startDisappearAnimation(Runnable finishRunnable) { + if (!mKeyguardSecurityContainerController.startDisappearAnimation(finishRunnable) + && finishRunnable != null) { + finishRunnable.run(); + } + } + + /** + * Called when the Keyguard is not actively shown anymore on the screen. + */ + public void onPause() { + if (DEBUG) { + Log.d(TAG, String.format("screen off, instance %s at %s", + Integer.toHexString(hashCode()), SystemClock.uptimeMillis())); + } + mKeyguardSecurityContainerController.showPrimarySecurityScreen(true); + mKeyguardSecurityContainerController.onPause(); + mView.clearFocus(); + } + + /** + * Called when the view needs to be shown. + */ + public void showPrimarySecurityScreen() { + if (DEBUG) Log.d(TAG, "show()"); + mKeyguardSecurityContainerController.showPrimarySecurityScreen(false); + } + + public void setExpansion(float fraction) { + float alpha = MathUtils.map(KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction); + mView.setAlpha(MathUtils.constrain(alpha, 0f, 1f)); + mView.setTranslationY(fraction * mView.getHeight()); + } + + /** + * When bouncer was visible and is starting to become hidden. + */ + public void onStartingToHide() { + mKeyguardSecurityContainerController.onStartingToHide(); + } + + public boolean hasDismissActions() { + return mDismissAction != null || mCancelAction != null; + } + + public SecurityMode getCurrentSecurityMode() { + return mKeyguardSecurityContainerController.getCurrentSecurityMode(); + } + + public int getTop() { + int top = mView.getTop(); + // The password view has an extra top padding that should be ignored. + if (getCurrentSecurityMode() == SecurityMode.Password) { + View messageArea = mView.findViewById(R.id.keyguard_message_area); + top += messageArea.getTop(); + } + return top; + } + + public boolean handleBackKey() { + if (mKeyguardSecurityContainerController.getCurrentSecuritySelection() + != SecurityMode.None) { + mKeyguardSecurityContainerController.dismiss( + false, KeyguardUpdateMonitor.getCurrentUser()); + return true; + } + return false; + } + + /** + * In general, we enable unlocking the insecure keyguard with the menu key. However, there are + * some cases where we wish to disable it, notably when the menu button placement or technology + * is prone to false positives. + * + * @return true if the menu key should be enabled + */ + public boolean shouldEnableMenuKey() { + final Resources res = mView.getResources(); + final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); + final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); + final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); + return !configDisabled || isTestHarness || fileOverride; + } + + /** + * Allows the media keys to work when the keyguard is showing. + * The media keys should be of no interest to the actual keyguard view(s), + * so intercepting them here should not be of any harm. + * @param event The key event + * @return whether the event was consumed as a media key. + */ + public boolean interceptMediaKey(KeyEvent event) { + int keyCode = event.getKeyCode(); + if (event.getAction() == KeyEvent.ACTION_DOWN) { + switch (keyCode) { + case KeyEvent.KEYCODE_MEDIA_PLAY: + case KeyEvent.KEYCODE_MEDIA_PAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + /* Suppress PLAY/PAUSE toggle when phone is ringing or + * in-call to avoid music playback */ + if (mTelephonyManager != null && + mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) { + return true; // suppress key event + } + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_RECORD: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { + handleMediaKeyEvent(event); + return true; + } + + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_VOLUME_MUTE: { + if (KEYGUARD_MANAGES_VOLUME) { + // Volume buttons should only function for music (local or remote). + // TODO: Actually handle MUTE. + mAudioManager.adjustSuggestedStreamVolume( + keyCode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER /* direction */, + AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */); + // Don't execute default volume behavior + return true; + } else { + return false; + } + } + } + } else if (event.getAction() == KeyEvent.ACTION_UP) { + switch (keyCode) { + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_PLAY: + case KeyEvent.KEYCODE_MEDIA_PAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_RECORD: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { + handleMediaKeyEvent(event); + return true; + } + } + } + return false; + } + + + private void handleMediaKeyEvent(KeyEvent keyEvent) { + mAudioManager.dispatchMediaKeyEvent(keyEvent); + } + + public void finish(boolean strongAuth, int currentUser) { + mSecurityCallback.finish(strongAuth, currentUser); + } + + +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java new file mode 100644 index 000000000000..f056bdbb9706 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java @@ -0,0 +1,68 @@ +/* + * 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; + +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** Controller for a {@link KeyguardMessageAreaController}. */ +public class KeyguardMessageAreaController extends ViewController<KeyguardMessageArea> { + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final ConfigurationController mConfigurationController; + + private KeyguardMessageAreaController(KeyguardMessageArea view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + ConfigurationController configurationController) { + super(view); + + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mConfigurationController = configurationController; + } + + @Override + protected void onViewAttached() { + //mConfigurationController.addCallback(); + //mKeyguardUpdateMonitor.registerCallback(); + } + + @Override + protected void onViewDetached() { + //mConfigurationController.removeCallback(); + //mKeyguardUpdateMonitor.removeCallback(); + } + + /** Factory for createing {@link com.android.keyguard.KeyguardMessageAreaController}. */ + public static class Factory { + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final ConfigurationController mConfigurationController; + + @Inject + public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor, + ConfigurationController configurationController) { + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mConfigurationController = configurationController; + } + + /** Build a new {@link KeyguardMessageAreaController}. */ + public KeyguardMessageAreaController create(KeyguardMessageArea view) { + return new KeyguardMessageAreaController( + view, mKeyguardUpdateMonitor, mConfigurationController); + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java new file mode 100644 index 000000000000..5c125fcc95cb --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java @@ -0,0 +1,48 @@ +/* + * 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; + +import android.view.ViewGroup; + +import com.android.keyguard.dagger.KeyguardBouncerScope; +import com.android.keyguard.dagger.RootView; +import com.android.systemui.statusbar.phone.KeyguardBouncer; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; +/** Controller for a {@link KeyguardBouncer}'s Root view. */ +@KeyguardBouncerScope +public class KeyguardRootViewController extends ViewController<ViewGroup> { + @Inject + public KeyguardRootViewController(@RootView ViewGroup view) { + super(view); + } + + public ViewGroup getView() { + return mView; + } + + @Override + protected void onViewAttached() { + + } + + @Override + protected void onViewDetached() { + + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java new file mode 100644 index 000000000000..17f25bd08ef4 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -0,0 +1,118 @@ +/* + * 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; + +import android.content.res.ColorStateList; + +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** Controller for {@link KeyguardSecurityContainer} */ +public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer> { + + private final LockPatternUtils mLockPatternUtils; + private final KeyguardSecurityViewController.Factory mKeyguardSecurityViewControllerFactory; + + @Inject + KeyguardSecurityContainerController(KeyguardSecurityContainer view, + LockPatternUtils lockPatternUtils, + KeyguardSecurityViewController.Factory keyguardSecurityViewControllerFactory) { + super(view); + mLockPatternUtils = lockPatternUtils; + view.setLockPatternUtils(mLockPatternUtils); + mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; + } + + @Override + protected void onViewAttached() { + } + + @Override + protected void onViewDetached() { + } + + /** */ + public void onPause() { + mView.onPause(); + } + + public void showPrimarySecurityScreen(boolean turningOff) { + mView.showPrimarySecurityScreen(turningOff); + } + + public void showPromptReason(int reason) { + mView.showPromptReason(reason); + } + + public void showMessage(CharSequence message, ColorStateList colorState) { + mView.showMessage(message, colorState); + } + + public SecurityMode getCurrentSecuritySelection() { + return mView.getCurrentSecuritySelection(); + } + + public void dismiss(boolean authenticated, int targetUserId) { + mView.dismiss(authenticated, targetUserId); + } + + public void reset() { + mView.reset(); + } + + public CharSequence getTitle() { + return mView.getTitle(); + } + + public void onResume(int screenOn) { + mView.onResume(screenOn); + } + + public void startAppearAnimation() { + mView.startAppearAnimation(); + } + + public boolean startDisappearAnimation(Runnable onFinishRunnable) { + return mView.startDisappearAnimation(onFinishRunnable); + } + + public void onStartingToHide() { + mView.onStartingToHide(); + } + + public void setSecurityCallback(SecurityCallback securityCallback) { + mView.setSecurityCallback(securityCallback); + } + + public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId, + boolean bypassSecondaryLockScreen) { + return mView.showNextSecurityScreenOrFinish( + authenticated, targetUserId, bypassSecondaryLockScreen); + } + + public boolean needsInput() { + return mView.needsInput(); + } + + public SecurityMode getCurrentSecurityMode() { + return mView.getCurrentSecurityMode(); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java new file mode 100644 index 000000000000..ef9ba19fbb43 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java @@ -0,0 +1,58 @@ +/* + * 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; + +import android.view.View; + +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + + +/** Controller for a {@link KeyguardSecurityView}. */ +public class KeyguardSecurityViewController extends ViewController<View> { + + private final KeyguardSecurityView mView; + + private KeyguardSecurityViewController(KeyguardSecurityView view) { + super((View) view); + // KeyguardSecurityView isn't actually a View, so we need to track it ourselves. + mView = view; + } + + @Override + protected void onViewAttached() { + + } + + @Override + protected void onViewDetached() { + + } + + /** Factory for a {@link KeyguardSecurityViewController}. */ + public static class Factory { + @Inject + public Factory() { + } + + /** Create a new {@link KeyguardSecurityViewController}. */ + public KeyguardSecurityViewController create(KeyguardSecurityView view) { + return new KeyguardSecurityViewController(view); + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java index 84deaca096aa..5160b7e01e89 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java @@ -16,27 +16,27 @@ package com.android.keyguard.dagger; -import android.view.ViewGroup; - +import com.android.keyguard.KeyguardHostViewController; +import com.android.keyguard.KeyguardRootViewController; import com.android.systemui.statusbar.phone.KeyguardBouncer; -import dagger.BindsInstance; import dagger.Subcomponent; /** * Dagger Subcomponent for the {@link KeyguardBouncer}. */ -@Subcomponent +@Subcomponent(modules = {KeyguardBouncerModule.class}) @KeyguardBouncerScope public interface KeyguardBouncerComponent { /** Simple factory for {@link KeyguardBouncerComponent}. */ @Subcomponent.Factory interface Factory { - KeyguardBouncerComponent build( - @BindsInstance @ContainerView ViewGroup container, - @BindsInstance KeyguardBouncer.BouncerExpansionCallback bouncerExpansionCallback); + KeyguardBouncerComponent create(); } - /** */ - KeyguardBouncer createKeyguardBouncer(); + /** Returns a {@link KeyguardRootViewController}. */ + KeyguardRootViewController getKeyguardRootViewController(); + + /** Returns a {@link KeyguardHostViewController}. */ + KeyguardHostViewController getKeyguardHostViewController(); } diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java new file mode 100644 index 000000000000..b6010c8915e7 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java @@ -0,0 +1,64 @@ +/* + * 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 android.view.LayoutInflater; +import android.view.ViewGroup; + +import com.android.keyguard.KeyguardHostView; +import com.android.keyguard.KeyguardMessageArea; +import com.android.keyguard.KeyguardSecurityContainer; +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.KeyguardBouncer; + +import dagger.Module; +import dagger.Provides; + +/** + * Module to create and access view related to the {@link KeyguardBouncer}. + */ +@Module +public interface KeyguardBouncerModule { + /** */ + @Provides + @KeyguardBouncerScope + @RootView + static ViewGroup providesRootView(LayoutInflater layoutInflater) { + return (ViewGroup) layoutInflater.inflate(R.layout.keyguard_bouncer, null); + } + + /** */ + @Provides + @KeyguardBouncerScope + static KeyguardMessageArea providesKeyguardMessageArea(@RootView ViewGroup viewGroup) { + return viewGroup.findViewById(R.id.keyguard_message_area); + } + + /** */ + @Provides + @KeyguardBouncerScope + static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView) { + return rootView.findViewById(R.id.keyguard_host_view); + } + + /** */ + @Provides + @KeyguardBouncerScope + static KeyguardSecurityContainer preovidesKeyguardSecurityContainer(KeyguardHostView hostView) { + return hostView.findViewById(R.id.keyguard_security_container); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java b/packages/SystemUI/src/com/android/keyguard/dagger/RootView.java index e65f19db5ac2..5ebff097604b 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/RootView.java @@ -26,5 +26,5 @@ import javax.inject.Qualifier; @Qualifier @Documented @Retention(RUNTIME) -public @interface ContainerView { +public @interface RootView { } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 09034c0899f5..3665c39bd9ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -25,26 +25,21 @@ import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; -import android.util.MathUtils; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.WindowInsets; -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardHostView; +import com.android.keyguard.KeyguardHostViewController; +import com.android.keyguard.KeyguardRootViewController; import com.android.keyguard.KeyguardSecurityModel; import com.android.keyguard.KeyguardSecurityView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; -import com.android.keyguard.dagger.ContainerView; -import com.android.keyguard.dagger.KeyguardBouncerScope; +import com.android.keyguard.dagger.KeyguardBouncerComponent; +import com.android.keyguard.dagger.RootView; import com.android.systemui.DejankUtils; -import com.android.systemui.Dependency; -import com.android.systemui.R; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.shared.system.SysUiStatsLog; @@ -57,18 +52,16 @@ import javax.inject.Inject; /** * A class which manages the bouncer on the lockscreen. */ -@KeyguardBouncerScope public class KeyguardBouncer { private static final String TAG = "KeyguardBouncer"; static final long BOUNCER_FACE_DELAY = 1200; - static final float ALPHA_EXPANSION_THRESHOLD = 0.95f; + public static final float ALPHA_EXPANSION_THRESHOLD = 0.95f; static final float EXPANSION_HIDDEN = 1f; static final float EXPANSION_VISIBLE = 0f; protected final Context mContext; protected final ViewMediatorCallback mCallback; - protected final LockPatternUtils mLockPatternUtils; protected final ViewGroup mContainer; private final FalsingManager mFalsingManager; private final DismissCallbackRegistry mDismissCallbackRegistry; @@ -76,6 +69,8 @@ public class KeyguardBouncer { private final BouncerExpansionCallback mExpansionCallback; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final KeyguardStateController mKeyguardStateController; + private final KeyguardSecurityModel mKeyguardSecurityModel; + private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { @Override @@ -85,32 +80,33 @@ public class KeyguardBouncer { }; private final Runnable mRemoveViewRunnable = this::removeView; private final KeyguardBypassController mKeyguardBypassController; - protected KeyguardHostView mKeyguardView; + private KeyguardHostViewController mKeyguardViewController; private final Runnable mResetRunnable = ()-> { - if (mKeyguardView != null) { - mKeyguardView.resetSecurityContainer(); + if (mKeyguardViewController != null) { + mKeyguardViewController.resetSecurityContainer(); } }; private int mStatusBarHeight; private float mExpansion = EXPANSION_HIDDEN; protected ViewGroup mRoot; + private KeyguardRootViewController mRootViewController; private boolean mShowingSoon; private int mBouncerPromptReason; private boolean mIsAnimatingAway; private boolean mIsScrimmed; - @Inject - public KeyguardBouncer(Context context, ViewMediatorCallback callback, - LockPatternUtils lockPatternUtils, @ContainerView ViewGroup container, + private KeyguardBouncer(Context context, ViewMediatorCallback callback, + ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager, BouncerExpansionCallback expansionCallback, KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, - KeyguardBypassController keyguardBypassController, Handler handler) { + KeyguardBypassController keyguardBypassController, Handler handler, + KeyguardSecurityModel keyguardSecurityModel, + KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { mContext = context; mCallback = callback; - mLockPatternUtils = lockPatternUtils; mContainer = container; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mFalsingManager = falsingManager; @@ -118,6 +114,8 @@ public class KeyguardBouncer { mExpansionCallback = expansionCallback; mHandler = handler; mKeyguardStateController = keyguardStateController; + mKeyguardSecurityModel = keyguardSecurityModel; + mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); mKeyguardBypassController = keyguardBypassController; } @@ -168,7 +166,7 @@ public class KeyguardBouncer { // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer. - if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) { + if (allowDismissKeyguard && mKeyguardViewController.dismiss(activeUserId)) { return; } @@ -204,12 +202,13 @@ public class KeyguardBouncer { */ private void onFullyShown() { mFalsingManager.onBouncerShown(); - if (mKeyguardView == null) { + if (mKeyguardViewController == null) { Log.wtf(TAG, "onFullyShown when view was null"); } else { - mKeyguardView.onResume(); + mKeyguardViewController.onResume(); if (mRoot != null) { - mRoot.announceForAccessibility(mKeyguardView.getAccessibilityTitleForCurrentMode()); + mRoot.announceForAccessibility( + mKeyguardViewController.getAccessibilityTitleForCurrentMode()); } } } @@ -233,28 +232,13 @@ public class KeyguardBouncer { showPromptReason(mBouncerPromptReason); final CharSequence customMessage = mCallback.consumeCustomMessage(); if (customMessage != null) { - mKeyguardView.showErrorMessage(customMessage); - } - // We might still be collapsed and the view didn't have time to layout yet or still - // be small, let's wait on the predraw to do the animation in that case. - if (mKeyguardView.getHeight() != 0 && mKeyguardView.getHeight() != mStatusBarHeight) { - mKeyguardView.startAppearAnimation(); - } else { - mKeyguardView.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - mKeyguardView.getViewTreeObserver().removeOnPreDrawListener(this); - mKeyguardView.startAppearAnimation(); - return true; - } - }); - mKeyguardView.requestLayout(); + mKeyguardViewController.showErrorMessage(customMessage); } + mKeyguardViewController.appear(mStatusBarHeight); mShowingSoon = false; if (mExpansion == EXPANSION_VISIBLE) { - mKeyguardView.onResume(); - mKeyguardView.resetSecurityContainer(); + mKeyguardViewController.onResume(); + mKeyguardViewController.resetSecurityContainer(); showPromptReason(mBouncerPromptReason); } SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, @@ -270,16 +254,16 @@ public class KeyguardBouncer { * and {@link KeyguardSecurityView#PROMPT_REASON_RESTART} */ public void showPromptReason(int reason) { - if (mKeyguardView != null) { - mKeyguardView.showPromptReason(reason); + if (mKeyguardViewController != null) { + mKeyguardViewController.showPromptReason(reason); } else { Log.w(TAG, "Trying to show prompt reason on empty bouncer"); } } public void showMessage(String message, ColorStateList colorState) { - if (mKeyguardView != null) { - mKeyguardView.showMessage(message, colorState); + if (mKeyguardViewController != null) { + mKeyguardViewController.showMessage(message, colorState); } else { Log.w(TAG, "Trying to show message on empty bouncer"); } @@ -293,7 +277,7 @@ public class KeyguardBouncer { public void showWithDismissAction(OnDismissAction r, Runnable cancelAction) { ensureView(); - mKeyguardView.setOnDismissAction(r, cancelAction); + mKeyguardViewController.setOnDismissAction(r, cancelAction); show(false /* resetSecuritySelection */); } @@ -307,9 +291,9 @@ public class KeyguardBouncer { mFalsingManager.onBouncerHidden(); mCallback.onBouncerVisiblityChanged(false /* shown */); cancelShowRunnable(); - if (mKeyguardView != null) { - mKeyguardView.cancelDismissAction(); - mKeyguardView.cleanUp(); + if (mKeyguardViewController != null) { + mKeyguardViewController.cancelDismissAction(); + mKeyguardViewController.cleanUp(); } mIsAnimatingAway = false; if (mRoot != null) { @@ -328,8 +312,8 @@ public class KeyguardBouncer { */ public void startPreHideAnimation(Runnable runnable) { mIsAnimatingAway = true; - if (mKeyguardView != null) { - mKeyguardView.startDisappearAnimation(runnable); + if (mKeyguardViewController != null) { + mKeyguardViewController.startDisappearAnimation(runnable); } else if (runnable != null) { runnable.run(); } @@ -345,8 +329,9 @@ public class KeyguardBouncer { } public void onScreenTurnedOff() { - if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) { - mKeyguardView.onPause(); + if (mKeyguardViewController != null + && mRoot != null && mRoot.getVisibility() == View.VISIBLE) { + mKeyguardViewController.onPause(); } } @@ -380,7 +365,7 @@ public class KeyguardBouncer { } private void showPrimarySecurityScreen() { - mKeyguardView.showPrimarySecurityScreen(); + mKeyguardViewController.showPrimarySecurityScreen(); } /** @@ -391,10 +376,8 @@ public class KeyguardBouncer { public void setExpansion(float fraction) { float oldExpansion = mExpansion; mExpansion = fraction; - if (mKeyguardView != null && !mIsAnimatingAway) { - float alpha = MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction); - mKeyguardView.setAlpha(MathUtils.constrain(alpha, 0f, 1f)); - mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight()); + if (mKeyguardViewController != null && !mIsAnimatingAway) { + mKeyguardViewController.setExpansion(fraction); } if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) { @@ -405,28 +388,22 @@ public class KeyguardBouncer { mExpansionCallback.onFullyHidden(); } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) { mExpansionCallback.onStartingToHide(); - if (mKeyguardView != null) { - mKeyguardView.onStartingToHide(); + if (mKeyguardViewController != null) { + mKeyguardViewController.onStartingToHide(); } } } public boolean willDismissWithAction() { - return mKeyguardView != null && mKeyguardView.hasDismissActions(); + return mKeyguardViewController != null && mKeyguardViewController.hasDismissActions(); } public int getTop() { - if (mKeyguardView == null) { + if (mKeyguardViewController == null) { return 0; } - int top = mKeyguardView.getTop(); - // The password view has an extra top padding that should be ignored. - if (mKeyguardView.getCurrentSecurityMode() == SecurityMode.Password) { - View messageArea = mKeyguardView.findViewById(R.id.keyguard_message_area); - top += messageArea.getTop(); - } - return top; + return mKeyguardViewController.getTop(); } protected void ensureView() { @@ -442,10 +419,13 @@ public class KeyguardBouncer { protected void inflateView() { removeView(); mHandler.removeCallbacks(mRemoveViewRunnable); - mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null); - mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view); - mKeyguardView.setLockPatternUtils(mLockPatternUtils); - mKeyguardView.setViewMediatorCallback(mCallback); + KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create(); + mRootViewController = component.getKeyguardRootViewController(); + mRootViewController.init(); + mRoot = mRootViewController.getView(); // TODO(b/166448040): Don't access root view here. + mKeyguardViewController = component.getKeyguardHostViewController(); + mKeyguardViewController.init(); + mContainer.addView(mRoot, mContainer.getChildCount()); mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset( com.android.systemui.R.dimen.status_bar_height); @@ -465,7 +445,7 @@ public class KeyguardBouncer { } public boolean onBackPressed() { - return mKeyguardView != null && mKeyguardView.handleBackKey(); + return mKeyguardViewController != null && mKeyguardViewController.handleBackKey(); } /** @@ -473,7 +453,7 @@ public class KeyguardBouncer { * notifications on Keyguard, like SIM PIN/PUK. */ public boolean needsFullscreenBouncer() { - SecurityMode mode = Dependency.get(KeyguardSecurityModel.class).getSecurityMode( + SecurityMode mode = mKeyguardSecurityModel.getSecurityMode( KeyguardUpdateMonitor.getCurrentUser()); return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk; } @@ -483,8 +463,8 @@ public class KeyguardBouncer { * makes this method much faster. */ public boolean isFullscreenBouncer() { - if (mKeyguardView != null) { - SecurityMode mode = mKeyguardView.getCurrentSecurityMode(); + if (mKeyguardViewController != null) { + SecurityMode mode = mKeyguardViewController.getCurrentSecurityMode(); return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk; } return false; @@ -494,21 +474,22 @@ public class KeyguardBouncer { * WARNING: This method might cause Binder calls. */ public boolean isSecure() { - return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None; + return mKeyguardSecurityModel.getSecurityMode( + KeyguardUpdateMonitor.getCurrentUser()) != SecurityMode.None; } public boolean shouldDismissOnMenuPressed() { - return mKeyguardView.shouldEnableMenuKey(); + return mKeyguardViewController.shouldEnableMenuKey(); } public boolean interceptMediaKey(KeyEvent event) { ensureView(); - return mKeyguardView.interceptMediaKey(event); + return mKeyguardViewController.interceptMediaKey(event); } public void notifyKeyguardAuthenticated(boolean strongAuth) { ensureView(); - mKeyguardView.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser()); + mKeyguardViewController.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser()); } public void dump(PrintWriter pw) { @@ -516,8 +497,8 @@ public class KeyguardBouncer { pw.println(" isShowing(): " + isShowing()); pw.println(" mStatusBarHeight: " + mStatusBarHeight); pw.println(" mExpansion: " + mExpansion); - pw.println(" mKeyguardView; " + mKeyguardView); - pw.println(" mShowingSoon: " + mKeyguardView); + pw.println(" mKeyguardViewController; " + mKeyguardViewController); + pw.println(" mShowingSoon: " + mShowingSoon); pw.println(" mBouncerPromptReason: " + mBouncerPromptReason); pw.println(" mIsAnimatingAway: " + mIsAnimatingAway); } @@ -528,4 +509,46 @@ public class KeyguardBouncer { void onStartingToShow(); void onFullyHidden(); } + + /** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */ + public static class Factory { + private final Context mContext; + private final ViewMediatorCallback mCallback; + private final DismissCallbackRegistry mDismissCallbackRegistry; + private final FalsingManager mFalsingManager; + private final KeyguardStateController mKeyguardStateController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final KeyguardBypassController mKeyguardBypassController; + private final Handler mHandler; + private final KeyguardSecurityModel mKeyguardSecurityModel; + private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; + + @Inject + public Factory(Context context, ViewMediatorCallback callback, + DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager, + KeyguardStateController keyguardStateController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + KeyguardBypassController keyguardBypassController, Handler handler, + KeyguardSecurityModel keyguardSecurityModel, + KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { + mContext = context; + mCallback = callback; + mDismissCallbackRegistry = dismissCallbackRegistry; + mFalsingManager = falsingManager; + mKeyguardStateController = keyguardStateController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mKeyguardBypassController = keyguardBypassController; + mHandler = handler; + mKeyguardSecurityModel = keyguardSecurityModel; + mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; + } + + public KeyguardBouncer create(@RootView ViewGroup container, + BouncerExpansionCallback expansionCallback) { + return new KeyguardBouncer(mContext, mCallback, container, + mDismissCallbackRegistry, mFalsingManager, expansionCallback, + mKeyguardStateController, mKeyguardUpdateMonitor, mKeyguardBypassController, + mHandler, mKeyguardSecurityModel, mKeyguardBouncerComponentFactory); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index b56993b5f439..51209d166eee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -44,7 +44,6 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.ViewMediatorCallback; -import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.settingslib.animation.AppearAnimationUtils; import com.android.systemui.DejankUtils; import com.android.systemui.dagger.SysUISingleton; @@ -104,7 +103,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private final NavigationModeController mNavigationModeController; private final NotificationShadeWindowController mNotificationShadeWindowController; private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController; - private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; + private final KeyguardBouncer.Factory mKeyguardBouncerFactory; private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() { @Override public void onFullyShown() { @@ -216,7 +215,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb KeyguardStateController keyguardStateController, Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController, NotificationMediaManager notificationMediaManager, - KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { + KeyguardBouncer.Factory keyguardBouncerFactory) { mContext = context; mViewMediatorCallback = callback; mLockPatternUtils = lockPatternUtils; @@ -229,7 +228,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mStatusBarStateController = sysuiStatusBarStateController; mDockManager = dockManager; mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController; - mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; + mKeyguardBouncerFactory = keyguardBouncerFactory; } @Override @@ -246,9 +245,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLastLockVisible = mLockIconContainer.getVisibility() == View.VISIBLE; } mBiometricUnlockController = biometricUnlockController; - mBouncer = mKeyguardBouncerComponentFactory - .build(container, mExpansionCallback) - .createKeyguardBouncer(); + mBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback); mNotificationPanelViewController = notificationPanelViewController; notificationPanelViewController.addExpansionListener(this); mBypassController = bypassController; diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java new file mode 100644 index 000000000000..64f8dbbb9e34 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java @@ -0,0 +1,72 @@ +/* + * 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.systemui.util; + +import android.view.View; +import android.view.View.OnAttachStateChangeListener; + +/** + * Utility class that handles view lifecycle events for View Controllers. + * + * Implementations should handle setup and teardown related activities inside of + * {@link #onViewAttached()} and {@link #onViewDetached()}. + * + * @param <T> View class that this ViewController is for. + */ +public abstract class ViewController<T extends View> { + protected final T mView; + private boolean mInited; + + private OnAttachStateChangeListener mOnAttachStateListener = new OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + ViewController.this.onViewAttached(); + } + + @Override + public void onViewDetachedFromWindow(View v) { + ViewController.this.onViewDetached(); + } + }; + + protected ViewController(T view) { + mView = view; + } + + /** Call immediately after constructing Controller in order to handle view lifecycle events. */ + public void init() { + if (mInited) { + return; + } + mInited = true; + + if (mView.isAttachedToWindow()) { + mOnAttachStateListener.onViewAttachedToWindow(mView); + } + mView.addOnAttachStateChangeListener(mOnAttachStateListener); + } + + /** + * Called when the view is attached and a call to {@link #init()} has been made in either order. + */ + protected abstract void onViewAttached(); + + /** + * Called when the view is detached. + */ + protected abstract void onViewDetached(); +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java index dd5c8335eefa..54e879e2ff38 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.keyguard; @@ -19,11 +19,12 @@ package com.android.keyguard; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import android.media.AudioManager; +import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import com.android.internal.widget.LockPatternUtils; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; @@ -39,41 +40,44 @@ import org.mockito.junit.MockitoRule; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper -public class KeyguardHostViewTest extends SysuiTestCase { +public class KeyguardHostViewControllerTest extends SysuiTestCase { @Mock - private KeyguardSecurityContainer mSecurityContainer; + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock - private LockPatternUtils mLockPatternUtils; + private KeyguardHostView mKeyguardHostView; + @Mock + private KeyguardSecurityContainerController mKeyguardSecurityContainerController; + @Mock + private AudioManager mAudioManager; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private ViewMediatorCallback mViewMediatorCallback; + @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); - private KeyguardHostView mKeyguardHostView; + private KeyguardHostViewController mKeyguardHostViewController; @Before public void setup() { - mDependency.injectMockDependency(KeyguardUpdateMonitor.class); - mKeyguardHostView = new KeyguardHostView(getContext()) { - @Override - protected void onFinishInflate() { - mSecurityContainer = KeyguardHostViewTest.this.mSecurityContainer; - mLockPatternUtils = KeyguardHostViewTest.this.mLockPatternUtils; - } - }; - mKeyguardHostView.onFinishInflate(); + mKeyguardHostViewController = new KeyguardHostViewController( + mKeyguardHostView, mKeyguardUpdateMonitor, mKeyguardSecurityContainerController, + mAudioManager, mTelephonyManager, mViewMediatorCallback); } @Test public void testHasDismissActions() { - Assert.assertFalse("Action not set yet", mKeyguardHostView.hasDismissActions()); - mKeyguardHostView.setOnDismissAction(mock(OnDismissAction.class), + Assert.assertFalse("Action not set yet", mKeyguardHostViewController.hasDismissActions()); + mKeyguardHostViewController.setOnDismissAction(mock(OnDismissAction.class), null /* cancelAction */); - Assert.assertTrue("Action should exist", mKeyguardHostView.hasDismissActions()); + Assert.assertTrue("Action should exist", mKeyguardHostViewController.hasDismissActions()); } @Test public void testOnStartingToHide() { - mKeyguardHostView.onStartingToHide(); - verify(mSecurityContainer).onStartingToHide(); + mKeyguardHostViewController.onStartingToHide(); + verify(mKeyguardSecurityContainerController).onStartingToHide(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java index 0a041e4a4dc5..1b05ad7f8b5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java @@ -38,16 +38,16 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.widget.FrameLayout; import androidx.test.filters.SmallTest; -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardHostView; +import com.android.keyguard.KeyguardHostViewController; +import com.android.keyguard.KeyguardRootViewController; import com.android.keyguard.KeyguardSecurityModel; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; +import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.DejankUtils; import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.DismissCallbackRegistry; @@ -76,13 +76,9 @@ public class KeyguardBouncerTest extends SysuiTestCase { @Mock private ViewMediatorCallback mViewMediatorCallback; @Mock - private LockPatternUtils mLockPatternUtils; - @Mock private DismissCallbackRegistry mDismissCallbackRegistry; @Mock - private KeyguardHostView mKeyguardHostView; - @Mock - private ViewTreeObserver mViewTreeObserver; + private KeyguardHostViewController mKeyguardHostViewController; @Mock private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback; @Mock @@ -96,7 +92,13 @@ public class KeyguardBouncerTest extends SysuiTestCase { @Mock private KeyguardSecurityModel mKeyguardSecurityModel; @Mock + private KeyguardRootViewController mRootViewController; + @Mock private ViewGroup mRootView; + @Mock + private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; + @Mock + private KeyguardBouncerComponent mKeyguardBouncerComponent; @Rule public MockitoRule mRule = MockitoJUnit.rule(); private Integer mRootVisibility = View.INVISIBLE; @@ -106,7 +108,6 @@ public class KeyguardBouncerTest extends SysuiTestCase { public void setup() { allowTestableLooperAsMainThread(); mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor); - mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel); mDependency.injectMockDependency(KeyguardStateController.class); when(mRootView.getVisibility()).thenAnswer((Answer<Integer>) invocation -> mRootVisibility); doAnswer(invocation -> { @@ -116,19 +117,22 @@ public class KeyguardBouncerTest extends SysuiTestCase { when(mKeyguardSecurityModel.getSecurityMode(anyInt())) .thenReturn(KeyguardSecurityModel.SecurityMode.None); DejankUtils.setImmediate(true); + when(mKeyguardBouncerComponentFactory.create()).thenReturn(mKeyguardBouncerComponent); + when(mKeyguardBouncerComponent.getKeyguardHostViewController()) + .thenReturn(mKeyguardHostViewController); + when(mKeyguardBouncerComponent.getKeyguardRootViewController()) + .thenReturn(mRootViewController); + + when(mRootViewController.getView()).thenReturn(mRootView); + when(mRootView.getResources()).thenReturn(mContext.getResources()); + final ViewGroup container = new FrameLayout(getContext()); - when(mKeyguardHostView.getViewTreeObserver()).thenReturn(mViewTreeObserver); - when(mKeyguardHostView.getHeight()).thenReturn(500); - mBouncer = new KeyguardBouncer(getContext(), mViewMediatorCallback, - mLockPatternUtils, container, mDismissCallbackRegistry, mFalsingManager, - mExpansionCallback, mKeyguardStateController, mKeyguardUpdateMonitor, - mKeyguardBypassController, mHandler) { - @Override - protected void inflateView() { - mKeyguardView = mKeyguardHostView; - mRoot = mRootView; - } - }; + mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback, + mDismissCallbackRegistry, mFalsingManager, + mKeyguardStateController, mKeyguardUpdateMonitor, + mKeyguardBypassController, mHandler, mKeyguardSecurityModel, + mKeyguardBouncerComponentFactory) + .create(container, mExpansionCallback); } @Test @@ -154,12 +158,10 @@ public class KeyguardBouncerTest extends SysuiTestCase { mBouncer.ensureView(); mBouncer.setExpansion(1); - reset(mKeyguardHostView); - when(mKeyguardHostView.getHeight()).thenReturn(500); + reset(mKeyguardHostViewController); mBouncer.show(true); - verify(mKeyguardHostView).setAlpha(eq(1f)); - verify(mKeyguardHostView).setTranslationY(eq(0f)); + verify(mKeyguardHostViewController).setExpansion(0); } @Test @@ -177,23 +179,23 @@ public class KeyguardBouncerTest extends SysuiTestCase { @Test public void testShow_triesToDismissKeyguard() { mBouncer.show(true); - verify(mKeyguardHostView).dismiss(anyInt()); + verify(mKeyguardHostViewController).dismiss(anyInt()); } @Test public void testShow_resetsSecuritySelection() { mBouncer.show(false); - verify(mKeyguardHostView, never()).showPrimarySecurityScreen(); + verify(mKeyguardHostViewController, never()).showPrimarySecurityScreen(); mBouncer.hide(false); mBouncer.show(true); - verify(mKeyguardHostView).showPrimarySecurityScreen(); + verify(mKeyguardHostViewController).showPrimarySecurityScreen(); } @Test public void testShow_animatesKeyguardView() { mBouncer.show(true); - verify(mKeyguardHostView).startAppearAnimation(); + verify(mKeyguardHostViewController).appear(anyInt()); } @Test @@ -201,7 +203,7 @@ public class KeyguardBouncerTest extends SysuiTestCase { final String errorMessage = "an error message"; when(mViewMediatorCallback.consumeCustomMessage()).thenReturn(errorMessage); mBouncer.show(true); - verify(mKeyguardHostView).showErrorMessage(eq(errorMessage)); + verify(mKeyguardHostViewController).showErrorMessage(eq(errorMessage)); } @Test @@ -218,10 +220,10 @@ public class KeyguardBouncerTest extends SysuiTestCase { verify(mExpansionCallback).onFullyShown(); verify(mExpansionCallback, never()).onStartingToHide(); - verify(mKeyguardHostView, never()).onStartingToHide(); + verify(mKeyguardHostViewController, never()).onStartingToHide(); mBouncer.setExpansion(0.9f); verify(mExpansionCallback).onStartingToHide(); - verify(mKeyguardHostView).onStartingToHide(); + verify(mKeyguardHostViewController).onStartingToHide(); } @Test @@ -230,7 +232,7 @@ public class KeyguardBouncerTest extends SysuiTestCase { mBouncer.setExpansion(0.1f); mBouncer.setExpansion(0); - verify(mKeyguardHostView).onResume(); + verify(mKeyguardHostViewController).onResume(); verify(mRootView).announceForAccessibility(any()); } @@ -267,7 +269,7 @@ public class KeyguardBouncerTest extends SysuiTestCase { public void testShowPromptReason_propagates() { mBouncer.ensureView(); mBouncer.showPromptReason(1); - verify(mKeyguardHostView).showPromptReason(eq(1)); + verify(mKeyguardHostViewController).showPromptReason(eq(1)); } @Test @@ -275,7 +277,8 @@ public class KeyguardBouncerTest extends SysuiTestCase { final String message = "a message"; mBouncer.ensureView(); mBouncer.showMessage(message, ColorStateList.valueOf(Color.GREEN)); - verify(mKeyguardHostView).showMessage(eq(message), eq(ColorStateList.valueOf(Color.GREEN))); + verify(mKeyguardHostViewController).showMessage( + eq(message), eq(ColorStateList.valueOf(Color.GREEN))); } @Test @@ -283,7 +286,7 @@ public class KeyguardBouncerTest extends SysuiTestCase { final OnDismissAction dismissAction = () -> false; final Runnable cancelAction = () -> {}; mBouncer.showWithDismissAction(dismissAction, cancelAction); - verify(mKeyguardHostView).setOnDismissAction(dismissAction, cancelAction); + verify(mKeyguardHostViewController).setOnDismissAction(dismissAction, cancelAction); Assert.assertTrue("Should be showing", mBouncer.isShowing()); } @@ -297,7 +300,7 @@ public class KeyguardBouncerTest extends SysuiTestCase { ran[0] = false; mBouncer.ensureView(); mBouncer.startPreHideAnimation(r); - verify(mKeyguardHostView).startDisappearAnimation(r); + verify(mKeyguardHostViewController).startDisappearAnimation(r); Assert.assertFalse("Callback should have been deferred", ran[0]); } @@ -322,16 +325,14 @@ public class KeyguardBouncerTest extends SysuiTestCase { public void testSetExpansion() { mBouncer.ensureView(); mBouncer.setExpansion(0.5f); - verify(mKeyguardHostView).setAlpha(anyFloat()); - verify(mKeyguardHostView).setTranslationY(anyFloat()); + verify(mKeyguardHostViewController).setExpansion(0.5f); } @Test public void testIsFullscreenBouncer_asksKeyguardView() { mBouncer.ensureView(); mBouncer.isFullscreenBouncer(); - verify(mKeyguardHostView).getCurrentSecurityMode(); - verify(mKeyguardHostView, never()).getSecurityMode(); + verify(mKeyguardHostViewController).getCurrentSecurityMode(); } @Test @@ -346,21 +347,18 @@ public class KeyguardBouncerTest extends SysuiTestCase { @Test public void testIsHiding_skipsTranslation() { mBouncer.show(false /* reset */); - reset(mKeyguardHostView); + reset(mKeyguardHostViewController); mBouncer.startPreHideAnimation(null /* runnable */); mBouncer.setExpansion(0.5f); - verify(mKeyguardHostView, never()).setTranslationY(anyFloat()); - verify(mKeyguardHostView, never()).setAlpha(anyFloat()); + verify(mKeyguardHostViewController, never()).setExpansion(anyFloat()); } @Test public void testIsSecure() { - Assert.assertTrue("Bouncer is secure before inflating views", mBouncer.isSecure()); - mBouncer.ensureView(); for (KeyguardSecurityModel.SecurityMode mode : KeyguardSecurityModel.SecurityMode.values()){ - reset(mKeyguardHostView); - when(mKeyguardHostView.getSecurityMode()).thenReturn(mode); + reset(mKeyguardSecurityModel); + when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(mode); Assert.assertEquals("Security doesn't match for mode: " + mode, mBouncer.isSecure(), mode != KeyguardSecurityModel.SecurityMode.None); } @@ -392,7 +390,7 @@ public class KeyguardBouncerTest extends SysuiTestCase { public void testWillDismissWithAction() { mBouncer.ensureView(); Assert.assertFalse("Action not set yet", mBouncer.willDismissWithAction()); - when(mKeyguardHostView.hasDismissActions()).thenReturn(true); + when(mKeyguardHostViewController.hasDismissActions()).thenReturn(true); Assert.assertTrue("Action should exist", mBouncer.willDismissWithAction()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 108327341f94..9832d31f7b05 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -39,7 +39,6 @@ import androidx.test.filters.SmallTest; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; -import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.DismissCallbackRegistry; @@ -92,9 +91,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private FaceAuthScreenBrightnessController mFaceAuthScreenBrightnessController; @Mock - private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; - @Mock - private KeyguardBouncerComponent mKeyguardBouncerComponent; + private KeyguardBouncer.Factory mKeyguardBouncerFactory; @Mock private KeyguardBouncer mBouncer; @@ -107,11 +104,10 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { when(mLockIconContainer.animate()).thenReturn(mock(ViewPropertyAnimator.class, RETURNS_DEEP_STUBS)); - when(mKeyguardBouncerComponentFactory.build( + when(mKeyguardBouncerFactory.create( any(ViewGroup.class), any(KeyguardBouncer.BouncerExpansionCallback.class))) - .thenReturn(mKeyguardBouncerComponent); - when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer); + .thenReturn(mBouncer); mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager( getContext(), @@ -126,7 +122,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mKeyguardStateController, Optional.of(mFaceAuthScreenBrightnessController), mock(NotificationMediaManager.class), - mKeyguardBouncerComponentFactory); + mKeyguardBouncerFactory); mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer, mNotificationPanelView, mBiometrucUnlockController, mLockIconContainer, mNotificationContainer, mBypassController); diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 92fce8a22937..c7de8d3d585f 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -107,17 +107,23 @@ public class PlatformCompat extends IPlatformCompat.Stub { } /** - * Internal version of the above method. Does not perform costly permission check. + * Internal version of the above method, without logging. Does not perform costly permission + * check. + * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property. + */ + public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) { + return mCompatConfig.isChangeEnabled(changeId, appInfo); + } + + /** + * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}. Does not perform costly + * permission check. */ public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) { - if (mCompatConfig.isChangeEnabled(changeId, appInfo)) { - reportChange(changeId, appInfo.uid, - ChangeReporter.STATE_ENABLED); - return true; - } + boolean value = isChangeEnabledInternalNoLogging(changeId, appInfo); reportChange(changeId, appInfo.uid, - ChangeReporter.STATE_DISABLED); - return false; + value ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED); + return value; } @Override diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 52e90218fd24..7401403de127 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1958,6 +1958,13 @@ public class NotificationManagerService extends SystemService { } @Override + void onConsolidatedPolicyChanged() { + Binder.withCleanCallingIdentity(() -> { + mRankingHandler.requestSort(); + }); + } + + @Override void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) { Binder.withCleanCallingIdentity(() -> { Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED); diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index f168ac70dda8..6d24a3bc0cd4 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -303,7 +303,8 @@ public class AppsFilter { private void updateEnabledState(@NonNull AndroidPackage pkg) { // TODO(b/135203078): Do not use toAppInfo - final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternal( + // TODO(b/167551701): Make changeId non-logging + final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternalNoLogging( PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState()); if (enabled) { mDisabledPackages.remove(pkg.getPackageName()); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index b6f0f9ffe001..33b12138db79 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2159,6 +2159,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return getDeviceOwnerOfCallerLocked(caller); } + @NonNull ActiveAdmin getParentOfAdminIfRequired(ActiveAdmin admin, boolean parent) { + Objects.requireNonNull(admin); + return parent ? admin.getParentActiveAdmin() : admin; + } + /** * Finds an active admin for the caller then checks {@code permission} if admin check failed. * @@ -4527,6 +4532,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } Objects.requireNonNull(who, "ComponentName is null"); Preconditions.checkArgument(timeoutMs >= 0, "Timeout must not be a negative number."); + final CallerIdentity caller = getCallerIdentity(who); + Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)); // timeoutMs with value 0 means that the admin doesn't participate // timeoutMs is clamped to the interval in case the internal constants change in the future final long minimumStrongAuthTimeout = getMinimumStrongAuthTimeoutMs(); @@ -4537,11 +4544,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { timeoutMs = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS; } - final int userHandle = mInjector.userHandleGetCallingUserId(); + final int userHandle = caller.getUserId(); boolean changed = false; synchronized (getLockObject()) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent); + ActiveAdmin ap = getParentOfAdminIfRequired(getProfileOwnerOrDeviceOwnerLocked(caller), + parent); if (ap.strongAuthUnlockTimeout != timeoutMs) { ap.strongAuthUnlockTimeout = timeoutMs; saveSettingsLocked(userHandle); @@ -5646,8 +5653,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { List<String> lockdownWhitelist) throws SecurityException { enforceProfileOrDeviceOwner(who); + final CallerIdentity caller = getCallerIdentity(who); - final int userId = mInjector.userHandleGetCallingUserId(); + final int userId = caller.getUserId(); mInjector.binderWithCleanCallingIdentity(() -> { if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) { Slog.w(LOG_TAG, "Non-existent VPN package specified: " + vpnPackage); @@ -5678,8 +5686,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .write(); }); synchronized (getLockObject()) { - ActiveAdmin admin = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller); if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage) || lockdown != admin.mAlwaysOnVpnLockdown) { admin.mAlwaysOnVpnPackage = vpnPackage; @@ -9675,10 +9682,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return null; } Objects.requireNonNull(who, "ComponentName is null"); + final CallerIdentity caller = getCallerIdentity(who); synchronized (getLockObject()) { - final ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent); + final ActiveAdmin activeAdmin = getParentOfAdminIfRequired( + getProfileOwnerOrDeviceOwnerLocked(caller), parent); if (parent) { enforceProfileOwnerOfOrganizationOwnedDevice(activeAdmin); } @@ -9929,6 +9937,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return; } Objects.requireNonNull(who, "ComponentName is null"); + final CallerIdentity caller = getCallerIdentity(who); synchronized (getLockObject()) { /* * When called on the parent DPM instance (parent == true), affects active admin @@ -9936,9 +9945,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * * The ActiveAdmin must be of an org-owned profile owner. * * The parent ActiveAdmin instance should be used for managing the restriction. */ - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - parent ? DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER - : DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent); + final ActiveAdmin ap; + if (parent) { + ap = getParentOfAdminIfRequired(getOrganizationOwnedProfileOwnerLocked(caller), + parent); + } else { + ap = getParentOfAdminIfRequired(getProfileOwnerOrDeviceOwnerLocked(caller), parent); + } + if (disabled) { ap.accountTypesWithManagementDisabled.add(accountType); } else { diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp index 943d78398879..a53ea16ba7c4 100644 --- a/tests/FlickerTests/Android.bp +++ b/tests/FlickerTests/Android.bp @@ -28,7 +28,6 @@ android_test { "flickertestapplib", "flickerlib", "truth-prebuilt", - "app-helpers-core", "launcher-helper-lib", "launcher-aosp-tapl" ], diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt deleted file mode 100644 index 71475774343a..000000000000 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.server.wm.flicker.helpers - -import android.app.Instrumentation -import android.support.test.launcherhelper.ILauncherStrategy -import com.android.server.wm.flicker.StandardAppHelper - -abstract class FlickerAppHelper( - instr: Instrumentation, - launcherName: String, - launcherStrategy: ILauncherStrategy -) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) { - companion object { - var sFlickerPackage = "com.android.server.wm.flicker.testapp" - } -} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt index c1b765790ce5..f4de36e99952 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt @@ -30,7 +30,7 @@ open class ImeAppHelper( launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) .launcherStrategy -) : FlickerAppHelper(instr, launcherName, launcherStrategy) { +) : StandardAppHelper(instr, launcherName, launcherStrategy) { open fun openIME(device: UiDevice) { val editText = device.wait( Until.findObject(By.res(getPackage(), "plain_text_input")), diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt index d10bb1ef3ee7..0572a7813819 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt @@ -28,7 +28,7 @@ class PipAppHelper( launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) .launcherStrategy -) : FlickerAppHelper(instr, "PipApp", launcherStrategy) { +) : StandardAppHelper(instr, "PipApp", launcherStrategy) { fun clickEnterPipButton(device: UiDevice) { val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip")) Assert.assertNotNull("Pip button not found, this usually happens when the device " + diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt index 7d70812a22f2..98e05d526bed 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.launch import com.android.server.wm.flicker.NonRotationTestBase -import com.android.server.wm.flicker.StandardAppHelper +import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.dsl.LayersAssertion import com.android.server.wm.flicker.dsl.WmAssertion diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt index afadb58eeed5..acd141a8d74f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.launch import android.view.Surface import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.StandardAppHelper +import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.dsl.flicker import com.android.server.wm.flicker.focusChanges import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt index 0ca150892f36..99218c2c586d 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt @@ -20,7 +20,7 @@ import androidx.test.filters.RequiresDevice import android.view.Surface import com.android.server.wm.flicker.NonRotationTestBase.Companion.SCREENSHOT_LAYER import com.android.server.wm.flicker.RotationTestBase -import com.android.server.wm.flicker.StandardAppHelper +import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.dsl.flicker import com.android.server.wm.flicker.focusDoesNotChange import com.android.server.wm.flicker.helpers.WindowUtils diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt index c5e48d966155..3b5e6694ef0f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker.splitscreen import android.view.Surface import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.NonRotationTestBase -import com.android.server.wm.flicker.StandardAppHelper +import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.dsl.flicker import com.android.server.wm.flicker.focusChanges import com.android.server.wm.flicker.helpers.exitSplitScreen diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt index 91211cabf45c..abf41a1fd408 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt @@ -24,7 +24,7 @@ import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.uiautomator.By import com.android.server.wm.flicker.FlickerTestBase -import com.android.server.wm.flicker.StandardAppHelper +import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.dsl.flicker import com.android.server.wm.flicker.focusDoesNotChange import com.android.server.wm.flicker.helpers.ImeAppHelper diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt index 5c7dcd901a41..87c863338edb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker.splitscreen import android.view.Surface import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.NonRotationTestBase -import com.android.server.wm.flicker.StandardAppHelper +import com.android.server.wm.flicker.helpers.StandardAppHelper import com.android.server.wm.flicker.dsl.flicker import com.android.server.wm.flicker.focusDoesNotChange import com.android.server.wm.flicker.helpers.exitSplitScreen |