Merge "Rotate keyguard indication messages" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
224e5f0b31
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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{}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user