Merge "Hide views on lockscreen when wallpaper dream is active" into udc-qpr-dev

This commit is contained in:
Coco Duan
2023-07-11 02:48:13 +00:00
committed by Android (Google) Code Review
11 changed files with 756 additions and 405 deletions

View File

@@ -21,6 +21,8 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.annotation.Nullable;
import android.database.ContentObserver;
@@ -33,12 +35,15 @@ import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.LogLevel;
import com.android.systemui.log.dagger.KeyguardClockLog;
@@ -58,6 +63,7 @@ import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter;
import java.util.Locale;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -99,8 +105,20 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private boolean mOnlyClock = false;
private boolean mIsActiveDreamLockscreenHosted = false;
private FeatureFlags mFeatureFlags;
private KeyguardInteractor mKeyguardInteractor;
private final DelayableExecutor mUiExecutor;
private boolean mCanShowDoubleLineClock = true;
@VisibleForTesting
final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback =
(Boolean isLockscreenHosted) -> {
if (mIsActiveDreamLockscreenHosted == isLockscreenHosted) {
return;
}
mIsActiveDreamLockscreenHosted = isLockscreenHosted;
updateKeyguardStatusAreaVisibility();
};
private final ContentObserver mDoubleLineClockObserver = new ContentObserver(null) {
@Override
public void onChange(boolean change) {
@@ -137,7 +155,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
@Main DelayableExecutor uiExecutor,
DumpManager dumpManager,
ClockEventController clockEventController,
@KeyguardClockLog LogBuffer logBuffer) {
@KeyguardClockLog LogBuffer logBuffer,
KeyguardInteractor keyguardInteractor,
FeatureFlags featureFlags) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mClockRegistry = clockRegistry;
@@ -151,6 +171,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mClockEventController = clockEventController;
mLogBuffer = logBuffer;
mView.setLogBuffer(mLogBuffer);
mFeatureFlags = featureFlags;
mKeyguardInteractor = keyguardInteractor;
mClockChangedListener = new ClockRegistry.ClockChangeListener() {
@Override
@@ -191,6 +213,12 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mDumpManager.unregisterDumpable(getClass().toString()); // unregister previous clocks
mDumpManager.registerDumpable(getClass().toString(), this);
if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
mStatusArea = mView.findViewById(R.id.keyguard_status_area);
collectFlow(mStatusArea, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
mIsActiveDreamLockscreenHostedCallback);
}
}
@Override
@@ -524,6 +552,15 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
}
private void updateKeyguardStatusAreaVisibility() {
if (mStatusArea != null) {
mUiExecutor.execute(() -> {
mStatusArea.setVisibility(
mIsActiveDreamLockscreenHosted ? View.INVISIBLE : View.VISIBLE);
});
}
}
/**
* Sets the clipChildren property on relevant views, to allow the smartspace to draw out of
* bounds during the unlock transition.

View File

@@ -24,6 +24,7 @@ import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.content.res.Configuration;
@@ -124,6 +125,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private int mActivePointerId = -1;
private boolean mIsDozing;
private boolean mIsActiveDreamLockscreenHosted;
private boolean mIsBouncerShowing;
private boolean mRunningFPS;
private boolean mCanDismissLockScreen;
@@ -165,6 +167,13 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
updateVisibility();
};
@VisibleForTesting
final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback =
(Boolean isLockscreenHosted) -> {
mIsActiveDreamLockscreenHosted = isLockscreenHosted;
updateVisibility();
};
@Inject
public LockIconViewController(
@Nullable LockIconView view,
@@ -224,6 +233,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mDozeTransitionCallback);
collectFlow(mView, mKeyguardInteractor.isDozing(), mIsDozingCallback);
}
if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
collectFlow(mView, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
mIsActiveDreamLockscreenHostedCallback);
}
}
@Override
@@ -289,6 +303,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
return;
}
if (mIsKeyguardShowing && mIsActiveDreamLockscreenHosted) {
mView.setVisibility(View.INVISIBLE);
return;
}
boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon
&& !mShowAodUnlockedIcon && !mShowAodLockIcon;
mShowLockIcon = !mCanDismissLockScreen && isLockScreen()
@@ -436,6 +455,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
pw.println(" mSensorTouchLocation: " + mSensorTouchLocation);
pw.println(" mDefaultPaddingPx: " + mDefaultPaddingPx);
pw.println(" mIsActiveDreamLockscreenHosted: " + mIsActiveDreamLockscreenHosted);
if (mView != null) {
mView.dump(pw, args);

View File

@@ -29,6 +29,7 @@ import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
@@ -43,6 +44,7 @@ import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewCont
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
import static com.android.systemui.log.core.LogLevel.ERROR;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.app.AlarmManager;
import android.app.admin.DevicePolicyManager;
@@ -96,6 +98,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.util.IndicationHelper;
import com.android.systemui.log.core.LogLevel;
import com.android.systemui.plugins.FalsingManager;
@@ -114,6 +117,7 @@ import java.io.PrintWriter;
import java.text.NumberFormat;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -171,7 +175,7 @@ public class KeyguardIndicationController {
public KeyguardIndicationRotateTextViewController mRotateTextViewController;
private BroadcastReceiver mBroadcastReceiver;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private KeyguardInteractor mKeyguardInteractor;
private String mPersistentUnlockMessage;
private String mAlignmentIndication;
private CharSequence mTrustGrantedIndication;
@@ -205,7 +209,17 @@ public class KeyguardIndicationController {
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
private boolean mDozing;
private boolean mIsActiveDreamLockscreenHosted;
private final ScreenLifecycle mScreenLifecycle;
@VisibleForTesting
final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback =
(Boolean isLockscreenHosted) -> {
if (mIsActiveDreamLockscreenHosted == isLockscreenHosted) {
return;
}
mIsActiveDreamLockscreenHosted = isLockscreenHosted;
updateDeviceEntryIndication(false);
};
private final ScreenLifecycle.Observer mScreenObserver =
new ScreenLifecycle.Observer() {
@Override
@@ -261,7 +275,8 @@ public class KeyguardIndicationController {
UserTracker userTracker,
BouncerMessageInteractor bouncerMessageInteractor,
FeatureFlags flags,
IndicationHelper indicationHelper
IndicationHelper indicationHelper,
KeyguardInteractor keyguardInteractor
) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
@@ -289,6 +304,7 @@ public class KeyguardIndicationController {
mBouncerMessageInteractor = bouncerMessageInteractor;
mFeatureFlags = flags;
mIndicationHelper = indicationHelper;
mKeyguardInteractor = keyguardInteractor;
mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
@@ -371,6 +387,10 @@ public class KeyguardIndicationController {
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, intentFilter);
}
if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
collectFlow(mIndicationArea, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
mIsActiveDreamLockscreenHostedCallback);
}
}
/**
@@ -878,6 +898,12 @@ public class KeyguardIndicationController {
return;
}
// Device is dreaming and the dream is hosted in lockscreen
if (mIsActiveDreamLockscreenHosted) {
mIndicationArea.setVisibility(GONE);
return;
}
// A few places might need to hide the indication, so always start by making it visible
mIndicationArea.setVisibility(VISIBLE);
@@ -1069,6 +1095,7 @@ public class KeyguardIndicationController {
pw.println(" mBiometricMessageFollowUp: " + mBiometricMessageFollowUp);
pw.println(" mBatteryLevel: " + mBatteryLevel);
pw.println(" mBatteryPresent: " + mBatteryPresent);
pw.println(" mIsActiveDreamLockscreenHosted: " + mIsActiveDreamLockscreenHosted);
pw.println(" AOD text: " + (
mTopIndicationView == null ? null : mTopIndicationView.getText()));
pw.println(" computePowerIndication(): " + computePowerIndication());

View File

@@ -0,0 +1,210 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.keyguard;
import static android.view.View.INVISIBLE;
import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.ClockEvents;
import com.android.systemui.plugins.ClockFaceConfig;
import com.android.systemui.plugins.ClockFaceController;
import com.android.systemui.plugins.ClockFaceEvents;
import com.android.systemui.plugins.ClockTickRate;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase {
@Mock
protected KeyguardClockSwitch mView;
@Mock
protected StatusBarStateController mStatusBarStateController;
@Mock
protected ClockRegistry mClockRegistry;
@Mock
KeyguardSliceViewController mKeyguardSliceViewController;
@Mock
NotificationIconAreaController mNotificationIconAreaController;
@Mock
LockscreenSmartspaceController mSmartspaceController;
@Mock
Resources mResources;
@Mock
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock
protected ClockController mClockController;
@Mock
protected ClockFaceController mLargeClockController;
@Mock
protected ClockFaceController mSmallClockController;
@Mock
protected ClockAnimations mClockAnimations;
@Mock
protected ClockEvents mClockEvents;
@Mock
protected ClockFaceEvents mClockFaceEvents;
@Mock
DumpManager mDumpManager;
@Mock
ClockEventController mClockEventController;
@Mock
protected NotificationIconContainer mNotificationIcons;
@Mock
protected AnimatableClockView mSmallClockView;
@Mock
protected AnimatableClockView mLargeClockView;
@Mock
protected FrameLayout mSmallClockFrame;
@Mock
protected FrameLayout mLargeClockFrame;
@Mock
protected SecureSettings mSecureSettings;
@Mock
protected LogBuffer mLogBuffer;
protected final View mFakeDateView = (View) (new ViewGroup(mContext) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {}
});
protected final View mFakeWeatherView = new View(mContext);
protected final View mFakeSmartspaceView = new View(mContext);
protected KeyguardClockSwitchController mController;
protected View mSliceView;
protected LinearLayout mStatusArea;
protected FakeExecutor mExecutor;
protected FakeFeatureFlags mFakeFeatureFlags;
@Captor protected ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mView.findViewById(R.id.left_aligned_notification_icon_container))
.thenReturn(mNotificationIcons);
when(mNotificationIcons.getLayoutParams()).thenReturn(
mock(RelativeLayout.LayoutParams.class));
when(mView.getContext()).thenReturn(getContext());
when(mView.getResources()).thenReturn(mResources);
when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
.thenReturn(100);
when(mResources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin))
.thenReturn(-200);
when(mResources.getInteger(R.integer.keyguard_date_weather_view_invisibility))
.thenReturn(INVISIBLE);
when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
when(mSmallClockView.getContext()).thenReturn(getContext());
when(mLargeClockView.getContext()).thenReturn(getContext());
when(mView.isAttachedToWindow()).thenReturn(true);
when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
mExecutor = new FakeExecutor(new FakeSystemClock());
mFakeFeatureFlags = new FakeFeatureFlags();
mFakeFeatureFlags.set(FACE_AUTH_REFACTOR, false);
mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
mController = new KeyguardClockSwitchController(
mView,
mStatusBarStateController,
mClockRegistry,
mKeyguardSliceViewController,
mNotificationIconAreaController,
mSmartspaceController,
mKeyguardUnlockAnimationController,
mSecureSettings,
mExecutor,
mDumpManager,
mClockEventController,
mLogBuffer,
KeyguardInteractorFactory.create(mFakeFeatureFlags).getKeyguardInteractor(),
mFakeFeatureFlags
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mLargeClockController.getView()).thenReturn(mLargeClockView);
when(mSmallClockController.getView()).thenReturn(mSmallClockView);
when(mClockController.getLargeClock()).thenReturn(mLargeClockController);
when(mClockController.getSmallClock()).thenReturn(mSmallClockController);
when(mClockController.getEvents()).thenReturn(mClockEvents);
when(mSmallClockController.getEvents()).thenReturn(mClockFaceEvents);
when(mLargeClockController.getEvents()).thenReturn(mClockFaceEvents);
when(mLargeClockController.getAnimations()).thenReturn(mClockAnimations);
when(mSmallClockController.getAnimations()).thenReturn(mClockAnimations);
when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
when(mClockEventController.getClock()).thenReturn(mClockController);
when(mSmallClockController.getConfig())
.thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
when(mLargeClockController.getConfig())
.thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
mSliceView = new View(getContext());
when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
mStatusArea = new LinearLayout(getContext());
when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
}
protected void init() {
mController.init();
verify(mView, atLeast(1)).addOnAttachStateChangeListener(mAttachCaptor.capture());
mAttachCaptor.getValue().onViewAttachedToWindow(mView);
}
}

View File

@@ -21,186 +21,33 @@ import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.ClockEvents;
import com.android.systemui.plugins.ClockFaceConfig;
import com.android.systemui.plugins.ClockFaceController;
import com.android.systemui.plugins.ClockFaceEvents;
import com.android.systemui.plugins.ClockTickRate;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.verification.VerificationMode;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Mock
private KeyguardClockSwitch mView;
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
private ClockRegistry mClockRegistry;
@Mock
KeyguardSliceViewController mKeyguardSliceViewController;
@Mock
NotificationIconAreaController mNotificationIconAreaController;
@Mock
LockscreenSmartspaceController mSmartspaceController;
@Mock
Resources mResources;
@Mock
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock
private ClockController mClockController;
@Mock
private ClockFaceController mLargeClockController;
@Mock
private ClockFaceController mSmallClockController;
@Mock
private ClockAnimations mClockAnimations;
@Mock
private ClockEvents mClockEvents;
@Mock
private ClockFaceEvents mClockFaceEvents;
@Mock
DumpManager mDumpManager;
@Mock
ClockEventController mClockEventController;
@Mock
private NotificationIconContainer mNotificationIcons;
@Mock
private AnimatableClockView mSmallClockView;
@Mock
private AnimatableClockView mLargeClockView;
@Mock
private FrameLayout mSmallClockFrame;
@Mock
private FrameLayout mLargeClockFrame;
@Mock
private SecureSettings mSecureSettings;
@Mock
private LogBuffer mLogBuffer;
private final View mFakeDateView = (View) (new ViewGroup(mContext) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {}
});
private final View mFakeWeatherView = new View(mContext);
private final View mFakeSmartspaceView = new View(mContext);
private KeyguardClockSwitchController mController;
private View mSliceView;
private FakeExecutor mExecutor;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mView.findViewById(R.id.left_aligned_notification_icon_container))
.thenReturn(mNotificationIcons);
when(mNotificationIcons.getLayoutParams()).thenReturn(
mock(RelativeLayout.LayoutParams.class));
when(mView.getContext()).thenReturn(getContext());
when(mView.getResources()).thenReturn(mResources);
when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
.thenReturn(100);
when(mResources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin))
.thenReturn(-200);
when(mResources.getInteger(R.integer.keyguard_date_weather_view_invisibility))
.thenReturn(View.INVISIBLE);
when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
when(mSmallClockView.getContext()).thenReturn(getContext());
when(mLargeClockView.getContext()).thenReturn(getContext());
when(mView.isAttachedToWindow()).thenReturn(true);
when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
mExecutor = new FakeExecutor(new FakeSystemClock());
mController = new KeyguardClockSwitchController(
mView,
mStatusBarStateController,
mClockRegistry,
mKeyguardSliceViewController,
mNotificationIconAreaController,
mSmartspaceController,
mKeyguardUnlockAnimationController,
mSecureSettings,
mExecutor,
mDumpManager,
mClockEventController,
mLogBuffer
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mLargeClockController.getView()).thenReturn(mLargeClockView);
when(mSmallClockController.getView()).thenReturn(mSmallClockView);
when(mClockController.getLargeClock()).thenReturn(mLargeClockController);
when(mClockController.getSmallClock()).thenReturn(mSmallClockController);
when(mClockController.getEvents()).thenReturn(mClockEvents);
when(mSmallClockController.getEvents()).thenReturn(mClockFaceEvents);
when(mLargeClockController.getEvents()).thenReturn(mClockFaceEvents);
when(mLargeClockController.getAnimations()).thenReturn(mClockAnimations);
when(mSmallClockController.getAnimations()).thenReturn(mClockAnimations);
when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
when(mClockEventController.getClock()).thenReturn(mClockController);
when(mSmallClockController.getConfig())
.thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
when(mLargeClockController.getConfig())
.thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
mSliceView = new View(getContext());
when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(
new LinearLayout(getContext()));
}
public class KeyguardClockSwitchControllerTest extends KeyguardClockSwitchControllerBaseTest {
@Test
public void testInit_viewAlreadyAttached() {
mController.init();

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.keyguard
import android.testing.AndroidTestingRunner
import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidTestingRunner::class)
@SmallTest
class KeyguardClockSwitchControllerWithCoroutinesTest : KeyguardClockSwitchControllerBaseTest() {
@Test
fun testStatusAreaVisibility_onLockscreenHostedDreamStateChanged() =
runBlocking(IMMEDIATE) {
// GIVEN starting state for the keyguard clock and wallpaper dream enabled
mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, true)
init()
// WHEN dreaming starts
mController.mIsActiveDreamLockscreenHostedCallback.accept(
true /* isActiveDreamLockscreenHosted */
)
// THEN the status area is hidden
mExecutor.runAllReady()
assertEquals(View.INVISIBLE, mStatusArea.visibility)
// WHEN dreaming stops
mController.mIsActiveDreamLockscreenHostedCallback.accept(
false /* isActiveDreamLockscreenHosted */
)
mExecutor.runAllReady()
// THEN status area view is visible
assertEquals(View.VISIBLE, mStatusArea.visibility)
}
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
}
}

View File

@@ -19,6 +19,7 @@ package com.android.keyguard;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.flags.Flags.MIGRATE_LOCK_ICON;
import static org.mockito.Mockito.any;
@@ -147,6 +148,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(FACE_AUTH_REFACTOR, false);
mFeatureFlags.set(MIGRATE_LOCK_ICON, false);
mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
mUnderTest = new LockIconViewController(
mLockIconView,
mStatusBarStateController,

View File

@@ -17,9 +17,11 @@
package com.android.keyguard
import android.testing.AndroidTestingRunner
import android.view.View
import androidx.test.filters.SmallTest
import com.android.keyguard.LockIconView.ICON_LOCK
import com.android.systemui.doze.util.getBurnInOffset
import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
@@ -117,6 +119,33 @@ class LockIconViewControllerWithCoroutinesTest : LockIconViewControllerBaseTest(
verify(mLockIconView).setTranslationX(0f)
}
@Test
fun testHideLockIconView_onLockscreenHostedDreamStateChanged() =
runBlocking(IMMEDIATE) {
// GIVEN starting state for the lock icon (keyguard) and wallpaper dream enabled
mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, true)
setupShowLockIcon()
init(/* useMigrationFlag= */ true)
reset(mLockIconView)
// WHEN dream starts
mUnderTest.mIsActiveDreamLockscreenHostedCallback.accept(
true /* isActiveDreamLockscreenHosted */
)
// THEN the lock icon is hidden
verify(mLockIconView).visibility = View.INVISIBLE
reset(mLockIconView)
// WHEN the device is no longer dreaming
mUnderTest.mIsActiveDreamLockscreenHostedCallback.accept(
false /* isActiveDreamLockscreenHosted */
)
// THEN lock icon is visible
verify(mLockIconView).visibility = View.VISIBLE
}
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
}

View File

@@ -0,0 +1,295 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.app.Instrumentation;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyResourcesManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Looper;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.testing.TestableLooper;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
import androidx.test.InstrumentationRegistry;
import com.android.internal.app.IBatteryStats;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
import com.android.systemui.keyguard.util.IndicationHelper;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.WakeLockFake;
import org.junit.After;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class KeyguardIndicationControllerBaseTest extends SysuiTestCase {
protected static final String ORGANIZATION_NAME = "organization";
protected static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName(
"com.android.foo",
"bar");
protected static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked;
protected String mDisclosureWithOrganization;
protected String mDisclosureGeneric;
protected String mFinancedDisclosureWithOrganization;
@Mock
protected DevicePolicyManager mDevicePolicyManager;
@Mock
protected DevicePolicyResourcesManager mDevicePolicyResourcesManager;
@Mock
protected ViewGroup mIndicationArea;
@Mock
protected KeyguardStateController mKeyguardStateController;
@Mock
protected KeyguardIndicationTextView mIndicationAreaBottom;
@Mock
protected BroadcastDispatcher mBroadcastDispatcher;
@Mock
protected StatusBarStateController mStatusBarStateController;
@Mock
protected KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
protected UserManager mUserManager;
@Mock
protected IBatteryStats mIBatteryStats;
@Mock
protected DockManager mDockManager;
@Mock
protected KeyguardIndicationRotateTextViewController mRotateTextViewController;
@Mock
protected FalsingManager mFalsingManager;
@Mock
protected LockPatternUtils mLockPatternUtils;
@Mock
protected KeyguardBypassController mKeyguardBypassController;
@Mock
protected AccessibilityManager mAccessibilityManager;
@Mock
protected FaceHelpMessageDeferral mFaceHelpMessageDeferral;
@Mock
protected AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock
protected ScreenLifecycle mScreenLifecycle;
@Mock
protected AuthController mAuthController;
@Mock
protected AlarmManager mAlarmManager;
@Mock
protected UserTracker mUserTracker;
@Captor
protected ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
@Captor
protected ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
@Captor
protected ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
@Captor
protected ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor;
@Captor
protected ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
@Captor
protected ArgumentCaptor<KeyguardStateController.Callback>
mKeyguardStateControllerCallbackCaptor;
@Captor
protected ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
protected KeyguardStateController.Callback mKeyguardStateControllerCallback;
protected KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
protected StatusBarStateController.StateListener mStatusBarStateListener;
protected ScreenLifecycle.Observer mScreenObserver;
protected BroadcastReceiver mBroadcastReceiver;
protected IndicationHelper mIndicationHelper;
protected FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
protected TestableLooper mTestableLooper;
protected final int mCurrentUserId = 1;
protected KeyguardIndicationTextView mTextView; // AOD text
protected KeyguardIndicationController mController;
protected WakeLockFake.Builder mWakeLockBuilder;
protected WakeLockFake mWakeLock;
protected Instrumentation mInstrumentation;
protected FakeFeatureFlags mFlags;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mTestableLooper = TestableLooper.get(this);
mTextView = new KeyguardIndicationTextView(mContext);
mTextView.setAnimationsEnabled(false);
// TODO(b/259908270): remove
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, "true",
/* makeDefault= */ false);
mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
mContext.addMockSystemService(UserManager.class, mUserManager);
mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
ORGANIZATION_NAME);
mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
mFinancedDisclosureWithOrganization = mContext.getString(
R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME);
when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_ON);
when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom))
.thenReturn(mIndicationAreaBottom);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
.thenReturn(DEVICE_OWNER_COMPONENT);
when(mDevicePolicyManager.isFinancedDevice()).thenReturn(false);
// TODO(b/259908270): remove
when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
when(mDevicePolicyResourcesManager.getString(anyString(), any()))
.thenReturn(mDisclosureGeneric);
when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
.thenReturn(mDisclosureWithOrganization);
when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor);
mWakeLock = new WakeLockFake();
mWakeLockBuilder = new WakeLockFake.Builder(mContext);
mWakeLockBuilder.setWakeLock(mWakeLock);
}
@After
public void tearDown() throws Exception {
mTextView.setAnimationsEnabled(true);
if (mController != null) {
mController.destroy();
mController = null;
}
}
protected void createController() {
if (Looper.myLooper() == null) {
Looper.prepare();
}
mFlags = new FakeFeatureFlags();
mFlags.set(KEYGUARD_TALKBACK_FIX, true);
mFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
mFlags.set(FACE_AUTH_REFACTOR, false);
mController = new KeyguardIndicationController(
mContext,
mTestableLooper.getLooper(),
mWakeLockBuilder,
mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
mUserManager, mExecutor, mExecutor, mFalsingManager,
mAuthController, mLockPatternUtils, mScreenLifecycle,
mKeyguardBypassController, mAccessibilityManager,
mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
mAlternateBouncerInteractor,
mAlarmManager,
mUserTracker,
mock(BouncerMessageInteractor.class),
mFlags,
mIndicationHelper,
KeyguardInteractorFactory.create(mFlags).getKeyguardInteractor()
);
mController.init();
mController.setIndicationArea(mIndicationArea);
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
mController.mRotateTextViewController = mRotateTextViewController;
mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
clearInvocations(mIBatteryStats);
verify(mKeyguardStateController).addCallback(
mKeyguardStateControllerCallbackCaptor.capture());
mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
verify(mKeyguardUpdateMonitor).registerCallback(
mKeyguardUpdateMonitorCallbackCaptor.capture());
mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
mScreenObserver = mScreenObserverCaptor.getValue();
mExecutor.runAllReady();
reset(mRotateTextViewController);
}
}

View File

@@ -11,12 +11,11 @@
* 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.systemui.statusbar;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
@@ -26,7 +25,6 @@ import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIME
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
@@ -38,7 +36,6 @@ import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewCont
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_OFF;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_TURNING_ON;
import static com.google.common.truth.Truth.assertThat;
@@ -60,73 +57,28 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.app.Instrumentation;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyResourcesManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.graphics.Color;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.fingerprint.FingerprintManager;
import android.os.BatteryManager;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.internal.app.IBatteryStats;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.TrustGrantFlags;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.util.IndicationHelper;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.WakeLockFake;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.text.NumberFormat;
import java.util.Collections;
@@ -137,205 +89,7 @@ import java.util.Set;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class KeyguardIndicationControllerTest extends SysuiTestCase {
private static final String ORGANIZATION_NAME = "organization";
private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo",
"bar");
private static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked;
private String mDisclosureWithOrganization;
private String mDisclosureGeneric;
private String mFinancedDisclosureWithOrganization;
@Mock
private DevicePolicyManager mDevicePolicyManager;
@Mock
private DevicePolicyResourcesManager mDevicePolicyResourcesManager;
@Mock
private ViewGroup mIndicationArea;
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private KeyguardIndicationTextView mIndicationAreaBottom;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
private UserManager mUserManager;
@Mock
private IBatteryStats mIBatteryStats;
@Mock
private DockManager mDockManager;
@Mock
private KeyguardIndicationRotateTextViewController mRotateTextViewController;
@Mock
private FalsingManager mFalsingManager;
@Mock
private LockPatternUtils mLockPatternUtils;
@Mock
private KeyguardBypassController mKeyguardBypassController;
@Mock
private AccessibilityManager mAccessibilityManager;
@Mock
private FaceHelpMessageDeferral mFaceHelpMessageDeferral;
@Mock
private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock
private ScreenLifecycle mScreenLifecycle;
@Mock
private AuthController mAuthController;
@Mock
private AlarmManager mAlarmManager;
@Mock
private UserTracker mUserTracker;
@Captor
private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
@Captor
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
@Captor
private ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor;
@Captor
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
@Captor
private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallbackCaptor;
@Captor
private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
private KeyguardStateController.Callback mKeyguardStateControllerCallback;
private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
private StatusBarStateController.StateListener mStatusBarStateListener;
private ScreenLifecycle.Observer mScreenObserver;
private BroadcastReceiver mBroadcastReceiver;
private IndicationHelper mIndicationHelper;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private TestableLooper mTestableLooper;
private final int mCurrentUserId = 1;
private KeyguardIndicationTextView mTextView; // AOD text
private KeyguardIndicationController mController;
private WakeLockFake.Builder mWakeLockBuilder;
private WakeLockFake mWakeLock;
private Instrumentation mInstrumentation;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mTestableLooper = TestableLooper.get(this);
mTextView = new KeyguardIndicationTextView(mContext);
mTextView.setAnimationsEnabled(false);
// TODO(b/259908270): remove
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, "true",
/* makeDefault= */ false);
mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
mContext.addMockSystemService(UserManager.class, mUserManager);
mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
ORGANIZATION_NAME);
mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
mFinancedDisclosureWithOrganization = mContext.getString(
R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME);
when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_ON);
when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom))
.thenReturn(mIndicationAreaBottom);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
.thenReturn(DEVICE_OWNER_COMPONENT);
when(mDevicePolicyManager.isFinancedDevice()).thenReturn(false);
// TODO(b/259908270): remove
when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
when(mDevicePolicyResourcesManager.getString(anyString(), any()))
.thenReturn(mDisclosureGeneric);
when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
.thenReturn(mDisclosureWithOrganization);
when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor);
mWakeLock = new WakeLockFake();
mWakeLockBuilder = new WakeLockFake.Builder(mContext);
mWakeLockBuilder.setWakeLock(mWakeLock);
}
@After
public void tearDown() throws Exception {
mTextView.setAnimationsEnabled(true);
if (mController != null) {
mController.destroy();
mController = null;
}
}
private void createController() {
if (Looper.myLooper() == null) {
Looper.prepare();
}
FakeFeatureFlags flags = new FakeFeatureFlags();
flags.set(KEYGUARD_TALKBACK_FIX, true);
mController = new KeyguardIndicationController(
mContext,
mTestableLooper.getLooper(),
mWakeLockBuilder,
mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
mUserManager, mExecutor, mExecutor, mFalsingManager,
mAuthController, mLockPatternUtils, mScreenLifecycle,
mKeyguardBypassController, mAccessibilityManager,
mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
mAlternateBouncerInteractor,
mAlarmManager,
mUserTracker,
mock(BouncerMessageInteractor.class),
flags,
mIndicationHelper
);
mController.init();
mController.setIndicationArea(mIndicationArea);
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
mController.mRotateTextViewController = mRotateTextViewController;
mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
clearInvocations(mIBatteryStats);
verify(mKeyguardStateController).addCallback(
mKeyguardStateControllerCallbackCaptor.capture());
mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
verify(mKeyguardUpdateMonitor).registerCallback(
mKeyguardUpdateMonitorCallbackCaptor.capture());
mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
mScreenObserver = mScreenObserverCaptor.getValue();
mExecutor.runAllReady();
reset(mRotateTextViewController);
}
public class KeyguardIndicationControllerTest extends KeyguardIndicationControllerBaseTest {
@Test
public void createController_setIndicationAreaAgain_destroysPreviousRotateTextViewController() {
// GIVEN a controller with a mocked rotate text view controlller

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@RunWith(AndroidTestingRunner::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class KeyguardIndicationControllerWithCoroutinesTest : KeyguardIndicationControllerBaseTest() {
@Test
fun testIndicationAreaVisibility_onLockscreenHostedDreamStateChanged() =
runBlocking(IMMEDIATE) {
// GIVEN starting state for keyguard indication and wallpaper dream enabled
createController()
mFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, true)
mController.setVisible(true)
// THEN indication area is visible
verify(mIndicationArea, times(2)).visibility = View.VISIBLE
// WHEN the device is dreaming with lockscreen hosted dream
mController.mIsActiveDreamLockscreenHostedCallback.accept(
true /* isActiveDreamLockscreenHosted */
)
mExecutor.runAllReady()
// THEN the indication area is hidden
verify(mIndicationArea).visibility = View.GONE
// WHEN the device stops dreaming with lockscreen hosted dream
mController.mIsActiveDreamLockscreenHostedCallback.accept(
false /* isActiveDreamLockscreenHosted */
)
mExecutor.runAllReady()
// THEN indication area is set visible
verify(mIndicationArea, times(3)).visibility = View.VISIBLE
}
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
}
}