Merge "Rotate keyguard indication messages" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-02-09 15:36:14 +00:00
committed by Android (Google) Code Review
13 changed files with 1394 additions and 275 deletions

View File

@@ -43,14 +43,17 @@
android:accessibilityLiveRegion="polite"/>
<com.android.systemui.statusbar.phone.KeyguardIndicationTextView
android:id="@+id/keyguard_indication_enterprise_disclosure"
android:layout_width="match_parent"
android:id="@+id/keyguard_indication_text_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="48dp"
android:layout_gravity="center_horizontal"
android:layout_centerHorizontal="true"
android:paddingStart="@dimen/keyguard_indication_text_padding"
android:paddingEnd="@dimen/keyguard_indication_text_padding"
android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
android:alpha=".54"
android:alpha=".8"
android:visibility="gone"/>
</LinearLayout>

View File

@@ -199,6 +199,9 @@
<!-- The amount the content shifts upwards when transforming into the shelf -->
<dimen name="shelf_transform_content_shift">32dp</dimen>
<!-- The y translation for keyguard indication text animation for rotating text in/out -->
<dimen name="keyguard_indication_y_translation">24dp</dimen>
<!-- The padding on the bottom of the notifications on the keyguard -->
<dimen name="keyguard_indication_bottom_padding">12sp</dimen>
@@ -1157,7 +1160,7 @@
<dimen name="logout_button_layout_height">32dp</dimen>
<dimen name="logout_button_padding_horizontal">16dp</dimen>
<dimen name="logout_button_margin_bottom">12dp</dimen>
<dimen name="logout_button_corner_radius">2dp</dimen>
<dimen name="logout_button_corner_radius">4dp</dimen>
<!-- Blur radius on status bar window and power menu -->
<dimen name="min_window_blur_radius">1px</dimen>

View File

@@ -56,8 +56,10 @@ public class KeyguardStatusView extends GridLayout {
private final IActivityManager mIActivityManager;
private TextView mLogoutView;
private boolean mCanShowLogout = true; // by default, try to show the logout button here
private KeyguardClockSwitch mClockView;
private TextView mOwnerInfo;
private boolean mCanShowOwnerInfo = true; // by default, try to show the owner information here
private KeyguardSliceView mKeyguardSlice;
private View mNotificationIcons;
private Runnable mPendingMarqueeStart;
@@ -114,6 +116,25 @@ public class KeyguardStatusView extends GridLayout {
if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled);
}
void setCanShowOwnerInfo(boolean canShowOwnerInfo) {
mCanShowOwnerInfo = canShowOwnerInfo;
mOwnerInfo = findViewById(R.id.owner_info);
if (mOwnerInfo != null) {
if (mCanShowOwnerInfo) {
mOwnerInfo.setVisibility(VISIBLE);
updateOwnerInfo();
} else {
mOwnerInfo.setVisibility(GONE);
mOwnerInfo = null;
}
}
}
void setCanShowLogout(boolean canShowLogout) {
mCanShowLogout = canShowLogout;
updateLogoutView();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -128,7 +149,10 @@ public class KeyguardStatusView extends GridLayout {
if (KeyguardClockAccessibilityDelegate.isNeeded(mContext)) {
mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
}
mOwnerInfo = findViewById(R.id.owner_info);
if (mCanShowOwnerInfo) {
mOwnerInfo = findViewById(R.id.owner_info);
}
mKeyguardSlice = findViewById(R.id.keyguard_status_area);
mTextColor = mClockView.getCurrentTextColor();
@@ -189,7 +213,7 @@ public class KeyguardStatusView extends GridLayout {
if (mLogoutView == null) {
return;
}
mLogoutView.setVisibility(shouldShowLogout() ? VISIBLE : GONE);
mLogoutView.setVisibility(mCanShowLogout && shouldShowLogout() ? VISIBLE : GONE);
// Logout button will stay in language of user 0 if we don't set that manually.
mLogoutView.setText(mContext.getResources().getString(
com.android.internal.R.string.global_action_logout));

View File

@@ -134,7 +134,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
/**
* Get the height of the logout button.
* Get the height of the owner information view.
*/
public int getOwnerInfoHeight() {
return mView.getOwnerInfoHeight();
@@ -335,9 +335,13 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
// of the top of the view
mKeyguardSliceViewController.updateTopMargin(
mKeyguardClockSwitchController.getClockTextTopPadding());
mView.setCanShowOwnerInfo(false);
mView.setCanShowLogout(false);
} else {
// reset margin
mKeyguardSliceViewController.updateTopMargin(0);
mView.setCanShowOwnerInfo(true);
mView.setCanShowLogout(false);
}
updateAodIcons();
}

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2021 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.keyguard;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.view.View;
/**
* Data class containing display information (message, icon, styling) for indication to show at
* the bottom of the keyguard.
*
* See {@link com.android.systemui.statusbar.phone.KeyguardBottomAreaView}.
*/
public class KeyguardIndication {
@NonNull
private final CharSequence mMessage;
@NonNull
private final ColorStateList mTextColor;
@Nullable
private final Drawable mIcon;
@Nullable
private final View.OnClickListener mOnClickListener;
@Nullable
private final Drawable mBackground;
private KeyguardIndication(
CharSequence message,
ColorStateList textColor,
Drawable icon,
View.OnClickListener onClickListener,
Drawable background) {
mMessage = message;
mTextColor = textColor;
mIcon = icon;
mOnClickListener = onClickListener;
mBackground = background;
}
/**
* Message to display
*/
public @NonNull CharSequence getMessage() {
return mMessage;
}
/**
* TextColor to display the message.
*/
public @NonNull ColorStateList getTextColor() {
return mTextColor;
}
/**
* Icon to display.
*/
public @Nullable Drawable getIcon() {
return mIcon;
}
/**
* Click listener for messsage.
*/
public @Nullable View.OnClickListener getClickListener() {
return mOnClickListener;
}
/**
* Background for textView.
*/
public @Nullable Drawable getBackground() {
return mBackground;
}
/**
* KeyguardIndication Builder
*/
public static class Builder {
private CharSequence mMessage;
private Drawable mIcon;
private View.OnClickListener mOnClickListener;
private ColorStateList mTextColor;
private Drawable mBackground;
public Builder() { }
/**
* Required field. Message to display.
*/
public Builder setMessage(@NonNull CharSequence message) {
this.mMessage = message;
return this;
}
/**
* Required field. Text color to use to display the message.
*/
public Builder setTextColor(@NonNull ColorStateList textColor) {
this.mTextColor = textColor;
return this;
}
/**
* Optional. Icon to show next to the text. Icon location changes based on language
* display direction. For LTR, icon shows to the left of the message. For RTL, icon shows
* to the right of the message.
*/
public Builder setIcon(Drawable icon) {
this.mIcon = icon;
return this;
}
/**
* Optional. Set a click listener on the message.
*/
public Builder setClickListener(View.OnClickListener onClickListener) {
this.mOnClickListener = onClickListener;
return this;
}
/**
* Optional. Set a custom background on the TextView.
*/
public Builder setBackground(Drawable background) {
this.mBackground = background;
return this;
}
/**
* Build the KeyguardIndication.
*/
public KeyguardIndication build() {
if (mMessage == null) throw new IllegalStateException("message must be set");
if (mTextColor == null) throw new IllegalStateException("text color must be set");
return new KeyguardIndication(
mMessage, mTextColor, mIcon, mOnClickListener, mBackground);
}
}
}

View File

@@ -0,0 +1,326 @@
/*
* Copyright (C) 2021 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.keyguard;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.IntDef;
import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Rotates through messages to show on the keyguard bottom area on the lock screen
* NOTE: This controller should not be used on AoD to avoid waking up the AP too often.
*/
public class KeyguardIndicationRotateTextViewController extends
ViewController<KeyguardIndicationTextView> implements Dumpable {
public static String TAG = "KgIndicationRotatingCtrl";
private static final long DEFAULT_INDICATION_SHOW_LENGTH = 3500; // milliseconds
private final StatusBarStateController mStatusBarStateController;
private final float mMaxAlpha;
private final ColorStateList mInitialTextColorState;
// Stores @IndicationType => KeyguardIndication messages
private final Map<Integer, KeyguardIndication> mIndicationMessages = new HashMap<>();
// Executor that will show the next message after a delay
private final DelayableExecutor mExecutor;
@Nullable private ShowNextIndication mShowNextIndicationRunnable;
// List of indication types to show. The next indication to show is always at index 0
private final List<Integer> mIndicationQueue = new LinkedList<>();
private @IndicationType int mCurrIndicationType = INDICATION_TYPE_NONE;
private boolean mIsDozing;
public KeyguardIndicationRotateTextViewController(
KeyguardIndicationTextView view,
@Main DelayableExecutor executor,
StatusBarStateController statusBarStateController,
int lockScreenMode
) {
super(view);
mMaxAlpha = view.getAlpha();
mExecutor = executor;
mInitialTextColorState = mView != null
? mView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
mStatusBarStateController = statusBarStateController;
mView.setLockScreenMode(lockScreenMode);
init();
}
@Override
protected void onViewAttached() {
mStatusBarStateController.addCallback(mStatusBarStateListener);
}
@Override
protected void onViewDetached() {
mStatusBarStateController.removeCallback(mStatusBarStateListener);
cancelScheduledIndication();
}
/**
* Update the indication type with the given String.
* @param type of indication
* @param newIndication message to associate with this indication type
* @param showImmediately if true: shows this indication message immediately. Else, the text
* associated with this type is updated and will show when its turn in
* the IndicationQueue comes around.
*/
public void updateIndication(@IndicationType int type, KeyguardIndication newIndication,
boolean showImmediately) {
final boolean hasPreviousIndication = mIndicationMessages.get(type) != null;
final boolean hasNewIndication = newIndication != null
&& !TextUtils.isEmpty(newIndication.getMessage());
if (!hasNewIndication) {
mIndicationMessages.remove(type);
mIndicationQueue.removeIf(x -> x == type);
} else {
if (!hasPreviousIndication) {
mIndicationQueue.add(type);
}
mIndicationMessages.put(type, newIndication);
}
if (mIsDozing) {
return;
}
final boolean showNow = showImmediately
|| mCurrIndicationType == INDICATION_TYPE_NONE
|| mCurrIndicationType == type;
if (hasNewIndication) {
if (showNow) {
showIndication(type);
} else if (!isNextIndicationScheduled()) {
scheduleShowNextIndication();
}
return;
}
if (mCurrIndicationType == type
&& !hasNewIndication
&& showImmediately) {
if (mShowNextIndicationRunnable != null) {
mShowNextIndicationRunnable.runImmediately();
} else {
showIndication(INDICATION_TYPE_NONE);
}
}
}
/**
* Stop showing the following indication type.
*
* If the current indication is of this type, immediately stops showing the message.
*/
public void hideIndication(@IndicationType int type) {
updateIndication(type, null, true);
}
/**
* Show a transient message.
* Transient messages:
* - show immediately
* - will continue to be in the rotation of messages shown until hideTransient is called.
* - can be presented with an "error" color if isError is true
*/
public void showTransient(CharSequence newIndication, boolean isError) {
updateIndication(INDICATION_TYPE_TRANSIENT,
new KeyguardIndication.Builder()
.setMessage(newIndication)
.setTextColor(isError
? Utils.getColorError(getContext())
: mInitialTextColorState)
.build(),
/* showImmediately */true);
}
/**
* Hide a transient message immediately.
*/
public void hideTransient() {
hideIndication(INDICATION_TYPE_TRANSIENT);
}
/**
* @return true if there are available indications to show
*/
public boolean hasIndications() {
return mIndicationMessages.keySet().size() > 0;
}
/**
* Immediately show the passed indication type and schedule the next indication to show.
* Will re-add this indication to be re-shown after all other indications have been
* rotated through.
*/
private void showIndication(@IndicationType int type) {
cancelScheduledIndication();
mCurrIndicationType = type;
mIndicationQueue.removeIf(x -> x == type);
if (mCurrIndicationType == INDICATION_TYPE_NONE) {
mView.setVisibility(View.GONE);
} else {
mView.setVisibility(View.VISIBLE);
mIndicationQueue.add(type); // re-add to show later
}
// pass the style update to be run right before our new indication is shown:
mView.switchIndication(mIndicationMessages.get(type));
// only schedule next indication if there's more than just this indication in the queue
if (mCurrIndicationType != INDICATION_TYPE_NONE && mIndicationQueue.size() > 1) {
scheduleShowNextIndication();
}
}
protected boolean isNextIndicationScheduled() {
return mShowNextIndicationRunnable != null;
}
private void scheduleShowNextIndication() {
cancelScheduledIndication();
mShowNextIndicationRunnable = new ShowNextIndication(DEFAULT_INDICATION_SHOW_LENGTH);
}
private void cancelScheduledIndication() {
if (mShowNextIndicationRunnable != null) {
mShowNextIndicationRunnable.cancelDelayedExecution();
mShowNextIndicationRunnable = null;
}
}
private StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
public void onDozeAmountChanged(float linear, float eased) {
mView.setAlpha((1 - linear) * mMaxAlpha);
}
@Override
public void onDozingChanged(boolean isDozing) {
if (isDozing == mIsDozing) return;
mIsDozing = isDozing;
if (mIsDozing) {
showIndication(INDICATION_TYPE_NONE);
} else if (mIndicationQueue.size() > 0) {
showIndication(mIndicationQueue.remove(0));
}
}
};
/**
* Shows the next indication in the IndicationQueue after an optional delay.
* This wrapper has the ability to cancel itself (remove runnable from DelayableExecutor) or
* immediately run itself (which also removes itself from the DelayableExecutor).
*/
class ShowNextIndication {
private final Runnable mShowIndicationRunnable;
private Runnable mCancelDelayedRunnable;
ShowNextIndication(long delay) {
mShowIndicationRunnable = () -> {
int type = mIndicationQueue.size() == 0
? INDICATION_TYPE_NONE : mIndicationQueue.remove(0);
showIndication(type);
};
mCancelDelayedRunnable = mExecutor.executeDelayed(mShowIndicationRunnable, delay);
}
public void runImmediately() {
cancelDelayedExecution();
mShowIndicationRunnable.run();
}
public void cancelDelayedExecution() {
if (mCancelDelayedRunnable != null) {
mCancelDelayedRunnable.run();
mCancelDelayedRunnable = null;
}
}
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardIndicationRotatingTextViewController:");
pw.println(" currentMessage=" + mView.getText());
pw.println(" dozing:" + mIsDozing);
pw.println(" queue:" + mIndicationQueue.toString());
pw.println(" showNextIndicationRunnable:" + mShowNextIndicationRunnable);
if (hasIndications()) {
pw.println(" All messages:");
for (int type : mIndicationMessages.keySet()) {
pw.println(" type=" + type + " message=" + mIndicationMessages.get(type));
}
}
}
private static final int INDICATION_TYPE_NONE = -1;
public static final int INDICATION_TYPE_OWNER_INFO = 0;
public static final int INDICATION_TYPE_DISCLOSURE = 1;
public static final int INDICATION_TYPE_LOGOUT = 2;
public static final int INDICATION_TYPE_BATTERY = 3;
public static final int INDICATION_TYPE_ALIGNMENT = 4;
public static final int INDICATION_TYPE_TRANSIENT = 5;
public static final int INDICATION_TYPE_TRUST = 6;
public static final int INDICATION_TYPE_RESTING = 7;
public static final int INDICATION_TYPE_USER_LOCKED = 8;
public static final int INDICATION_TYPE_NOW_PLAYING = 9;
public static final int INDICATION_TYPE_REVERSE_CHARGING = 10;
@IntDef({
INDICATION_TYPE_NONE,
INDICATION_TYPE_DISCLOSURE,
INDICATION_TYPE_OWNER_INFO,
INDICATION_TYPE_LOGOUT,
INDICATION_TYPE_BATTERY,
INDICATION_TYPE_ALIGNMENT,
INDICATION_TYPE_TRANSIENT,
INDICATION_TYPE_TRUST,
INDICATION_TYPE_RESTING,
INDICATION_TYPE_USER_LOCKED,
INDICATION_TYPE_NOW_PLAYING,
INDICATION_TYPE_REVERSE_CHARGING,
})
@Retention(RetentionPolicy.SOURCE)
public @interface IndicationType{}
}

View File

@@ -16,10 +16,24 @@
package com.android.systemui.statusbar;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.android.keyguard.KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1;
import static com.android.systemui.DejankUtils.whitelistIpcs;
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_DISCLOSURE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_LOGOUT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_USER_LOCKED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -47,6 +61,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.ViewClippingUtil;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -56,13 +71,16 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
@@ -76,8 +94,7 @@ import javax.inject.Inject;
* Controls the indications and error messages shown on the Keyguard
*/
@SysUISingleton
public class KeyguardIndicationController implements StateListener,
KeyguardStateController.Callback {
public class KeyguardIndicationController implements KeyguardStateController.Callback {
private static final String TAG = "KeyguardIndication";
private static final boolean DEBUG_CHARGING_SPEED = false;
@@ -94,14 +111,17 @@ public class KeyguardIndicationController implements StateListener,
private final StatusBarStateController mStatusBarStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private ViewGroup mIndicationArea;
private KeyguardIndicationTextView mTextView;
private KeyguardIndicationTextView mDisclosure;
private KeyguardIndicationTextView mTopIndicationView;
private final IBatteryStats mBatteryInfo;
private final SettableWakeLock mWakeLock;
private final DockManager mDockManager;
private final DevicePolicyManager mDevicePolicyManager;
private final UserManager mUserManager;
private final @Main DelayableExecutor mExecutor;
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
protected KeyguardIndicationRotateTextViewController mRotateTextViewController;
private BroadcastReceiver mBroadcastReceiver;
private LockscreenLockIconController mLockIconController;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -110,7 +130,7 @@ public class KeyguardIndicationController implements StateListener,
private String mAlignmentIndication;
private CharSequence mTransientIndication;
private boolean mTransientTextIsError;
private ColorStateList mInitialTextColorState;
protected ColorStateList mInitialTextColorState;
private boolean mVisible;
private boolean mHideTransientMessageOnScreenOff;
@@ -124,8 +144,8 @@ public class KeyguardIndicationController implements StateListener,
private int mBatteryLevel;
private boolean mBatteryPresent = true;
private long mChargingTimeRemaining;
private float mDisclosureMaxAlpha;
private String mMessageToShowOnScreenOn;
protected int mLockScreenMode;
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -151,7 +171,8 @@ public class KeyguardIndicationController implements StateListener,
BroadcastDispatcher broadcastDispatcher,
DevicePolicyManager devicePolicyManager,
IBatteryStats iBatteryStats,
UserManager userManager) {
UserManager userManager,
@Main DelayableExecutor executor) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mDevicePolicyManager = devicePolicyManager;
@@ -165,23 +186,29 @@ public class KeyguardIndicationController implements StateListener,
wakeLockBuilder.setTag("Doze:KeyguardIndication").build(), TAG);
mBatteryInfo = iBatteryStats;
mUserManager = userManager;
mExecutor = executor;
mLockPatternUtils = new LockPatternUtils(context);
mIActivityManager = ActivityManager.getService();
mKeyguardUpdateMonitor.registerCallback(getKeyguardCallback());
mKeyguardUpdateMonitor.registerCallback(mTickReceiver);
mStatusBarStateController.addCallback(this);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mKeyguardStateController.addCallback(this);
}
public void setIndicationArea(ViewGroup indicationArea) {
mIndicationArea = indicationArea;
mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
mInitialTextColorState = mTextView != null ?
mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
mDisclosureMaxAlpha = mDisclosure.getAlpha();
mTopIndicationView = indicationArea.findViewById(R.id.keyguard_indication_text);
mInitialTextColorState = mTopIndicationView != null
? mTopIndicationView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
mRotateTextViewController = new KeyguardIndicationRotateTextViewController(
indicationArea.findViewById(R.id.keyguard_indication_text_bottom),
mExecutor,
mStatusBarStateController,
mLockScreenMode);
updateIndication(false /* animate */);
updateDisclosure();
updateOwnerInfo();
if (mBroadcastReceiver == null) {
// Update the disclosure proactively to avoid IPC on the critical path.
mBroadcastReceiver = new BroadcastReceiver() {
@@ -233,19 +260,196 @@ public class KeyguardIndicationController implements StateListener,
return mUpdateMonitorCallback;
}
/**
* Doesn't include owner information or disclosure which get triggered separately.
*/
private void updateIndications(boolean animate, int userId) {
updateBattery(animate);
updateUserLocked(userId);
updateTransient();
updateTrust(userId, getTrustGrantedIndication(), getTrustManagedIndication());
updateAlignment();
updateResting();
}
private void updateDisclosure() {
// NOTE: Because this uses IPC, avoid calling updateDisclosure() on a critical path.
if (whitelistIpcs(this::isOrganizationOwnedDevice)) {
CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
if (organizationName != null) {
mDisclosure.switchIndication(mContext.getResources().getString(
R.string.do_disclosure_with_name, organizationName));
} else {
mDisclosure.switchIndication(R.string.do_disclosure_generic);
}
mDisclosure.setVisibility(View.VISIBLE);
final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
final CharSequence disclosure = organizationName != null
? mContext.getResources().getString(R.string.do_disclosure_with_name,
organizationName)
: mContext.getResources().getText(R.string.do_disclosure_generic);
mRotateTextViewController.updateIndication(
INDICATION_TYPE_DISCLOSURE,
new KeyguardIndication.Builder()
.setMessage(disclosure)
.setTextColor(mInitialTextColorState)
.build(),
/* updateImmediately */ false);
} else {
mDisclosure.setVisibility(View.GONE);
mRotateTextViewController.hideIndication(INDICATION_TYPE_DISCLOSURE);
}
if (isKeyguardLayoutEnabled()) {
updateIndication(false); // resting indication may need to update
}
}
private void updateBattery(boolean animate) {
if (mPowerPluggedIn || mEnableBatteryDefender) {
String powerIndication = computePowerIndication();
if (DEBUG_CHARGING_SPEED) {
powerIndication += ", " + (mChargingWattage / 1000) + " mW";
}
mRotateTextViewController.updateIndication(
INDICATION_TYPE_BATTERY,
new KeyguardIndication.Builder()
.setMessage(powerIndication)
.setTextColor(mInitialTextColorState)
.build(),
animate);
} else {
// don't show the charging information if device isn't plugged in
mRotateTextViewController.hideIndication(INDICATION_TYPE_BATTERY);
}
}
private void updateUserLocked(int userId) {
if (!mKeyguardUpdateMonitor.isUserUnlocked(userId)) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_USER_LOCKED,
new KeyguardIndication.Builder()
.setMessage(mContext.getResources().getText(
com.android.internal.R.string.lockscreen_storage_locked))
.setTextColor(mInitialTextColorState)
.build(),
false);
} else {
mRotateTextViewController.hideIndication(INDICATION_TYPE_USER_LOCKED);
}
}
private void updateTransient() {
if (!TextUtils.isEmpty(mTransientIndication)) {
mRotateTextViewController.showTransient(mTransientIndication,
mTransientTextIsError);
} else {
mRotateTextViewController.hideTransient();
}
}
private void updateTrust(int userId, CharSequence trustGrantedIndication,
CharSequence trustManagedIndication) {
if (!TextUtils.isEmpty(trustGrantedIndication)
&& mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_TRUST,
new KeyguardIndication.Builder()
.setMessage(trustGrantedIndication)
.setTextColor(mInitialTextColorState)
.build(),
false);
} else if (!TextUtils.isEmpty(trustManagedIndication)
&& mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
&& !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_TRUST,
new KeyguardIndication.Builder()
.setMessage(trustManagedIndication)
.setTextColor(mInitialTextColorState)
.build(),
false);
} else {
mRotateTextViewController.hideIndication(INDICATION_TYPE_TRUST);
}
}
private void updateAlignment() {
if (!TextUtils.isEmpty(mAlignmentIndication)) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_ALIGNMENT,
new KeyguardIndication.Builder()
.setMessage(mAlignmentIndication)
.setTextColor(Utils.getColorError(mContext))
.build(),
true);
} else {
mRotateTextViewController.hideIndication(INDICATION_TYPE_ALIGNMENT);
}
}
private void updateResting() {
if (mRestingIndication != null
&& !mRotateTextViewController.hasIndications()) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_RESTING,
new KeyguardIndication.Builder()
.setMessage(mRestingIndication)
.setTextColor(mInitialTextColorState)
.build(),
false);
} else {
mRotateTextViewController.hideIndication(INDICATION_TYPE_RESTING);
}
}
protected boolean isKeyguardLayoutEnabled() {
return mLockScreenMode == LOCK_SCREEN_MODE_LAYOUT_1;
}
private void updateLogoutView() {
if (!isKeyguardLayoutEnabled()) {
return;
}
final boolean shouldShowLogout = mKeyguardUpdateMonitor.isLogoutEnabled()
&& KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM;
String logoutString = shouldShowLogout ? mContext.getResources().getString(
com.android.internal.R.string.global_action_logout) : null;
mRotateTextViewController.updateIndication(
INDICATION_TYPE_LOGOUT,
new KeyguardIndication.Builder()
.setMessage(logoutString)
.setTextColor(mInitialTextColorState)
.setBackground(mContext.getDrawable(
com.android.systemui.R.drawable.logout_button_background))
.setClickListener((view) -> {
int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
try {
mIActivityManager.switchUser(UserHandle.USER_SYSTEM);
mIActivityManager.stopUser(currentUserId, true /* force */, null);
} catch (RemoteException re) {
Log.e(TAG, "Failed to logout user", re);
}
})
.build(),
false);
updateIndication(false); // resting indication may need to update
}
private void updateOwnerInfo() {
if (!isKeyguardLayoutEnabled()) {
return;
}
String info = mLockPatternUtils.getDeviceOwnerInfo();
if (info == null) {
// Use the current user owner information if enabled.
final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
KeyguardUpdateMonitor.getCurrentUser());
if (ownerInfoEnabled) {
info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
}
}
if (info != null) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_OWNER_INFO,
new KeyguardIndication.Builder()
.setMessage(info)
.setTextColor(mInitialTextColorState)
.build(),
false);
} else {
updateIndication(false); // resting indication may need to update
}
}
@@ -281,9 +485,10 @@ public class KeyguardIndicationController implements StateListener,
return UserHandle.USER_NULL;
}
public void setVisible(boolean visible) {
@VisibleForTesting
protected void setVisible(boolean visible) {
mVisible = visible;
mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
mIndicationArea.setVisibility(visible ? VISIBLE : GONE);
if (visible) {
// If this is called after an error message was already shown, we should not clear it.
// Otherwise the error message won't be shown
@@ -382,6 +587,7 @@ public class KeyguardIndicationController implements StateListener,
mTransientIndication = null;
mHideTransientMessageOnScreenOff = false;
mHandler.removeMessages(MSG_HIDE_TRANSIENT);
mRotateTextViewController.hideTransient();
updateIndication(false);
}
}
@@ -396,98 +602,109 @@ public class KeyguardIndicationController implements StateListener,
}
// A few places might need to hide the indication, so always start by making it visible
mIndicationArea.setVisibility(View.VISIBLE);
mIndicationArea.setVisibility(VISIBLE);
// Walk down a precedence-ordered list of what indication
// should be shown based on user or device state
// AoD
if (mDozing) {
mTopIndicationView.setVisibility(VISIBLE);
// When dozing we ignore any text color and use white instead, because
// colors can be hard to read in low brightness.
mTextView.setTextColor(Color.WHITE);
mTopIndicationView.setTextColor(Color.WHITE);
if (!TextUtils.isEmpty(mTransientIndication)) {
mTextView.switchIndication(mTransientIndication);
mTopIndicationView.switchIndication(mTransientIndication, null);
} else if (!mBatteryPresent) {
// If there is no battery detected, hide the indication and bail
mIndicationArea.setVisibility(View.GONE);
mIndicationArea.setVisibility(GONE);
} else if (!TextUtils.isEmpty(mAlignmentIndication)) {
mTextView.switchIndication(mAlignmentIndication);
mTextView.setTextColor(mContext.getColor(R.color.misalignment_text_color));
mTopIndicationView.switchIndication(mAlignmentIndication, null);
mTopIndicationView.setTextColor(mContext.getColor(R.color.misalignment_text_color));
} else if (mPowerPluggedIn || mEnableBatteryDefender) {
String indication = computePowerIndication();
if (animate) {
animateText(mTextView, indication);
animateText(mTopIndicationView, indication);
} else {
mTextView.switchIndication(indication);
mTopIndicationView.switchIndication(indication, null);
}
} else {
String percentage = NumberFormat.getPercentInstance()
.format(mBatteryLevel / 100f);
mTextView.switchIndication(percentage);
mTopIndicationView.switchIndication(percentage, null);
}
return;
}
int userId = KeyguardUpdateMonitor.getCurrentUser();
String trustGrantedIndication = getTrustGrantedIndication();
String trustManagedIndication = getTrustManagedIndication();
String powerIndication = null;
if (mPowerPluggedIn || mEnableBatteryDefender) {
powerIndication = computePowerIndication();
}
// LOCK SCREEN
// Some cases here might need to hide the indication (if the battery is not present)
boolean hideIndication = false;
boolean isError = false;
if (!mKeyguardUpdateMonitor.isUserUnlocked(userId)) {
mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
} else if (!TextUtils.isEmpty(mTransientIndication)) {
if (powerIndication != null && !mTransientIndication.equals(powerIndication)) {
String indication = mContext.getResources().getString(
R.string.keyguard_indication_trust_unlocked_plugged_in,
mTransientIndication, powerIndication);
mTextView.switchIndication(indication);
hideIndication = !mBatteryPresent;
} else {
mTextView.switchIndication(mTransientIndication);
}
isError = mTransientTextIsError;
} else if (!TextUtils.isEmpty(trustGrantedIndication)
&& mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
if (powerIndication != null) {
String indication = mContext.getResources().getString(
R.string.keyguard_indication_trust_unlocked_plugged_in,
trustGrantedIndication, powerIndication);
mTextView.switchIndication(indication);
hideIndication = !mBatteryPresent;
} else {
mTextView.switchIndication(trustGrantedIndication);
}
} else if (!TextUtils.isEmpty(mAlignmentIndication)) {
mTextView.switchIndication(mAlignmentIndication);
isError = true;
hideIndication = !mBatteryPresent;
} else if (mPowerPluggedIn || mEnableBatteryDefender) {
if (DEBUG_CHARGING_SPEED) {
powerIndication += ", " + (mChargingWattage / 1000) + " mW";
}
if (animate) {
animateText(mTextView, powerIndication);
} else {
mTextView.switchIndication(powerIndication);
}
hideIndication = !mBatteryPresent;
} else if (!TextUtils.isEmpty(trustManagedIndication)
&& mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
&& !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
mTextView.switchIndication(trustManagedIndication);
int userId = KeyguardUpdateMonitor.getCurrentUser();
if (mLockScreenMode == LOCK_SCREEN_MODE_LAYOUT_1) {
mTopIndicationView.setVisibility(GONE);
updateIndications(animate, userId);
} else {
mTextView.switchIndication(mRestingIndication);
}
mTextView.setTextColor(isError ? Utils.getColorError(mContext)
: mInitialTextColorState);
if (hideIndication) {
mIndicationArea.setVisibility(View.GONE);
boolean hideIndication = false;
boolean isError = false;
String trustGrantedIndication = getTrustGrantedIndication();
String trustManagedIndication = getTrustManagedIndication();
String powerIndication = null;
if (mPowerPluggedIn || mEnableBatteryDefender) {
powerIndication = computePowerIndication();
}
if (!mKeyguardUpdateMonitor.isUserUnlocked(userId)) {
mTopIndicationView.switchIndication(
com.android.internal.R.string.lockscreen_storage_locked);
} else if (!TextUtils.isEmpty(mTransientIndication)) {
if (powerIndication != null && !mTransientIndication.equals(powerIndication)) {
String indication = mContext.getResources().getString(
R.string.keyguard_indication_trust_unlocked_plugged_in,
mTransientIndication, powerIndication);
mTopIndicationView.switchIndication(indication, null);
hideIndication = !mBatteryPresent;
} else {
mTopIndicationView.switchIndication(mTransientIndication, null);
}
isError = mTransientTextIsError;
} else if (!TextUtils.isEmpty(trustGrantedIndication)
&& mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
if (powerIndication != null) {
String indication = mContext.getResources().getString(
R.string.keyguard_indication_trust_unlocked_plugged_in,
trustGrantedIndication, powerIndication);
mTopIndicationView.switchIndication(indication, null);
hideIndication = !mBatteryPresent;
} else {
mTopIndicationView.switchIndication(trustGrantedIndication, null);
}
} else if (!TextUtils.isEmpty(mAlignmentIndication)) {
mTopIndicationView.switchIndication(mAlignmentIndication, null);
isError = true;
hideIndication = !mBatteryPresent;
} else if (mPowerPluggedIn || mEnableBatteryDefender) {
if (DEBUG_CHARGING_SPEED) {
powerIndication += ", " + (mChargingWattage / 1000) + " mW";
}
if (animate) {
animateText(mTopIndicationView, powerIndication);
} else {
mTopIndicationView.switchIndication(powerIndication, null);
}
hideIndication = !mBatteryPresent;
} else if (!TextUtils.isEmpty(trustManagedIndication)
&& mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
&& !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
mTopIndicationView.switchIndication(trustManagedIndication, null);
} else {
mTopIndicationView.switchIndication(mRestingIndication, null);
}
mTopIndicationView.setTextColor(
isError ? Utils.getColorError(mContext) : mInitialTextColorState);
if (hideIndication) {
mIndicationArea.setVisibility(GONE);
}
}
}
@@ -510,7 +727,7 @@ public class KeyguardIndicationController implements StateListener,
@Override
public void onAnimationStart(Animator animation) {
textView.switchIndication(indication);
textView.switchIndication(indication, null);
}
@Override
@@ -634,18 +851,6 @@ public class KeyguardIndicationController implements StateListener,
}
}
public void setDozing(boolean dozing) {
if (mDozing == dozing) {
return;
}
mDozing = dozing;
if (mHideTransientMessageOnScreenOff && mDozing) {
hideTransientIndication();
} else {
updateIndication(false);
}
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardIndicationController:");
pw.println(" mTransientTextIsError: " + mTransientTextIsError);
@@ -659,23 +864,10 @@ public class KeyguardIndicationController implements StateListener,
pw.println(" mDozing: " + mDozing);
pw.println(" mBatteryLevel: " + mBatteryLevel);
pw.println(" mBatteryPresent: " + mBatteryPresent);
pw.println(" mTextView.getText(): " + (mTextView == null ? null : mTextView.getText()));
pw.println(" mTextView.getText(): " + (
mTopIndicationView == null ? null : mTopIndicationView.getText()));
pw.println(" computePowerIndication(): " + computePowerIndication());
}
@Override
public void onStateChanged(int newState) {
// don't care
}
@Override
public void onDozingChanged(boolean isDozing) {
setDozing(isDozing);
}
@Override
public void onDozeAmountChanged(float linear, float eased) {
mDisclosure.setAlpha((1 - linear) * mDisclosureMaxAlpha);
mRotateTextViewController.dump(fd, pw, args);
}
@Override
@@ -686,6 +878,11 @@ public class KeyguardIndicationController implements StateListener,
protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
public static final int HIDE_DELAY_MS = 5000;
@Override
public void onLockScreenModeChanged(int mode) {
mLockScreenMode = mode;
}
@Override
public void onRefreshBatteryInfo(BatteryStatus status) {
boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
@@ -845,6 +1042,7 @@ public class KeyguardIndicationController implements StateListener,
@Override
public void onUserSwitchComplete(int userId) {
if (mVisible) {
updateOwnerInfo();
updateIndication(false);
}
}
@@ -856,12 +1054,40 @@ public class KeyguardIndicationController implements StateListener,
}
}
@Override
public void onLogoutEnabledChanged() {
if (mVisible) {
updateLogoutView();
}
}
@Override
public void onRequireUnlockForNfc() {
showTransientIndication(mContext.getString(R.string.require_unlock_for_nfc),
false /* isError */, false /* hideOnScreenOff */);
hideTransientIndicationDelayed(HIDE_DELAY_MS);
}
}
private StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
public void onStateChanged(int newState) {
setVisible(newState == StatusBarState.KEYGUARD);
}
@Override
public void onDozingChanged(boolean dozing) {
if (mDozing == dozing) {
return;
}
mDozing = dozing;
if (mHideTransientMessageOnScreenOff && mDozing) {
hideTransientIndication();
} else {
updateIndication(false);
}
}
};
}

View File

@@ -131,8 +131,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private KeyguardAffordanceView mLeftAffordanceView;
private ImageView mAltLeftButton;
private ViewGroup mIndicationArea;
private TextView mEnterpriseDisclosure;
private TextView mIndicationText;
private TextView mIndicationTextBottom;
private ViewGroup mPreviewContainer;
private ViewGroup mOverlayContainer;
@@ -251,9 +251,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mLeftAffordanceView = findViewById(R.id.left_button);
mAltLeftButton = findViewById(R.id.alt_left_button);
mIndicationArea = findViewById(R.id.keyguard_indication_area);
mEnterpriseDisclosure = findViewById(
R.id.keyguard_indication_enterprise_disclosure);
mIndicationText = findViewById(R.id.keyguard_indication_text);
mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
mIndicationBottomMargin = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_margin_bottom);
mBurnInYOffset = getResources().getDimensionPixelSize(
@@ -330,7 +329,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
// Respect font size setting.
mEnterpriseDisclosure.setTextSize(TypedValue.COMPLEX_UNIT_PX,
mIndicationTextBottom.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(
com.android.internal.R.dimen.text_size_small_material));
mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,

View File

@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.phone;
import static com.android.keyguard.KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
@@ -28,6 +32,7 @@ import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Interpolators;
import com.android.systemui.keyguard.KeyguardIndication;
import java.util.LinkedList;
@@ -35,13 +40,15 @@ import java.util.LinkedList;
* A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open").
*/
public class KeyguardIndicationTextView extends TextView {
private static final int FADE_OUT_MILLIS = 200;
private static final int FADE_IN_MILLIS = 250;
private static final long MSG_DURATION_MILLIS = 600;
private long mNextAnimationTime = 0;
private boolean mAnimationsEnabled = true;
private LinkedList<CharSequence> mMessages = new LinkedList<>();
private LinkedList<KeyguardIndication> mKeyguardIndicationInfo = new LinkedList<>();
private boolean mUseNewAnimations = false;
public KeyguardIndicationTextView(Context context) {
super(context);
@@ -60,12 +67,33 @@ public class KeyguardIndicationTextView extends TextView {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setLockScreenMode(int lockScreenMode) {
mUseNewAnimations = lockScreenMode == LOCK_SCREEN_MODE_LAYOUT_1;
}
/**
* Changes the text with an animation and makes sure a single indication is shown long enough.
*/
public void switchIndication(int textResId) {
switchIndication(getResources().getText(textResId), null);
}
/**
* Changes the text with an animation and makes sure a single indication is shown long enough.
*
* @param indication The text to show.
*/
public void switchIndication(KeyguardIndication indication) {
switchIndication(indication == null ? null : indication.getMessage(), indication);
}
/**
* Changes the text with an animation and makes sure a single indication is shown long enough.
*
* @param text The text to show.
* @param indication optional display information for the text
*/
public void switchIndication(CharSequence text) {
public void switchIndication(CharSequence text, KeyguardIndication indication) {
if (text == null) text = "";
CharSequence lastPendingMessage = mMessages.peekLast();
@@ -74,55 +102,119 @@ public class KeyguardIndicationTextView extends TextView {
return;
}
mMessages.add(text);
mKeyguardIndicationInfo.add(indication);
Animator fadeOut = ObjectAnimator.ofFloat(this, View.ALPHA, 0f);
fadeOut.setDuration(getFadeOutMillis());
fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
final CharSequence nextText = text;
fadeOut.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animator) {
setText(mMessages.poll());
}
});
final boolean hasIcon = indication != null && indication.getIcon() != null;
final AnimatorSet animSet = new AnimatorSet();
final AnimatorSet.Builder animSetBuilder = animSet.play(fadeOut);
final AnimatorSet.Builder animSetBuilder = animSet.play(getOutAnimator());
// Make sure each animation is visible for a minimum amount of time, while not worrying
// about fading in blank text
long timeInMillis = System.currentTimeMillis();
long delay = Math.max(0, mNextAnimationTime - timeInMillis);
setNextAnimationTime(timeInMillis + delay + getFadeOutMillis());
setNextAnimationTime(timeInMillis + delay + getFadeOutDuration());
if (!text.equals("")) {
if (!text.equals("") || hasIcon) {
setNextAnimationTime(mNextAnimationTime + MSG_DURATION_MILLIS);
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(this, View.ALPHA, 1f);
fadeIn.setDuration(getFadeInMillis());
fadeIn.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
animSetBuilder.before(fadeIn);
animSetBuilder.before(getInAnimator());
}
animSet.setStartDelay(delay);
animSet.start();
}
private AnimatorSet getOutAnimator() {
AnimatorSet animatorSet = new AnimatorSet();
Animator fadeOut = ObjectAnimator.ofFloat(this, View.ALPHA, 0f);
fadeOut.setDuration(getFadeOutDuration());
fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
fadeOut.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
KeyguardIndication info = mKeyguardIndicationInfo.poll();
if (info != null) {
setTextColor(info.getTextColor());
setOnClickListener(info.getClickListener());
final Drawable icon = info.getIcon();
if (icon != null) {
icon.setTint(getCurrentTextColor());
if (icon instanceof AnimatedVectorDrawable) {
((AnimatedVectorDrawable) icon).start();
}
}
setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null);
}
setText(mMessages.poll());
}
});
if (mUseNewAnimations) {
Animator yTranslate =
ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -getYTranslationPixels());
yTranslate.setDuration(getFadeOutDuration());
fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
animatorSet.playTogether(fadeOut, yTranslate);
} else {
animatorSet.play(fadeOut);
}
return animatorSet;
}
private AnimatorSet getInAnimator() {
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(this, View.ALPHA, 1f);
fadeIn.setStartDelay(getFadeInDelay());
fadeIn.setDuration(getFadeInDuration());
fadeIn.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
if (mUseNewAnimations) {
Animator yTranslate =
ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, getYTranslationPixels(), 0);
yTranslate.setDuration(getYInDuration());
yTranslate.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
setTranslationY(0);
}
});
animatorSet.playTogether(yTranslate, fadeIn);
} else {
animatorSet.play(fadeIn);
}
return animatorSet;
}
@VisibleForTesting
public void setAnimationsEnabled(boolean enabled) {
mAnimationsEnabled = enabled;
}
private long getFadeInMillis() {
if (mAnimationsEnabled) return FADE_IN_MILLIS;
private long getFadeInDelay() {
if (!mAnimationsEnabled) return 0L;
if (mUseNewAnimations) return 150L;
return 0L;
}
private long getFadeOutMillis() {
if (mAnimationsEnabled) return FADE_OUT_MILLIS;
private long getFadeInDuration() {
if (!mAnimationsEnabled) return 0L;
if (mUseNewAnimations) return 317L;
return FADE_IN_MILLIS;
}
private long getYInDuration() {
if (!mAnimationsEnabled) return 0L;
if (mUseNewAnimations) return 600L;
return 0L;
}
private long getFadeOutDuration() {
if (!mAnimationsEnabled) return 0L;
if (mUseNewAnimations) return 167L;
return FADE_OUT_MILLIS;
}
private void setNextAnimationTime(long time) {
if (mAnimationsEnabled) {
mNextAnimationTime = time;
@@ -131,10 +223,8 @@ public class KeyguardIndicationTextView extends TextView {
}
}
/**
* See {@link #switchIndication}.
*/
public void switchIndication(int textResId) {
switchIndication(getResources().getText(textResId));
private int getYTranslationPixels() {
return mContext.getResources().getDimensionPixelSize(
com.android.systemui.R.dimen.keyguard_indication_y_translation);
}
}

View File

@@ -1146,8 +1146,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mLockscreenWallpaper = mLockscreenWallpaperLazy.get();
}
mKeyguardIndicationController.setIndicationArea(
mNotificationShadeWindowView.findViewById(R.id.keyguard_indication_area));
mNotificationPanelViewController.setKeyguardIndicationController(
mKeyguardIndicationController);
@@ -3625,26 +3623,19 @@ public class StatusBar extends SystemUI implements DemoMode,
mNavigationBarController.touchAutoDim(mDisplayId);
Trace.beginSection("StatusBar#updateKeyguardState");
if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationController.setVisible(true);
if (mKeyguardUserSwitcher != null) {
mKeyguardUserSwitcher.setKeyguard(true,
mStatusBarStateController.fromShadeLocked());
}
if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables();
if (mAmbientIndicationContainer != null) {
mAmbientIndicationContainer.setVisibility(View.VISIBLE);
}
} else {
mKeyguardIndicationController.setVisible(false);
if (mKeyguardUserSwitcher != null) {
mKeyguardUserSwitcher.setKeyguard(false,
mStatusBarStateController.goingToFullShade() ||
mState == StatusBarState.SHADE_LOCKED ||
mStatusBarStateController.fromShadeLocked());
}
if (mAmbientIndicationContainer != null) {
mAmbientIndicationContainer.setVisibility(View.INVISIBLE);
}
}
updateDozingState();
checkBarModes();

View File

@@ -0,0 +1,304 @@
/*
* Copyright (C) 2021 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.keyguard;
import static com.android.keyguard.KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.util.concurrency.DelayableExecutor;
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;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCase {
private static final String TEST_MESSAGE = "test message";
private static final String TEST_MESSAGE_2 = "test message 2";
@Mock
private DelayableExecutor mExecutor;
@Mock
private KeyguardIndicationTextView mView;
@Mock
private StatusBarStateController mStatusBarStateController;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
private KeyguardIndicationRotateTextViewController mController;
private StatusBarStateController.StateListener mStatusBarStateListener;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mView.getTextColors()).thenReturn(ColorStateList.valueOf(Color.WHITE));
mController = new KeyguardIndicationRotateTextViewController(mView, mExecutor,
mStatusBarStateController, LOCK_SCREEN_MODE_LAYOUT_1);
mController.onViewAttached();
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
}
@Test
public void testInitialState_noIndication() {
assertFalse(mController.hasIndications());
}
@Test
public void testShowOneIndication() {
// WHEN we add our first indication
final KeyguardIndication indication = createIndication();
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, indication, false);
// THEN
// - we see controller has an indication
// - the indication shows immediately since it's the only one
// - no next indication is scheduled since there's only one indication
assertTrue(mController.hasIndications());
verify(mView).switchIndication(indication);
verify(mExecutor, never()).executeDelayed(any(), anyLong());
}
@Test
public void testShowTwoRotatingMessages() {
// GIVEN we already have an indication message
mController.updateIndication(
INDICATION_TYPE_OWNER_INFO, createIndication(), false);
reset(mView);
// WHEN we have a new indication type to display
final KeyguardIndication indication2 = createIndication();
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, indication2, false);
// THEN
// - we don't immediately see the new message until the delay
// - next indication is scheduled
verify(mView, never()).switchIndication(indication2);
verify(mExecutor).executeDelayed(any(), anyLong());
}
@Test
public void testUpdateCurrentMessage() {
// GIVEN we already have an indication message
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, createIndication(), false);
reset(mView);
// WHEN we have a new message for this indication type to display
final KeyguardIndication indication2 = createIndication();
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, indication2, false);
// THEN
// - new indication is updated immediately
// - we don't schedule to show anything later
verify(mView).switchIndication(indication2);
verify(mExecutor, never()).executeDelayed(any(), anyLong());
}
@Test
public void testUpdateRotatingMessageForUndisplayedIndication() {
// GIVEN we already have two indication messages
mController.updateIndication(
INDICATION_TYPE_OWNER_INFO, createIndication(), false);
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, createIndication(), false);
reset(mView);
reset(mExecutor);
// WHEN we have a new message for an undisplayed indication type
final KeyguardIndication indication3 = createIndication();
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, indication3, false);
// THEN
// - we don't immediately update
// - we don't schedule to show anything new
verify(mView, never()).switchIndication(indication3);
verify(mExecutor, never()).executeDelayed(any(), anyLong());
}
@Test
public void testUpdateImmediately() {
// GIVEN we already have three indication messages
mController.updateIndication(
INDICATION_TYPE_OWNER_INFO, createIndication(), false);
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, createIndication(), false);
mController.updateIndication(
INDICATION_TYPE_BATTERY, createIndication(), false);
reset(mView);
reset(mExecutor);
// WHEN we have a new message for a currently shown type that we want to show immediately
final KeyguardIndication indication4 = createIndication();
mController.updateIndication(
INDICATION_TYPE_BATTERY, indication4, true);
// THEN
// - we immediately update
// - we schedule a new delayable to show the next message later
verify(mView).switchIndication(indication4);
verify(mExecutor).executeDelayed(any(), anyLong());
// WHEN an already existing type is updated to show immediately
reset(mView);
reset(mExecutor);
final KeyguardIndication indication5 = createIndication();
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, indication5, true);
// THEN
// - we immediately update
// - we schedule a new delayable to show the next message later
verify(mView).switchIndication(indication5);
verify(mExecutor).executeDelayed(any(), anyLong());
}
@Test
public void testTransientIndication() {
// GIVEN we already have two indication messages
mController.updateIndication(
INDICATION_TYPE_OWNER_INFO, createIndication(), false);
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, createIndication(), false);
reset(mView);
reset(mExecutor);
// WHEN we have a transient message
mController.showTransient(TEST_MESSAGE_2, false);
// THEN
// - we immediately update
// - we schedule a new delayable to show the next message later
verify(mView).switchIndication(any(KeyguardIndication.class));
verify(mExecutor).executeDelayed(any(), anyLong());
}
@Test
public void testHideIndicationOneMessage() {
// GIVEN we have one indication message
mController.updateIndication(
INDICATION_TYPE_OWNER_INFO, createIndication(), false);
// WHEN we hide the current indication type
mController.hideIndication(INDICATION_TYPE_OWNER_INFO);
// THEN we immediately update the text to show no text
verify(mView).switchIndication(null);
}
@Test
public void testHideIndicationTwoMessages() {
// GIVEN we have two indication messages
final KeyguardIndication indication1 = createIndication();
final KeyguardIndication indication2 = createIndication();
mController.updateIndication(
INDICATION_TYPE_OWNER_INFO, indication1, false);
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, indication2, false);
assertTrue(mController.isNextIndicationScheduled());
// WHEN we hide the current indication type
mController.hideIndication(INDICATION_TYPE_OWNER_INFO);
// THEN we show the next indication and there's no scheduled next indication
verify(mView).switchIndication(indication2);
assertFalse(mController.isNextIndicationScheduled());
}
@Test
public void testStartDozing() {
// WHEN the device is dozing
mStatusBarStateListener.onDozingChanged(true);
// THEN the view is GONE
verify(mView).setVisibility(View.GONE);
}
@Test
public void testStoppedDozing() {
// GIVEN we're dozing & we have an indication message
mStatusBarStateListener.onDozingChanged(true);
final KeyguardIndication indication = createIndication();
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, indication, false);
reset(mView);
reset(mExecutor);
// WHEN the device is no longer dozing
mStatusBarStateListener.onDozingChanged(false);
// THEN show the next message
verify(mView).switchIndication(indication);
}
@Test
public void testIsDozing() {
// GIVEN the device is dozing
mStatusBarStateListener.onDozingChanged(true);
reset(mView);
// WHEN an indication is updated
final KeyguardIndication indication = createIndication();
mController.updateIndication(
INDICATION_TYPE_DISCLOSURE, indication, false);
// THEN no message is shown since we're dozing
verify(mView, never()).switchIndication(any());
}
private KeyguardIndication createIndication() {
return new KeyguardIndication.Builder()
.setMessage(TEST_MESSAGE)
.setTextColor(ColorStateList.valueOf(Color.WHITE))
.build();
}
}

View File

@@ -18,6 +18,8 @@ package com.android.systemui.statusbar;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
@@ -27,13 +29,11 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
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.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.Instrumentation;
@@ -51,7 +51,6 @@ import android.os.BatteryManager;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserManager;
import android.view.View;
import android.view.ViewGroup;
import androidx.test.InstrumentationRegistry;
@@ -60,18 +59,21 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.app.IBatteryStats;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockIcon;
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;
@@ -93,6 +95,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
private static final String ORGANIZATION_NAME = "organization";
private String mDisclosureWithOrganization;
private String mDisclosureGeneric;
@Mock
private DevicePolicyManager mDevicePolicyManager;
@@ -101,7 +104,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private KeyguardIndicationTextView mDisclosure;
private KeyguardIndicationTextView mIndicationAreaBottom;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
@@ -118,8 +121,20 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
private IBatteryStats mIBatteryStats;
@Mock
private DockManager mDockManager;
@Mock
private KeyguardIndicationRotateTextViewController mRotateTextViewController;
@Captor
private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
@Captor
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
@Captor
private ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor;
private StatusBarStateController.StateListener mStatusBarStateListener;
private BroadcastReceiver mBroadcastReceiver;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private KeyguardIndicationTextView mTextView;
private KeyguardIndicationController mController;
@@ -140,15 +155,15 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
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);
when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
when(mIndicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure))
.thenReturn(mDisclosure);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom))
.thenReturn(mIndicationAreaBottom);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
when(mDisclosure.getAlpha()).thenReturn(1f);
mWakeLock = new WakeLockFake();
mWakeLockBuilder = new WakeLockFake.Builder(mContext);
@@ -168,11 +183,15 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mController = new KeyguardIndicationController(mContext, mWakeLockBuilder,
mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
mUserManager);
mUserManager, mExecutor);
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(mDisclosure).getAlpha();
}
@Test
@@ -223,7 +242,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
createController();
verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
mController.setVisible(true);
mController.setDozing(true);
mStatusBarStateListener.onDozingChanged(true);
mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
});
@@ -241,7 +260,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
createController();
verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
mController.setVisible(true);
mController.setDozing(true);
mStatusBarStateListener.onDozingChanged(true);
mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
});
@@ -255,136 +274,108 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
@Test
public void disclosure_unmanaged() {
createController();
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(false);
createController();
sendUpdateDisclosureBroadcast();
verify(mDisclosure).setVisibility(View.GONE);
verifyNoMoreInteractions(mDisclosure);
verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_DISCLOSURE);
verify(mRotateTextViewController, never()).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
any(), anyBoolean());
}
@Test
public void disclosure_deviceOwner_noOwnerName() {
public void disclosure_deviceOwner_noOrganizationName() {
createController();
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
createController();
sendUpdateDisclosureBroadcast();
verify(mDisclosure).setVisibility(View.VISIBLE);
verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
verifyNoMoreInteractions(mDisclosure);
verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
mKeyguardIndicationCaptor.capture(), eq(false));
assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
.isEqualTo(mDisclosureGeneric);
}
@Test
public void disclosure_orgOwnedDeviceWithManagedProfile_noOwnerName() {
public void disclosure_orgOwnedDeviceWithManagedProfile_noOrganizationName() {
createController();
when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(true);
when(mUserManager.getProfiles(anyInt())).thenReturn(Collections.singletonList(
new UserInfo(10, /* name */ null, /* flags */ FLAG_MANAGED_PROFILE)));
when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(null);
createController();
sendUpdateDisclosureBroadcast();
verify(mDisclosure).setVisibility(View.VISIBLE);
verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
verifyNoMoreInteractions(mDisclosure);
verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
mKeyguardIndicationCaptor.capture(), eq(false));
assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
.isEqualTo(mDisclosureGeneric);
}
@Test
public void disclosure_hiddenWhenDozing() {
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
public void disclosure_deviceOwner_withOrganizationName() {
createController();
mController.setVisible(true);
mController.onDozeAmountChanged(1, 1);
mController.setDozing(true);
verify(mDisclosure).setVisibility(View.VISIBLE);
verify(mDisclosure).setAlpha(0f);
verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
verifyNoMoreInteractions(mDisclosure);
}
@Test
public void disclosure_visibleWhenDozing() {
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
createController();
mController.setVisible(true);
mController.onDozeAmountChanged(0, 0);
mController.setDozing(false);
verify(mDisclosure).setVisibility(View.VISIBLE);
verify(mDisclosure).setAlpha(1f);
verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
verifyNoMoreInteractions(mDisclosure);
}
@Test
public void disclosure_deviceOwner_withOwnerName() {
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
createController();
sendUpdateDisclosureBroadcast();
verify(mDisclosure).setVisibility(View.VISIBLE);
verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
verifyNoMoreInteractions(mDisclosure);
verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
mKeyguardIndicationCaptor.capture(), eq(false));
assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
.isEqualTo(mDisclosureWithOrganization);
}
@Test
public void disclosure_orgOwnedDeviceWithManagedProfile_withOwnerName() {
public void disclosure_orgOwnedDeviceWithManagedProfile_withOrganizationName() {
createController();
when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(true);
when(mUserManager.getProfiles(anyInt())).thenReturn(Collections.singletonList(
new UserInfo(10, /* name */ null, FLAG_MANAGED_PROFILE)));
when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(ORGANIZATION_NAME);
createController();
sendUpdateDisclosureBroadcast();
verify(mDisclosure).setVisibility(View.VISIBLE);
verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
verifyNoMoreInteractions(mDisclosure);
verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
mKeyguardIndicationCaptor.capture(), eq(false));
assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
.isEqualTo(mDisclosureWithOrganization);
}
@Test
public void disclosure_updateOnTheFly() {
ArgumentCaptor<BroadcastReceiver> receiver = ArgumentCaptor.forClass(
BroadcastReceiver.class);
doNothing().when(mBroadcastDispatcher).registerReceiver(receiver.capture(), any());
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
createController();
final KeyguardUpdateMonitorCallback monitor = mController.getKeyguardCallback();
reset(mDisclosure);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
receiver.getValue().onReceive(mContext, new Intent());
sendUpdateDisclosureBroadcast();
verify(mDisclosure).setVisibility(View.VISIBLE);
verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
verifyNoMoreInteractions(mDisclosure);
reset(mDisclosure);
verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
mKeyguardIndicationCaptor.capture(), eq(false));
assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
.isEqualTo(mDisclosureGeneric);
reset(mRotateTextViewController);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
receiver.getValue().onReceive(mContext, new Intent());
sendUpdateDisclosureBroadcast();
verify(mDisclosure).setVisibility(View.VISIBLE);
verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
verifyNoMoreInteractions(mDisclosure);
reset(mDisclosure);
verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
mKeyguardIndicationCaptor.capture(), eq(false));
assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
.isEqualTo(mDisclosureWithOrganization);
reset(mRotateTextViewController);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
receiver.getValue().onReceive(mContext, new Intent());
sendUpdateDisclosureBroadcast();
verify(mDisclosure).setVisibility(View.GONE);
verifyNoMoreInteractions(mDisclosure);
verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_DISCLOSURE);
}
@Test
public void transientIndication_holdsWakeLock_whenDozing() {
createController();
mController.setDozing(true);
mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test");
assertTrue(mWakeLock.isHeld());
@@ -394,7 +385,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
public void transientIndication_releasesWakeLock_afterHiding() {
createController();
mController.setDozing(true);
mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test");
mController.hideTransientIndication();
@@ -406,7 +397,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mInstrumentation.runOnMainSync(() -> {
createController();
mController.setDozing(true);
mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test");
mController.hideTransientIndicationDelayed(0);
});
@@ -425,7 +416,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mController.setVisible(true);
mController.showTransientIndication("Test");
mController.setDozing(true);
mStatusBarStateListener.onDozingChanged(true);
assertThat(mTextView.getText()).isEqualTo("Test");
assertThat(mTextView.getCurrentTextColor()).isEqualTo(Color.WHITE);
@@ -442,7 +433,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message,
BiometricSourceType.FACE);
assertThat(mTextView.getText()).isEqualTo(message);
mController.setDozing(true);
mStatusBarStateListener.onDozingChanged(true);
assertThat(mTextView.getText()).isNotEqualTo(message);
}
@@ -457,7 +448,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
"A message", BiometricSourceType.FACE);
assertThat(mTextView.getText()).isEqualTo(message);
mController.setDozing(true);
mStatusBarStateListener.onDozingChanged(true);
assertThat(mTextView.getText()).isNotEqualTo(message);
}
@@ -528,8 +519,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
public void setDozing_noIBatteryCalls() throws RemoteException {
createController();
mController.setVisible(true);
mController.setDozing(true);
mController.setDozing(false);
mStatusBarStateListener.onDozingChanged(true);
mStatusBarStateListener.onDozingChanged(false);
verify(mIBatteryStats, never()).computeChargeTimeRemaining();
}
@@ -537,7 +528,6 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
public void updateMonitor_listener() {
createController();
verify(mKeyguardStateController).addCallback(eq(mController));
verify(mStatusBarStateController).addCallback(eq(mController));
verify(mKeyguardUpdateMonitor, times(2)).registerCallback(any());
}
@@ -612,10 +602,14 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
0 /* maxChargingWattage */, true /* present */);
mController.getKeyguardCallback().onRefreshBatteryInfo(status);
mController.setDozing(true);
mStatusBarStateListener.onDozingChanged(true);
mController.setVisible(true);
String percentage = NumberFormat.getPercentInstance().format(90 / 100f);
assertThat(mTextView.getText()).isEqualTo(percentage);
}
private void sendUpdateDisclosureBroadcast() {
mBroadcastReceiver.onReceive(mContext, new Intent());
}
}

View File

@@ -51,21 +51,21 @@ public class KeyguardIndicationTextViewTest extends SysuiTestCase {
@Test
public void switchIndication_null_hideIndication() {
mKeyguardIndicationTextView.switchIndication(null /* text */);
mKeyguardIndicationTextView.switchIndication(null /* text */, null);
assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("");
}
@Test
public void switchIndication_emptyText_hideIndication() {
mKeyguardIndicationTextView.switchIndication("" /* text */);
mKeyguardIndicationTextView.switchIndication("" /* text */, null);
assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("");
}
@Test
public void switchIndication_newText_updateProperly() {
mKeyguardIndicationTextView.switchIndication("test_indication" /* text */);
mKeyguardIndicationTextView.switchIndication("test_indication" /* text */, null);
assertThat(mKeyguardIndicationTextView.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("test_indication");