From 617777eb55c1d83d81b2ad05cd61082c404b30ff Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Fri, 28 Aug 2020 17:55:27 -0400 Subject: [PATCH 1/3] 1/N Add Controllers for most KeyguardBouncer related views. This adds Controllers to most of the KeyguardBouncer related views, though it does not move much (or any) functionality into them. This is the first step of a few to get View Injection out of the KeyguardMessageArea. The CL was growing large, and I wanted to find a good check-in point before continuing. I also added a "ViewController" utility class in this CL that simplifies some of the repetetive work I've been finding myself writing when implementing other Controllers. It is intentionally left simple, existing only to hook into view lifecycle events. More work to follow. Bug: 166448040 Test: manual && atest SystemUITests Change-Id: Ie59f62e97d979fb753e4a103d37ceca02e327238 --- .../keyguard/CarKeyguardViewController.java | 13 ++-- .../CarKeyguardViewControllerTest.java | 12 +-- .../android/keyguard/KeyguardHostView.java | 7 -- .../keyguard/KeyguardHostViewController.java | 69 +++++++++++++++++ .../KeyguardMessageAreaController.java | 70 +++++++++++++++++ .../keyguard/KeyguardRootViewController.java | 51 +++++++++++++ .../KeyguardSecurityContainerController.java | 51 +++++++++++++ .../KeyguardSecurityViewController.java | 57 ++++++++++++++ .../dagger/KeyguardBouncerComponent.java | 18 ++--- .../dagger/KeyguardBouncerModule.java | 64 ++++++++++++++++ .../{ContainerView.java => RootView.java} | 2 +- .../statusbar/phone/KeyguardBouncer.java | 76 +++++++++++++++---- .../phone/StatusBarKeyguardViewManager.java | 11 +-- .../android/systemui/util/ViewController.java | 70 +++++++++++++++++ .../statusbar/phone/KeyguardBouncerTest.java | 38 ++++++---- .../StatusBarKeyguardViewManagerTest.java | 12 +-- 16 files changed, 545 insertions(+), 76 deletions(-) create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java rename packages/SystemUI/src/com/android/keyguard/dagger/{ContainerView.java => RootView.java} (96%) create mode 100644 packages/SystemUI/src/com/android/systemui/util/ViewController.java 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 dadbc22760b9d..3af7507ae2b46 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 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 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 63d4004fb6402..062ab41152633 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 57b3761c294f8..676000ba4f2e5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java @@ -306,13 +306,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { } } - /** - * Called before this view is being removed. - */ - public void cleanUp() { - getSecurityContainer().onPause(); - } - @Override public boolean dispatchKeyEvent(KeyEvent event) { if (interceptMediaKey(event)) { 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 0000000000000..fb1569a6b8aa5 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java @@ -0,0 +1,69 @@ +/* + * 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.internal.widget.LockPatternUtils; +import com.android.keyguard.dagger.KeyguardBouncerScope; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** Controller for a {@link KeyguardHostView}. */ +@KeyguardBouncerScope +public class KeyguardHostViewController extends ViewController { + private final KeyguardHostView mView; + private final KeyguardSecurityContainerController mKeyguardSecurityContainerController; + private final LockPatternUtils mLockPatternUtils; + private final ViewMediatorCallback mViewMediatorCallback; + + @Inject + public KeyguardHostViewController(KeyguardHostView view, + KeyguardSecurityContainerController keyguardSecurityContainerController, + LockPatternUtils lockPatternUtils, + ViewMediatorCallback viewMediatorCallback) { + super(view); + mView = view; + mKeyguardSecurityContainerController = keyguardSecurityContainerController; + mLockPatternUtils = lockPatternUtils; + mViewMediatorCallback = viewMediatorCallback; + } + + /** Initialize the Controller. */ + public void init() { + super.init(); + mView.setLockPatternUtils(mLockPatternUtils); + mView.setViewMediatorCallback(mViewMediatorCallback); + mKeyguardSecurityContainerController.init(); + } + + @Override + protected void onViewAttached() { + } + + @Override + protected void onViewDetached() { + } + + public KeyguardHostView getView() { + return mView; + } + + /** Called before this view is being removed. */ + public void cleanUp() { + mKeyguardSecurityContainerController.onPause(); + } +} 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 0000000000000..71a28d2944f3b --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java @@ -0,0 +1,70 @@ +/* + * 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 { + private final KeyguardMessageArea mView; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final ConfigurationController mConfigurationController; + + private KeyguardMessageAreaController(KeyguardMessageArea view, + KeyguardUpdateMonitor keyguardUpdateMonitor, + ConfigurationController configurationController) { + super(view); + + mView = 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 0000000000000..79711566251d7 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java @@ -0,0 +1,51 @@ +/* + * 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 { + private final ViewGroup mView; + + @Inject + public KeyguardRootViewController(@RootView ViewGroup view) { + super(view); + mView = 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 0000000000000..9554f3ac36192 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -0,0 +1,51 @@ +/* + * 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.util.ViewController; + +import javax.inject.Inject; + +/** Controller for {@link KeyguardSecurityContainer} */ +public class KeyguardSecurityContainerController extends ViewController { + + private final KeyguardSecurityContainer mView; + private final KeyguardSecurityViewController.Factory mKeyguardSecurityViewControllerFactory; + + @Inject + KeyguardSecurityContainerController(KeyguardSecurityContainer view, + KeyguardSecurityViewController.Factory keyguardSecurityViewControllerFactory) { + super(view); + mView = view; + mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; + } + + @Override + protected void onViewAttached() { + + } + + @Override + protected void onViewDetached() { + + } + + /** */ + public void onPause() { + mView.onPause(); + } +} 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 0000000000000..4408eca95fd59 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java @@ -0,0 +1,57 @@ +/* + * 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 { + + private final KeyguardSecurityView mView; + + private KeyguardSecurityViewController(KeyguardSecurityView view) { + super((View) view); + 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 84deaca096aa3..5160b7e01e892 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 0000000000000..b6010c8915e7c --- /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 similarity index 96% rename from packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java rename to packages/SystemUI/src/com/android/keyguard/dagger/RootView.java index e65f19db5ac24..5ebff097604b8 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 09034c0899f51..69bf78aa8b018 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -27,21 +27,21 @@ 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; @@ -57,7 +57,6 @@ import javax.inject.Inject; /** * A class which manages the bouncer on the lockscreen. */ -@KeyguardBouncerScope public class KeyguardBouncer { private static final String TAG = "KeyguardBouncer"; @@ -68,7 +67,6 @@ public class KeyguardBouncer { 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 +74,7 @@ public class KeyguardBouncer { private final BouncerExpansionCallback mExpansionCallback; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final KeyguardStateController mKeyguardStateController; + private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { @Override @@ -86,6 +85,7 @@ 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(); @@ -95,22 +95,22 @@ public class KeyguardBouncer { 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, + KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { mContext = context; mCallback = callback; - mLockPatternUtils = lockPatternUtils; mContainer = container; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mFalsingManager = falsingManager; @@ -118,6 +118,7 @@ public class KeyguardBouncer { mExpansionCallback = expansionCallback; mHandler = handler; mKeyguardStateController = keyguardStateController; + mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); mKeyguardBypassController = keyguardBypassController; } @@ -309,7 +310,7 @@ public class KeyguardBouncer { cancelShowRunnable(); if (mKeyguardView != null) { mKeyguardView.cancelDismissAction(); - mKeyguardView.cleanUp(); + mKeyguardViewController.cleanUp(); } mIsAnimatingAway = false; if (mRoot != null) { @@ -442,10 +443,14 @@ 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(); + mKeyguardView = mKeyguardViewController.getView(); + mContainer.addView(mRoot, mContainer.getChildCount()); mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset( com.android.systemui.R.dimen.status_bar_height); @@ -528,4 +533,43 @@ 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 KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; + + @Inject + public Factory(Context context, ViewMediatorCallback callback, + DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager, + KeyguardStateController keyguardStateController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + KeyguardBypassController keyguardBypassController, Handler handler, + KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { + mContext = context; + mCallback = callback; + mDismissCallbackRegistry = dismissCallbackRegistry; + mFalsingManager = falsingManager; + mKeyguardStateController = keyguardStateController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mKeyguardBypassController = keyguardBypassController; + mHandler = handler; + mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; + } + + public KeyguardBouncer create(@RootView ViewGroup container, + BouncerExpansionCallback expansionCallback) { + return new KeyguardBouncer(mContext, mCallback, container, + mDismissCallbackRegistry, mFalsingManager, expansionCallback, + mKeyguardStateController, mKeyguardUpdateMonitor, mKeyguardBypassController, + mHandler, 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 b56993b5f4398..51209d166eeeb 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 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, 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 0000000000000..66503f550c07b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java @@ -0,0 +1,70 @@ +/* + * 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()}. + */ +public abstract class ViewController { + private final View 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(View 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/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java index 0a041e4a4dc57..ee6488d9e0717 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 @@ -43,11 +43,13 @@ 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,10 +78,10 @@ public class KeyguardBouncerTest extends SysuiTestCase { @Mock private ViewMediatorCallback mViewMediatorCallback; @Mock - private LockPatternUtils mLockPatternUtils; - @Mock private DismissCallbackRegistry mDismissCallbackRegistry; @Mock + private KeyguardHostViewController mKeyguardHostViewController; + @Mock private KeyguardHostView mKeyguardHostView; @Mock private ViewTreeObserver mViewTreeObserver; @@ -96,7 +98,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; @@ -116,19 +124,23 @@ 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(mKeyguardHostViewController.getView()).thenReturn(mKeyguardHostView); + 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, mKeyguardBouncerComponentFactory) + .create(container, mExpansionCallback); } @Test 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 108327341f94c..9832d31f7b05d 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); From f6032e30d71f51d8f5b5c037ec500b4aa589b731 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Mon, 31 Aug 2020 12:29:02 -0400 Subject: [PATCH 2/3] 2/N Use KeyguardHostViewController in KeyguardBouncer. This mostly proxies existing calls through to the view. A few exceptions were made where it was obvious what to change. Also, make ViewController take a View type to streamling initialization a bit more. Bug: 166448040 Test: atest SystemUITests && manual. Change-Id: If849ff57c4b8462e07cc9a4b0546fe7d2a6a0c0a --- .../android/keyguard/KeyguardHostView.java | 37 ---- .../keyguard/KeyguardHostViewController.java | 175 +++++++++++++++++- .../KeyguardMessageAreaController.java | 4 +- .../keyguard/KeyguardRootViewController.java | 5 +- .../KeyguardSecurityContainerController.java | 4 +- .../KeyguardSecurityViewController.java | 3 +- .../statusbar/phone/KeyguardBouncer.java | 121 +++++------- .../android/systemui/util/ViewController.java | 8 +- .../statusbar/phone/KeyguardBouncerTest.java | 64 +++---- 9 files changed, 253 insertions(+), 168 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java index 676000ba4f2e5..8fa4bf6cd237f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java @@ -23,7 +23,6 @@ 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; @@ -36,7 +35,6 @@ 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; @@ -60,40 +58,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { 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 @@ -111,7 +75,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { public KeyguardHostView(Context context, AttributeSet attrs) { super(context, attrs); - Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateCallback); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java index fb1569a6b8aa5..381071994e7b4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java @@ -16,27 +16,77 @@ package com.android.keyguard; +import android.content.res.ColorStateList; +import android.service.trust.TrustAgentService; +import android.util.Log; +import android.util.MathUtils; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewTreeObserver; + import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.dagger.KeyguardBouncerScope; +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 javax.inject.Inject; /** Controller for a {@link KeyguardHostView}. */ @KeyguardBouncerScope -public class KeyguardHostViewController extends ViewController { - private final KeyguardHostView mView; +public class KeyguardHostViewController extends ViewController { + private static final String TAG = "KeyguardViewBase"; + + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final KeyguardSecurityContainerController mKeyguardSecurityContainerController; private final LockPatternUtils mLockPatternUtils; private final ViewMediatorCallback mViewMediatorCallback; + private final KeyguardUpdateMonitorCallback mUpdateCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onUserSwitchComplete(int userId) { + mView.getSecurityContainer().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."); + } + mView.dismiss(false /* authenticated */, userId, + /* bypassSecondaryLockScreen */ false); + } else { + mViewMediatorCallback.playTrustedSound(); + } + } + } + }; + @Inject public KeyguardHostViewController(KeyguardHostView view, + KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardSecurityContainerController keyguardSecurityContainerController, LockPatternUtils lockPatternUtils, ViewMediatorCallback viewMediatorCallback) { super(view); - mView = view; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; mKeyguardSecurityContainerController = keyguardSecurityContainerController; mLockPatternUtils = lockPatternUtils; mViewMediatorCallback = viewMediatorCallback; @@ -52,18 +102,129 @@ public class KeyguardHostViewController extends ViewController { @Override protected void onViewAttached() { + mKeyguardUpdateMonitor.registerCallback(mUpdateCallback); } @Override protected void onViewDetached() { - } - - public KeyguardHostView getView() { - return mView; + mKeyguardUpdateMonitor.removeCallback(mUpdateCallback); } /** Called before this view is being removed. */ public void cleanUp() { mKeyguardSecurityContainerController.onPause(); } + + public void resetSecurityContainer() { + mView.resetSecurityContainer(); + } + + public boolean dismiss(int activeUserId) { + return mView.dismiss(activeUserId); + } + + public void onResume() { + mView.onResume(); + } + + public CharSequence getAccessibilityTitleForCurrentMode() { + return mView.getAccessibilityTitleForCurrentMode(); + } + + public void showErrorMessage(CharSequence customMessage) { + mView.showErrorMessage(customMessage); + } + + 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) { + mView.startAppearAnimation(); + } else { + mView.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + mView.getViewTreeObserver().removeOnPreDrawListener(this); + mView.startAppearAnimation(); + return true; + } + }); + mView.requestLayout(); + } + } + + public void showPromptReason(int reason) { + mView.showPromptReason(reason); + } + + public void showMessage(String message, ColorStateList colorState) { + mView.showMessage(message, colorState); + } + + public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) { + mView.setOnDismissAction(action, cancelAction); + } + + public void cancelDismissAction() { + mView.cancelDismissAction(); + } + + public void startDisappearAnimation(Runnable runnable) { + mView.startDisappearAnimation(runnable); + } + + public void onPause() { + mView.onPause(); + } + + public void showPrimarySecurityScreen() { + mView.showPrimarySecurityScreen(); + } + + 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()); + } + + public void onStartingToHide() { + mView.onStartingToHide(); + } + + public boolean hasDismissActions() { + return mView.hasDismissActions(); + } + + public SecurityMode getCurrentSecurityMode() { + return mView.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() { + return mView.handleBackKey(); + } + + public boolean shouldEnableMenuKey() { + return mView.shouldEnableMenuKey(); + } + + public boolean interceptMediaKey(KeyEvent event) { + return mView.interceptMediaKey(event); + } + + public void finish(boolean strongAuth, int currentUser) { + mView.finish(strongAuth, currentUser); + } + + } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java index 71a28d2944f3b..f056bdbb97065 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java @@ -22,8 +22,7 @@ import com.android.systemui.util.ViewController; import javax.inject.Inject; /** Controller for a {@link KeyguardMessageAreaController}. */ -public class KeyguardMessageAreaController extends ViewController { - private final KeyguardMessageArea mView; +public class KeyguardMessageAreaController extends ViewController { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final ConfigurationController mConfigurationController; @@ -32,7 +31,6 @@ public class KeyguardMessageAreaController extends ViewController { ConfigurationController configurationController) { super(view); - mView = view; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mConfigurationController = configurationController; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java index 79711566251d7..5c125fcc95cbd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java @@ -26,13 +26,10 @@ import com.android.systemui.util.ViewController; import javax.inject.Inject; /** Controller for a {@link KeyguardBouncer}'s Root view. */ @KeyguardBouncerScope -public class KeyguardRootViewController extends ViewController { - private final ViewGroup mView; - +public class KeyguardRootViewController extends ViewController { @Inject public KeyguardRootViewController(@RootView ViewGroup view) { super(view); - mView = view; } public ViewGroup getView() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 9554f3ac36192..30480a15b4379 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -21,16 +21,14 @@ import com.android.systemui.util.ViewController; import javax.inject.Inject; /** Controller for {@link KeyguardSecurityContainer} */ -public class KeyguardSecurityContainerController extends ViewController { +public class KeyguardSecurityContainerController extends ViewController { - private final KeyguardSecurityContainer mView; private final KeyguardSecurityViewController.Factory mKeyguardSecurityViewControllerFactory; @Inject KeyguardSecurityContainerController(KeyguardSecurityContainer view, KeyguardSecurityViewController.Factory keyguardSecurityViewControllerFactory) { super(view); - mView = view; mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java index 4408eca95fd59..ef9ba19fbb435 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java @@ -24,12 +24,13 @@ import javax.inject.Inject; /** Controller for a {@link KeyguardSecurityView}. */ -public class KeyguardSecurityViewController extends ViewController { +public class KeyguardSecurityViewController extends ViewController { 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; } 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 69bf78aa8b018..3665c39bd9ea7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -25,14 +25,11 @@ 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.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.WindowInsets; -import com.android.keyguard.KeyguardHostView; import com.android.keyguard.KeyguardHostViewController; import com.android.keyguard.KeyguardRootViewController; import com.android.keyguard.KeyguardSecurityModel; @@ -43,8 +40,6 @@ import com.android.keyguard.ViewMediatorCallback; 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; @@ -61,7 +56,7 @@ 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; @@ -74,6 +69,7 @@ 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() { @@ -84,11 +80,10 @@ 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(); } }; @@ -108,6 +103,7 @@ public class KeyguardBouncer { KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardBypassController keyguardBypassController, Handler handler, + KeyguardSecurityModel keyguardSecurityModel, KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { mContext = context; mCallback = callback; @@ -118,6 +114,7 @@ public class KeyguardBouncer { mExpansionCallback = expansionCallback; mHandler = handler; mKeyguardStateController = keyguardStateController; + mKeyguardSecurityModel = keyguardSecurityModel; mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); mKeyguardBypassController = keyguardBypassController; @@ -169,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; } @@ -205,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()); } } } @@ -234,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, @@ -271,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"); } @@ -294,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 */); } @@ -308,8 +291,8 @@ public class KeyguardBouncer { mFalsingManager.onBouncerHidden(); mCallback.onBouncerVisiblityChanged(false /* shown */); cancelShowRunnable(); - if (mKeyguardView != null) { - mKeyguardView.cancelDismissAction(); + if (mKeyguardViewController != null) { + mKeyguardViewController.cancelDismissAction(); mKeyguardViewController.cleanUp(); } mIsAnimatingAway = false; @@ -329,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(); } @@ -346,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(); } } @@ -381,7 +365,7 @@ public class KeyguardBouncer { } private void showPrimarySecurityScreen() { - mKeyguardView.showPrimarySecurityScreen(); + mKeyguardViewController.showPrimarySecurityScreen(); } /** @@ -392,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) { @@ -406,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() { @@ -449,7 +425,6 @@ public class KeyguardBouncer { mRoot = mRootViewController.getView(); // TODO(b/166448040): Don't access root view here. mKeyguardViewController = component.getKeyguardHostViewController(); mKeyguardViewController.init(); - mKeyguardView = mKeyguardViewController.getView(); mContainer.addView(mRoot, mContainer.getChildCount()); mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset( @@ -470,7 +445,7 @@ public class KeyguardBouncer { } public boolean onBackPressed() { - return mKeyguardView != null && mKeyguardView.handleBackKey(); + return mKeyguardViewController != null && mKeyguardViewController.handleBackKey(); } /** @@ -478,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; } @@ -488,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; @@ -499,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) { @@ -521,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); } @@ -544,6 +520,7 @@ public class KeyguardBouncer { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final KeyguardBypassController mKeyguardBypassController; private final Handler mHandler; + private final KeyguardSecurityModel mKeyguardSecurityModel; private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; @Inject @@ -552,6 +529,7 @@ public class KeyguardBouncer { KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardBypassController keyguardBypassController, Handler handler, + KeyguardSecurityModel keyguardSecurityModel, KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { mContext = context; mCallback = callback; @@ -561,6 +539,7 @@ public class KeyguardBouncer { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mKeyguardBypassController = keyguardBypassController; mHandler = handler; + mKeyguardSecurityModel = keyguardSecurityModel; mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; } @@ -569,7 +548,7 @@ public class KeyguardBouncer { return new KeyguardBouncer(mContext, mCallback, container, mDismissCallbackRegistry, mFalsingManager, expansionCallback, mKeyguardStateController, mKeyguardUpdateMonitor, mKeyguardBypassController, - mHandler, mKeyguardBouncerComponentFactory); + mHandler, mKeyguardSecurityModel, mKeyguardBouncerComponentFactory); } } } diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java index 66503f550c07b..64f8dbbb9e34d 100644 --- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java +++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java @@ -24,9 +24,11 @@ import android.view.View.OnAttachStateChangeListener; * * Implementations should handle setup and teardown related activities inside of * {@link #onViewAttached()} and {@link #onViewDetached()}. + * + * @param View class that this ViewController is for. */ -public abstract class ViewController { - private final View mView; +public abstract class ViewController { + protected final T mView; private boolean mInited; private OnAttachStateChangeListener mOnAttachStateListener = new OnAttachStateChangeListener() { @@ -41,7 +43,7 @@ public abstract class ViewController { } }; - protected ViewController(View view) { + protected ViewController(T view) { mView = view; } 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 ee6488d9e0717..1b05ad7f8b5b3 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,12 +38,10 @@ 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.keyguard.KeyguardHostView; import com.android.keyguard.KeyguardHostViewController; import com.android.keyguard.KeyguardRootViewController; import com.android.keyguard.KeyguardSecurityModel; @@ -82,10 +80,6 @@ public class KeyguardBouncerTest extends SysuiTestCase { @Mock private KeyguardHostViewController mKeyguardHostViewController; @Mock - private KeyguardHostView mKeyguardHostView; - @Mock - private ViewTreeObserver mViewTreeObserver; - @Mock private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -114,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) invocation -> mRootVisibility); doAnswer(invocation -> { @@ -131,15 +124,14 @@ public class KeyguardBouncerTest extends SysuiTestCase { .thenReturn(mRootViewController); when(mRootViewController.getView()).thenReturn(mRootView); - when(mKeyguardHostViewController.getView()).thenReturn(mKeyguardHostView); + 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.Factory(getContext(), mViewMediatorCallback, mDismissCallbackRegistry, mFalsingManager, mKeyguardStateController, mKeyguardUpdateMonitor, - mKeyguardBypassController, mHandler, mKeyguardBouncerComponentFactory) + mKeyguardBypassController, mHandler, mKeyguardSecurityModel, + mKeyguardBouncerComponentFactory) .create(container, mExpansionCallback); } @@ -166,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 @@ -189,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 @@ -213,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 @@ -230,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 @@ -242,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()); } @@ -279,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 @@ -287,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 @@ -295,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()); } @@ -309,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]); } @@ -334,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 @@ -358,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); } @@ -404,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()); } From 860a2c0343354be81c8b845b1ee3075c0c5ca10e Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Mon, 31 Aug 2020 16:59:58 -0400 Subject: [PATCH 3/3] 3/N Use KeyguardSecurityContainerController in KHVC. Use the KeyguardSecurityContainerController in the KeyguardHostViewController instead of the view directly. This actually cleans up KeyguardHostView quite a bit, with all lot of its business logic moved over to its view. The KeyguardSecurityContainerController doesn't do much except to proxy through calls to its view for now. Bug: 166448040 Test: atest SystemUITests && manual Change-Id: I96a27b673c4579983bb07b7fb7ef321a022f0f65 --- .../android/keyguard/KeyguardHostView.java | 359 +----------------- .../keyguard/KeyguardHostViewController.java | 298 +++++++++++++-- .../KeyguardSecurityContainerController.java | 73 +++- ...va => KeyguardHostViewControllerTest.java} | 44 ++- 4 files changed, 360 insertions(+), 414 deletions(-) rename packages/SystemUI/tests/src/com/android/keyguard/{KeyguardHostViewTest.java => KeyguardHostViewControllerTest.java} (61%) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java index 8fa4bf6cd237f..08e9cf60a65ac 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java @@ -16,30 +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.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.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 @@ -49,26 +30,11 @@ 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; - // 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); } @@ -85,330 +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(); - } - } - - @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 index 381071994e7b4..7aabb17de90cd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java @@ -16,39 +16,60 @@ 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.internal.widget.LockPatternUtils; +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 { 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 LockPatternUtils mLockPatternUtils; + 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) { - mView.getSecurityContainer().showPrimarySecurityScreen(false /* turning off */); + mKeyguardSecurityContainerController.showPrimarySecurityScreen( + false /* turning off */); } @Override @@ -70,7 +91,7 @@ public class KeyguardHostViewController extends ViewController //agent. Log.i(TAG, "TrustAgent dismissed Keyguard."); } - mView.dismiss(false /* authenticated */, userId, + mSecurityCallback.dismiss(false /* authenticated */, userId, /* bypassSecondaryLockScreen */ false); } else { mViewMediatorCallback.playTrustedSound(); @@ -79,35 +100,102 @@ public class KeyguardHostViewController extends ViewController } }; + 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, - LockPatternUtils lockPatternUtils, + AudioManager audioManager, + TelephonyManager telephonyManager, ViewMediatorCallback viewMediatorCallback) { super(view); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mKeyguardSecurityContainerController = keyguardSecurityContainerController; - mLockPatternUtils = lockPatternUtils; + mAudioManager = audioManager; + mTelephonyManager = telephonyManager; mViewMediatorCallback = viewMediatorCallback; } /** Initialize the Controller. */ public void init() { super.init(); - mView.setLockPatternUtils(mLockPatternUtils); 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. */ @@ -116,37 +204,46 @@ public class KeyguardHostViewController extends ViewController } public void resetSecurityContainer() { - mView.resetSecurityContainer(); + mKeyguardSecurityContainerController.reset(); } - public boolean dismiss(int activeUserId) { - return mView.dismiss(activeUserId); + /** + * 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() { - mView.onResume(); + if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); + mKeyguardSecurityContainerController.onResume(KeyguardSecurityView.SCREEN_ON); + mView.requestFocus(); } public CharSequence getAccessibilityTitleForCurrentMode() { - return mView.getAccessibilityTitleForCurrentMode(); - } - - public void showErrorMessage(CharSequence customMessage) { - mView.showErrorMessage(customMessage); + 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) { - mView.startAppearAnimation(); + mKeyguardSecurityContainerController.startAppearAnimation(); } else { mView.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mView.getViewTreeObserver().removeOnPreDrawListener(this); - mView.startAppearAnimation(); + mKeyguardSecurityContainerController.startAppearAnimation(); return true; } }); @@ -154,32 +251,71 @@ public class KeyguardHostViewController extends ViewController } } + /** + * 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) { - mView.showPromptReason(reason); + mKeyguardSecurityContainerController.showPromptReason(reason); } - public void showMessage(String message, ColorStateList colorState) { - mView.showMessage(message, colorState); + 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) { - mView.setOnDismissAction(action, cancelAction); + if (mCancelAction != null) { + mCancelAction.run(); + mCancelAction = null; + } + mDismissAction = action; + mCancelAction = cancelAction; } public void cancelDismissAction() { - mView.cancelDismissAction(); + setOnDismissAction(null, null); } - public void startDisappearAnimation(Runnable runnable) { - mView.startDisappearAnimation(runnable); + 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() { - mView.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() { - mView.showPrimarySecurityScreen(); + if (DEBUG) Log.d(TAG, "show()"); + mKeyguardSecurityContainerController.showPrimarySecurityScreen(false); } public void setExpansion(float fraction) { @@ -188,16 +324,19 @@ public class KeyguardHostViewController extends ViewController mView.setTranslationY(fraction * mView.getHeight()); } + /** + * When bouncer was visible and is starting to become hidden. + */ public void onStartingToHide() { - mView.onStartingToHide(); + mKeyguardSecurityContainerController.onStartingToHide(); } public boolean hasDismissActions() { - return mView.hasDismissActions(); + return mDismissAction != null || mCancelAction != null; } public SecurityMode getCurrentSecurityMode() { - return mView.getCurrentSecurityMode(); + return mKeyguardSecurityContainerController.getCurrentSecurityMode(); } public int getTop() { @@ -211,19 +350,110 @@ public class KeyguardHostViewController extends ViewController } public boolean handleBackKey() { - return mView.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() { - return mView.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) { - return mView.interceptMediaKey(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) { - mView.finish(strongAuth, currentUser); + mSecurityCallback.finish(strongAuth, currentUser); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 30480a15b4379..17f25bd08ef49 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -16,6 +16,11 @@ 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; @@ -23,27 +28,91 @@ import javax.inject.Inject; /** Controller for {@link KeyguardSecurityContainer} */ public class KeyguardSecurityContainerController extends ViewController { + 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/tests/src/com/android/keyguard/KeyguardHostViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java similarity index 61% rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java rename to packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java index dd5c8335eefa7..54e879e2ff387 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(); } }