summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
authorBeverly <beverlyt@google.com>2021-02-03 09:58:26 -0500
committerBeverly <beverlyt@google.com>2021-02-09 08:35:31 -0500
commitaac8e536ab2411a0febacbcfaae1fe79d85f556c (patch)
treef819c4d36572c77eec9006217356eedd173f6959 /packages/SystemUI/src
parent5e8177bf787c384f914fa9bb388a871afd6e25fa (diff)
Rotate keyguard indication messages
In the new LS layout, we show the following messages in the keyguard bottom area instead of in the KeyguardStatusView: - Logout button - Owner information We also now show now playing as part of the rotating text on the lock screen. Bug: 178794517 Test: atest SystemUITest, manual Change-Id: I1a0a47e300d1f9e5fe11c17d143e5a8f0ad8af60
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java28
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java155
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java326
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java464
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java150
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java11
8 files changed, 981 insertions, 166 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 97aa26fb7f68..fea152abe36a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -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));
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 973b49384c09..a5f364d30d7d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -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();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
new file mode 100644
index 000000000000..3a06f7aeb6bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
@@ -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);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
new file mode 100644
index 000000000000..d0070d8d9ae9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -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{}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index c816784a22f2..c70a93b5c894 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -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);
+ 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 {
+ 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";
}
- mDisclosure.setVisibility(View.VISIBLE);
+
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_BATTERY,
+ new KeyguardIndication.Builder()
+ .setMessage(powerIndication)
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ animate);
} else {
- mDisclosure.setVisibility(View.GONE);
+ // 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;
}
+ // LOCK SCREEN
+ // Some cases here might need to hide the indication (if the battery is not present)
int userId = KeyguardUpdateMonitor.getCurrentUser();
- String trustGrantedIndication = getTrustGrantedIndication();
- String trustManagedIndication = getTrustManagedIndication();
-
- String powerIndication = null;
- if (mPowerPluggedIn || mEnableBatteryDefender) {
- powerIndication = computePowerIndication();
- }
- // 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);
+ if (mLockScreenMode == LOCK_SCREEN_MODE_LAYOUT_1) {
+ mTopIndicationView.setVisibility(GONE);
+ updateIndications(animate, userId);
+ } else {
+ boolean hideIndication = false;
+ boolean isError = false;
+ String trustGrantedIndication = getTrustGrantedIndication();
+ String trustManagedIndication = getTrustManagedIndication();
+ String powerIndication = null;
+
+ if (mPowerPluggedIn || mEnableBatteryDefender) {
+ powerIndication = computePowerIndication();
}
- 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);
+ 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 {
- 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";
+ mTopIndicationView.switchIndication(mRestingIndication, null);
}
- if (animate) {
- animateText(mTextView, powerIndication);
- } else {
- mTextView.switchIndication(powerIndication);
+
+ mTopIndicationView.setTextColor(
+ isError ? Utils.getColorError(mContext) : mInitialTextColorState);
+
+ if (hideIndication) {
+ mIndicationArea.setVisibility(GONE);
}
- hideIndication = !mBatteryPresent;
- } else if (!TextUtils.isEmpty(trustManagedIndication)
- && mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
- && !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
- mTextView.switchIndication(trustManagedIndication);
- } else {
- mTextView.switchIndication(mRestingIndication);
- }
- mTextView.setTextColor(isError ? Utils.getColorError(mContext)
- : mInitialTextColorState);
- if (hideIndication) {
- mIndicationArea.setVisibility(View.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
@@ -687,6 +879,11 @@ public class KeyguardIndicationController implements StateListener,
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
|| status.status == BatteryManager.BATTERY_STATUS_FULL;
@@ -845,6 +1042,7 @@ public class KeyguardIndicationController implements StateListener,
@Override
public void onUserSwitchComplete(int userId) {
if (mVisible) {
+ updateOwnerInfo();
updateIndication(false);
}
}
@@ -857,11 +1055,39 @@ 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);
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 0a366c9bb380..3ff04d2d83a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -123,8 +123,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private KeyguardAffordanceView mRightAffordanceView;
private KeyguardAffordanceView mLeftAffordanceView;
private ViewGroup mIndicationArea;
- private TextView mEnterpriseDisclosure;
private TextView mIndicationText;
+ private TextView mIndicationTextBottom;
private ViewGroup mPreviewContainer;
private ViewGroup mOverlayContainer;
@@ -237,9 +237,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mRightAffordanceView = findViewById(R.id.camera_button);
mLeftAffordanceView = findViewById(R.id.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(
@@ -316,7 +315,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,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 30c951ac518c..8970a9a20931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -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);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 83651398be43..1425dabc6d9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1136,8 +1136,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mLockscreenWallpaper = mLockscreenWallpaperLazy.get();
}
- mKeyguardIndicationController.setIndicationArea(
- mNotificationShadeWindowView.findViewById(R.id.keyguard_indication_area));
mNotificationPanelViewController.setKeyguardIndicationController(
mKeyguardIndicationController);
@@ -3613,26 +3611,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();