summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/Keyguard/src/com/android/keyguard/EmergencyButton.java4
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java8
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java2
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java11
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java9
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java3
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java5
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java36
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java5
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_fingerprint_ridges_animation.xml50
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_1_animation.xml36
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_2_animation.xml70
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_path_3_animation.xml36
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_0_animation.xml43
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_animation.xml36
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_0_animation.xml43
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_animation.xml36
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_0_animation.xml43
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_animation.xml26
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_0_animation.xml43
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_animation.xml36
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_0_animation.xml53
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_animation.xml36
-rw-r--r--packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_white_fingerprint_ridges_animation.xml50
-rw-r--r--packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state.xml180
-rw-r--r--packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_animation.xml65
-rw-r--r--packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1.xml19
-rw-r--r--packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2.xml19
-rw-r--r--packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3.xml19
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml2
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/BatteryMeterView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java146
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java212
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java170
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java262
56 files changed, 1940 insertions, 540 deletions
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 1699809..25b1875 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -120,7 +120,7 @@ public class EmergencyButton extends Button {
KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(
true /* bypassHandler */);
getContext().startActivityAsUser(INTENT_EMERGENCY_DIAL,
- new UserHandle(mLockPatternUtils.getCurrentUser()));
+ new UserHandle(KeyguardUpdateMonitor.getCurrentUser()));
}
}
@@ -138,7 +138,7 @@ public class EmergencyButton extends Button {
visible = mEnableEmergencyCallWhileSimLocked;
} else {
// Only show if there is a secure screen (pin/pattern/SIM pin/SIM puk);
- visible = mLockPatternUtils.isSecure();
+ visible = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
}
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 322be91..c4f4b9a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -63,7 +63,8 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
// start fresh
resetPasswordText(false /* animate */);
// if the user is currently locked out, enforce it.
- long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
if (shouldLockout(deadline)) {
handleAttemptLockout(deadline);
} else {
@@ -106,7 +107,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
protected void verifyPasswordAndUnlock() {
String entry = getPasswordText();
- if (mLockPatternUtils.checkPassword(entry)) {
+ if (mLockPatternUtils.checkPassword(entry, KeyguardUpdateMonitor.getCurrentUser())) {
mCallback.reportUnlockAttempt(true);
mCallback.dismiss(true);
} else {
@@ -116,7 +117,8 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
mCallback.reportUnlockAttempt(false);
int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
if (0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
handleAttemptLockout(deadline);
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index be71b034..2cf30ba 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -71,7 +71,7 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
@Override
public void onTrustGrantedWithFlags(int flags, int userId) {
- if (userId != mLockPatternUtils.getCurrentUser()) return;
+ if (userId != KeyguardUpdateMonitor.getCurrentUser()) return;
if (!isAttachedToWindow()) return;
boolean bouncerVisible = isVisibleToUser();
boolean initiatedByUser =
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 9aa5729..557cd13 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -130,7 +130,8 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
mLockPatternView.setOnPatternListener(new UnlockPatternListener());
// stealth mode will be the same for the life of this screen
- mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled());
+ mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
+ KeyguardUpdateMonitor.getCurrentUser()));
// vibrate mode will be the same for the life of this screen
mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
@@ -176,7 +177,8 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
mLockPatternView.clearPattern();
// if the user is currently locked out, enforce it.
- long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
if (deadline != 0) {
handleAttemptLockout(deadline);
} else {
@@ -213,7 +215,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
}
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
- if (mLockPatternUtils.checkPattern(pattern)) {
+ if (mLockPatternUtils.checkPattern(pattern, KeyguardUpdateMonitor.getCurrentUser())) {
mCallback.reportUnlockAttempt(true);
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
mCallback.dismiss(true);
@@ -230,7 +232,8 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
int attempts = mKeyguardUpdateMonitor.getFailedUnlockAttempts();
if (registeredAttempt &&
0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
handleAttemptLockout(deadline);
} else {
mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern, true);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5af7783..ae4baad 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -261,7 +261,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
SecurityMode mode = mSecurityModel.getSecurityMode();
final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern;
- final int currentUser = mLockPatternUtils.getCurrentUser();
+ final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
final int failedAttemptsBeforeWipe =
dpm.getMaximumFailedPasswordsForWipe(null, currentUser);
@@ -296,7 +296,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
(failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
}
monitor.reportFailedUnlockAttempt();
- mLockPatternUtils.reportFailedPasswordAttempt();
+ mLockPatternUtils.reportFailedPasswordAttempt(KeyguardUpdateMonitor.getCurrentUser());
if (showTimeout) {
showTimeoutDialog();
}
@@ -321,7 +321,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
boolean showNextSecurityScreenOrFinish(boolean authenticated) {
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
boolean finish = false;
- if (mUpdateMonitor.getUserHasTrust(mLockPatternUtils.getCurrentUser())) {
+ if (mUpdateMonitor.getUserHasTrust(KeyguardUpdateMonitor.getCurrentUser())) {
finish = true;
} else if (SecurityMode.None == mCurrentSecuritySelection) {
SecurityMode securityMode = mSecurityModel.getSecurityMode();
@@ -430,7 +430,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
if (success) {
monitor.clearFailedUnlockAttempts();
- mLockPatternUtils.reportSuccessfulPasswordAttempt();
+ mLockPatternUtils.reportSuccessfulPasswordAttempt(
+ KeyguardUpdateMonitor.getCurrentUser());
} else {
KeyguardSecurityContainer.this.reportFailedUnlockAttempt();
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 3eb31ad..454221a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -67,7 +67,8 @@ public class KeyguardSecurityModel {
return SecurityMode.SimPuk;
}
- final int security = mLockPatternUtils.getActivePasswordQuality();
+ final int security = mLockPatternUtils.getActivePasswordQuality(
+ KeyguardUpdateMonitor.getCurrentUser());
switch (security) {
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index af6360a..4e9621a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -200,9 +200,10 @@ public class KeyguardStatusView extends GridLayout {
private String getOwnerInfo() {
ContentResolver res = getContext().getContentResolver();
String info = null;
- final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled();
+ final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
+ KeyguardUpdateMonitor.getCurrentUser());
if (ownerInfoEnabled) {
- info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser());
+ info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
}
return info;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1eec532..b8d9053 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -244,6 +244,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
+ private static int sCurrentUser;
+
+ public synchronized static void setCurrentUser(int currentUser) {
+ sCurrentUser = currentUser;
+ }
+
+ public synchronized static int getCurrentUser() {
+ return sCurrentUser;
+ }
+
@Override
public void onTrustChanged(boolean enabled, int userId, int flags) {
mUserHasTrust.put(userId, enabled);
@@ -669,7 +679,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
cb.onScreenTurnedOn();
}
}
- startListeningForFingerprint();
+ updateFingerprintListeningState();
}
protected void handleScreenTurnedOff(int arg1) {
@@ -681,7 +691,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
cb.onScreenTurnedOff(arg1);
}
}
- stopListeningForFingerprint();
+ updateFingerprintListeningState();
}
/**
@@ -754,14 +764,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
newUserId, 0, reply));
mSwitchingUser = true;
- stopListeningForFingerprint();
+ updateFingerprintListeningState();
}
@Override
public void onUserSwitchComplete(int newUserId) throws RemoteException {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
newUserId, 0));
mSwitchingUser = false;
- startListeningForFingerprint();
+ updateFingerprintListeningState();
}
@Override
public void onForegroundProfileSwitch(int newProfileId) {
@@ -777,7 +787,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
trustManager.registerTrustListener(this);
mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
- startListeningForFingerprint();
+ updateFingerprintListeningState();
+ }
+
+ private void updateFingerprintListeningState() {
+ boolean shouldListenForFingerprint = shouldListenForFingerprint();
+ if (mFingerprintDetectionRunning && !shouldListenForFingerprint) {
+ stopListeningForFingerprint();
+ } else if (!mFingerprintDetectionRunning && shouldListenForFingerprint) {
+ startListeningForFingerprint();
+ }
+ }
+
+ private boolean shouldListenForFingerprint() {
+ return mScreenOn && mKeyguardIsVisible && !mSwitchingUser;
}
private void startListeningForFingerprint() {
@@ -794,7 +817,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
- public void stopListeningForFingerprint() {
+ private void stopListeningForFingerprint() {
if (DEBUG) Log.v(TAG, "stopListeningForFingerprint()");
if (isFingerprintDetectionRunning()) {
mFingerprintCancelSignal.cancel();
@@ -1052,6 +1075,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
cb.onKeyguardVisibilityChangedRaw(isShowing);
}
}
+ updateFingerprintListeningState();
}
/**
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 870f043..7bf2223 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2066,7 +2066,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
LockPatternUtils lpu = new LockPatternUtils(mContext);
List<LockPatternView.Cell> cellPattern =
LockPatternUtils.stringToPattern(lockPattern);
- lpu.saveLockPattern(cellPattern, null);
+ lpu.saveLockPattern(cellPattern, null, UserHandle.USER_OWNER);
} catch (IllegalArgumentException e) {
// Don't want corrupted lock pattern to hang the reboot process
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 7f826ef..d99f741 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -754,7 +754,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
*/
private byte[] getLockSettings() {
final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
- final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled();
+ final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(UserHandle.myUserId());
final String ownerInfo = lockPatternUtils.getOwnerInfo(UserHandle.myUserId());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -871,7 +871,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
switch (key) {
case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
- lockPatternUtils.setOwnerInfoEnabled("1".equals(value));
+ lockPatternUtils.setOwnerInfoEnabled("1".equals(value),
+ UserHandle.myUserId());
break;
case KEY_LOCK_SETTINGS_OWNER_INFO:
lockPatternUtils.setOwnerInfo(value, UserHandle.myUserId());
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_fingerprint_ridges_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_fingerprint_ridges_animation.xml
new file mode 100644
index 0000000..c6a4622
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_fingerprint_ridges_animation.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="rotation"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="566"
+ android:propertyName="rotation"
+ android:valueFrom="0.0"
+ android:valueTo="-305.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3" />
+ <objectAnimator
+ android:duration="1066"
+ android:propertyName="rotation"
+ android:valueFrom="-305.0"
+ android:valueTo="-305.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+ <objectAnimator
+ android:duration="800"
+ android:propertyName="rotation"
+ android:valueFrom="-305.0"
+ android:valueTo="-720.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_1_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_1_animation.xml
new file mode 100644
index 0000000..0e2c2f0
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_1_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="rotation"
+ android:valueFrom="285.0"
+ android:valueTo="285.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="516"
+ android:propertyName="rotation"
+ android:valueFrom="285.0"
+ android:valueTo="90.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_2_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_2_animation.xml
new file mode 100644
index 0000000..c01010d
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_group_2_animation.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="scaleX"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="316"
+ android:propertyName="scaleX"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="scaleY"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="316"
+ android:propertyName="scaleY"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="rotation"
+ android:valueFrom="184.0"
+ android:valueTo="184.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="316"
+ android:propertyName="rotation"
+ android:valueFrom="184.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_path_3_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_path_3_animation.xml
new file mode 100644
index 0000000..454be24
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_path_3_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="233"
+ android:propertyName="trimPathStart"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="466"
+ android:propertyName="trimPathStart"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_0_animation.xml
new file mode 100644
index 0000000..faeecf4
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_0_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_animation.xml
new file mode 100644
index 0000000..3bacf03
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_1_path_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="16"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="66"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_0_animation.xml
new file mode 100644
index 0000000..80a0faa
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_0_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="116"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="116"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3" />
+ </set>
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="trimPathStart"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3" />
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_animation.xml
new file mode 100644
index 0000000..3a18296
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_2_path_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="16"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_0_animation.xml
new file mode 100644
index 0000000..1e16df7
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_0_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_animation.xml
new file mode 100644
index 0000000..a1cf8df
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_5_path_animation.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_0_animation.xml
new file mode 100644
index 0000000..f88c070
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_0_animation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="216"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_animation.xml
new file mode 100644
index 0000000..ada7c10
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_6_path_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="16"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="216"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_0_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_0_animation.xml
new file mode 100644
index 0000000..e6b12da
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_0_animation.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="16"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="216"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="266"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_animation.xml
new file mode 100644
index 0000000..8c6e71d
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_ridge_7_path_animation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="trimPathStart"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_white_fingerprint_ridges_animation.xml b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_white_fingerprint_ridges_animation.xml
new file mode 100644
index 0000000..c6a4622
--- /dev/null
+++ b/packages/SystemUI/res/anim/lockscreen_fingerprint_error_state_white_fingerprint_ridges_animation.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="rotation"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="566"
+ android:propertyName="rotation"
+ android:valueFrom="0.0"
+ android:valueTo="-305.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3" />
+ <objectAnimator
+ android:duration="1066"
+ android:propertyName="rotation"
+ android:valueFrom="-305.0"
+ android:valueTo="-305.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+ <objectAnimator
+ android:duration="800"
+ android:propertyName="rotation"
+ android:valueFrom="-305.0"
+ android:valueTo="-720.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state.xml
new file mode 100644
index 0000000..cc8aba9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state.xml
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="lockscreen_fingerprint_error_state"
+ android:width="32dp"
+ android:viewportWidth="32"
+ android:height="32dp"
+ android:viewportHeight="32" >
+ <group
+ android:name="white_fingerprint_ridges"
+ android:translateX="16.125"
+ android:translateY="19.75" >
+ <group
+ android:name="white_fingerprint_ridges_pivot"
+ android:translateX="33.2085"
+ android:translateY="30.91685" >
+ <group
+ android:name="ridge_5" >
+ <path
+ android:name="ridge_5_path"
+ android:pathData="M -25.3591003418,-24.4138946533 c -0.569000244141,0.106399536133 -1.12660217285,0.140594482422 -1.45460510254,0.140594482422 c -1.29689025879,0.0 -2.53239440918,-0.343307495117 -3.62019348145,-1.12400817871 c -1.67700195312,-1.20349121094 -2.76950073242,-3.17008972168 -2.76950073242,-5.39189147949"
+ android:strokeColor="#FFFFFFFF"
+ android:strokeAlpha="0.5"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round" />
+ </group>
+ <group
+ android:name="ridge_4" >
+ <path
+ android:name="ridge_7_path"
+ android:pathData="M -36.1409912109,-21.7843475342 c -1.00540161133,-1.19300842285 -1.57499694824,-1.9181060791 -2.36520385742,-3.50170898438 c -0.827560424805,-1.65869140625 -1.31352233887,-3.49159240723 -1.31352233887,-5.48489379883 c 0.0,-3.66279602051 2.96932983398,-6.63220214844 6.63221740723,-6.63220214844 c 3.6628112793,0.0 6.63220214844,2.96940612793 6.63220214844,6.63220214844"
+ android:strokeColor="#FFFFFFFF"
+ android:strokeAlpha="0.5"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round" />
+ </group>
+ <group
+ android:name="ridge_3" >
+ <path
+ android:name="ridge_6_path"
+ android:pathData="M -42.1907958984,-25.6756896973 c -0.758117675781,-2.14370727539 -0.896545410156,-3.86891174316 -0.896545410156,-5.12921142578 c 0.0,-1.46069335938 0.249176025391,-2.84799194336 0.814682006836,-4.09748840332 c 1.56153869629,-3.45030212402 5.03434753418,-5.85076904297 9.0679473877,-5.85076904297 c 5.49430847168,0.0 9.94830322266,4.4539642334 9.94830322266,9.94825744629 c 0.0,1.83151245117 -1.48460388184,3.31610107422 -3.31610107422,3.31610107422 c -1.83149719238,0.0 -3.31610107422,-1.48469543457 -3.31610107422,-3.31610107422 c 0.0,-1.83139038086 -1.48458862305,-3.31610107422 -3.31610107422,-3.31610107422 c -1.83149719238,0.0 -3.31610107422,1.48471069336 -3.31610107422,3.31610107422 c 0.0,2.57020568848 0.989517211914,4.88710021973 2.60510253906,6.5865020752 c 1.22210693359,1.28550720215 2.43139648438,2.09950256348 4.47590637207,2.69030761719"
+ android:strokeColor="#FFFFFFFF"
+ android:strokeAlpha="0.5"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round" />
+ </group>
+ <group
+ android:name="ridge_2" >
+ <path
+ android:name="ridge_2_path"
+ android:pathData="M -44.0646514893,-38.1672973633 c 1.19026184082,-1.77430725098 2.67503356934,-3.24531555176 4.55902099609,-4.27278137207 c 1.88395690918,-1.0274810791 4.04466247559,-1.61137390137 6.34175109863,-1.61137390137 c 2.28761291504,0.0 4.43991088867,0.579071044922 6.31831359863,1.59861755371 c 1.8784942627,1.01954650879 3.36059570312,2.4796295166 4.55279541016,4.24153137207"
+ android:strokeColor="#FFFFFFFF"
+ android:strokeAlpha="0.5"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round" />
+ </group>
+ <group
+ android:name="ridge_1"
+ android:translateX="-97.5"
+ android:translateY="-142.5" >
+ <path
+ android:name="ridge_1_path"
+ android:pathData="M 71.7812347412,97.0507202148 c -2.27149963379,-1.31344604492 -4.71360778809,-2.07006835938 -7.56221008301,-2.07006835938 c -2.84869384766,0.0 -5.23320007324,0.779556274414 -7.34411621094,2.07006835938"
+ android:strokeColor="#FFFFFFFF"
+ android:strokeAlpha="0.5"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round" />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="fingerprint_ridges"
+ android:translateX="16.125"
+ android:translateY="19.75" >
+ <group
+ android:name="fingerprint_ridges_pivot"
+ android:translateX="33.2085"
+ android:translateY="30.91685" >
+ <group
+ android:name="ridge_6" >
+ <path
+ android:name="ridge_5_path_0"
+ android:pathData="M -25.3591003418,-24.4138946533 c -0.569000244141,0.106399536133 -1.12660217285,0.140594482422 -1.45460510254,0.140594482422 c -1.29689025879,0.0 -2.53239440918,-0.343307495117 -3.62019348145,-1.12400817871 c -1.67700195312,-1.20349121094 -2.76950073242,-3.17008972168 -2.76950073242,-5.39189147949"
+ android:strokeColor="#FFF2501D"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round"
+ android:trimPathEnd="0" />
+ </group>
+ <group
+ android:name="ridge_7" >
+ <path
+ android:name="ridge_7_path_0"
+ android:pathData="M -36.1409912109,-21.7843475342 c -1.00540161133,-1.19300842285 -1.57499694824,-1.9181060791 -2.36520385742,-3.50170898438 c -0.827560424805,-1.65869140625 -1.31352233887,-3.49159240723 -1.31352233887,-5.48489379883 c 0.0,-3.66279602051 2.96932983398,-6.63220214844 6.63221740723,-6.63220214844 c 3.6628112793,0.0 6.63220214844,2.96940612793 6.63220214844,6.63220214844"
+ android:strokeColor="#FFF2501D"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round"
+ android:trimPathEnd="0" />
+ </group>
+ <group
+ android:name="ridge_8" >
+ <path
+ android:name="ridge_6_path_0"
+ android:pathData="M -42.1907958984,-25.6756896973 c -0.758117675781,-2.14370727539 -0.896545410156,-3.86891174316 -0.896545410156,-5.12921142578 c 0.0,-1.46069335938 0.249176025391,-2.84799194336 0.814682006836,-4.09748840332 c 1.56153869629,-3.45030212402 5.03434753418,-5.85076904297 9.0679473877,-5.85076904297 c 5.49430847168,0.0 9.94830322266,4.4539642334 9.94830322266,9.94825744629 c 0.0,1.83151245117 -1.48460388184,3.31610107422 -3.31610107422,3.31610107422 c -1.83149719238,0.0 -3.31610107422,-1.48469543457 -3.31610107422,-3.31610107422 c 0.0,-1.83139038086 -1.48458862305,-3.31610107422 -3.31610107422,-3.31610107422 c -1.83149719238,0.0 -3.31610107422,1.48471069336 -3.31610107422,3.31610107422 c 0.0,2.57020568848 0.989517211914,4.88710021973 2.60510253906,6.5865020752 c 1.22210693359,1.28550720215 2.43139648438,2.09950256348 4.47590637207,2.69030761719"
+ android:strokeColor="#FFF2501D"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round"
+ android:trimPathEnd="0" />
+ </group>
+ <group
+ android:name="ridge_9" >
+ <path
+ android:name="ridge_2_path_0"
+ android:pathData="M -44.0646514893,-38.1672973633 c 1.19026184082,-1.77430725098 2.67503356934,-3.24531555176 4.55902099609,-4.27278137207 c 1.88395690918,-1.0274810791 4.04466247559,-1.61137390137 6.34175109863,-1.61137390137 c 2.28761291504,0.0 4.43991088867,0.579071044922 6.31831359863,1.59861755371 c 1.8784942627,1.01954650879 3.36059570312,2.4796295166 4.55279541016,4.24153137207"
+ android:strokeColor="#FFF2501D"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round"
+ android:trimPathStart="1" />
+ </group>
+ <group
+ android:name="ridge_10"
+ android:translateX="-97.5"
+ android:translateY="-142.5" >
+ <path
+ android:name="ridge_1_path_0"
+ android:pathData="M 71.7812347412,97.0507202148 c -2.27149963379,-1.31344604492 -4.71360778809,-2.07006835938 -7.56221008301,-2.07006835938 c -2.84869384766,0.0 -5.23320007324,0.779556274414 -7.34411621094,2.07006835938"
+ android:strokeColor="#FFF2501D"
+ android:strokeWidth="1.45"
+ android:strokeLineCap="round"
+ android:trimPathEnd="0" />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="exclamation"
+ android:translateX="16"
+ android:translateY="16" >
+ <group
+ android:name="group_2"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:rotation="184" >
+ <path
+ android:name="path_2_merged"
+ android:pathData="M 1.35900878906,6.76104736328 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-2.69995117188 0.0,-2.69995117188 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,2.69995117188 0.0,2.69995117188 Z M 1.35363769531,1.36633300781 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-8.09997558594 0.0,-8.09997558594 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,8.09997558594 0.0,8.09997558594 Z"
+ android:fillColor="#FFF2501D" />
+ </group>
+ </group>
+ <group
+ android:name="circle_outline"
+ android:translateX="16"
+ android:translateY="16" >
+ <group
+ android:name="group_1"
+ android:scaleX="1.12734"
+ android:scaleY="1.12734"
+ android:rotation="285" >
+ <path
+ android:name="path_3"
+ android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
+ android:strokeColor="#FFF2501D"
+ android:strokeWidth="2"
+ android:trimPathStart="1" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_animation.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_animation.xml
new file mode 100644
index 0000000..8cc8ac2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_animation.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/lockscreen_fingerprint_error_state" >
+ <target
+ android:name="white_fingerprint_ridges"
+ android:animation="@anim/lockscreen_fingerprint_error_state_white_fingerprint_ridges_animation" />
+ <target
+ android:name="ridge_5_path"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_5_path_animation" />
+ <target
+ android:name="ridge_7_path"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_7_path_animation" />
+ <target
+ android:name="ridge_6_path"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_6_path_animation" />
+ <target
+ android:name="ridge_2_path"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_2_path_animation" />
+ <target
+ android:name="ridge_1_path"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_1_path_animation" />
+ <target
+ android:name="fingerprint_ridges"
+ android:animation="@anim/lockscreen_fingerprint_error_state_fingerprint_ridges_animation" />
+ <target
+ android:name="ridge_5_path_0"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_5_path_0_animation" />
+ <target
+ android:name="ridge_7_path_0"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_7_path_0_animation" />
+ <target
+ android:name="ridge_6_path_0"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_6_path_0_animation" />
+ <target
+ android:name="ridge_2_path_0"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_2_path_0_animation" />
+ <target
+ android:name="ridge_1_path_0"
+ android:animation="@anim/lockscreen_fingerprint_error_state_ridge_1_path_0_animation" />
+ <target
+ android:name="group_2"
+ android:animation="@anim/lockscreen_fingerprint_error_state_group_2_animation" />
+ <target
+ android:name="group_1"
+ android:animation="@anim/lockscreen_fingerprint_error_state_group_1_animation" />
+ <target
+ android:name="path_3"
+ android:animation="@anim/lockscreen_fingerprint_error_state_path_3_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0.xml
new file mode 100644
index 0000000..39c5211
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.16666666667,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1.xml
new file mode 100644
index 0000000..d3ae9d7
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_1.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.0,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2.xml
new file mode 100644
index 0000000..e10db01
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_2.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.8,0.0 0.5,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3.xml
new file mode 100644
index 0000000..736eac6
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_error_state_animation_interpolator_3.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index fca8231..1057464 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -61,7 +61,7 @@
android:scaleType="center"
android:contentDescription="@string/accessibility_phone_button" />
- <com.android.systemui.statusbar.KeyguardAffordanceView
+ <com.android.systemui.statusbar.phone.LockIcon
android:id="@+id/lock_icon"
android:layout_width="@dimen/keyguard_affordance_width"
android:layout_height="@dimen/keyguard_affordance_height"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6afc5e5..6e79423 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -150,7 +150,7 @@
<integer name="heads_up_notification_minimum_time">2000</integer>
<!-- milliseconds before the heads up notification accepts touches. -->
- <integer name="heads_up_sensitivity_delay">700</integer>
+ <integer name="touch_acceptance_delay">700</integer>
<!-- The duration in seconds to wait before the dismiss buttons are shown. -->
<integer name="recents_task_bar_dismiss_delay_seconds">1</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 0d331d1..3fbc76b 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -225,23 +225,23 @@ public class BatteryMeterView extends View implements DemoMode,
mSubpixelSmoothingRight = context.getResources().getFraction(
R.fraction.battery_subpixel_smoothing_right, 1, 1);
- mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mFramePaint = new Paint();
mFramePaint.setColor(frameColor);
mFramePaint.setDither(true);
mFramePaint.setStrokeWidth(0);
mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
- mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBatteryPaint = new Paint();
mBatteryPaint.setDither(true);
mBatteryPaint.setStrokeWidth(0);
mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
- mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mTextPaint = new Paint();
Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
mTextPaint.setTypeface(font);
mTextPaint.setTextAlign(Paint.Align.CENTER);
- mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mWarningTextPaint = new Paint();
mWarningTextPaint.setColor(mColors[1]);
font = Typeface.create("sans-serif", Typeface.BOLD);
mWarningTextPaint.setTypeface(font);
@@ -249,7 +249,7 @@ public class BatteryMeterView extends View implements DemoMode,
mChargeColor = context.getColor(R.color.batterymeter_charge_color);
- mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBoltPaint = new Paint();
mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
mBoltPoints = loadBoltPoints(res);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 7b555fc..6479dc5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -539,10 +539,11 @@ public class KeyguardViewMediator extends SystemUI {
mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
mLockPatternUtils = new LockPatternUtils(mContext);
- mLockPatternUtils.setCurrentUser(ActivityManager.getCurrentUser());
+ KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());
// Assume keyguard is showing (unless it's disabled) until we know for sure...
- setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled());
+ setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled(
+ KeyguardUpdateMonitor.getCurrentUser()));
mTrustManager.reportKeyguardShowingChanged();
mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(mContext,
@@ -623,8 +624,10 @@ public class KeyguardViewMediator extends SystemUI {
// Lock immediately based on setting if secure (user has a pin/pattern/password).
// This also "locks" the device when not secure to provide easy access to the
// camera while preventing unwanted input.
+ int currentUser = KeyguardUpdateMonitor.getCurrentUser();
final boolean lockImmediately =
- mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure();
+ mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser)
+ || !mLockPatternUtils.isSecure(currentUser);
notifyScreenOffLocked();
@@ -670,7 +673,7 @@ public class KeyguardViewMediator extends SystemUI {
// From DevicePolicyAdmin
final long policyTimeout = mLockPatternUtils.getDevicePolicyManager()
- .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser());
+ .getMaximumTimeToLock(null, KeyguardUpdateMonitor.getCurrentUser());
long timeout;
if (policyTimeout > 0) {
@@ -719,7 +722,8 @@ public class KeyguardViewMediator extends SystemUI {
}
private void maybeSendUserPresentBroadcast() {
- if (mSystemReady && mLockPatternUtils.isLockScreenDisabled()) {
+ if (mSystemReady && mLockPatternUtils.isLockScreenDisabled(
+ KeyguardUpdateMonitor.getCurrentUser())) {
// Lock screen is disabled because the user has set the preference to "None".
// In this case, send out ACTION_USER_PRESENT here instead of in
// handleKeyguardDone()
@@ -733,7 +737,7 @@ public class KeyguardViewMediator extends SystemUI {
*/
public void onDreamingStarted() {
synchronized (this) {
- if (mScreenOn && mLockPatternUtils.isSecure()) {
+ if (mScreenOn && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
doKeyguardLaterLocked();
}
}
@@ -974,12 +978,13 @@ public class KeyguardViewMediator extends SystemUI {
return;
}
- if (mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) {
+ if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
+ && !lockedOrMissing) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
return;
}
- if (mLockPatternUtils.checkVoldPassword()) {
+ if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
// Without this, settings is not enabled until the lock screen first appears
setShowingLocked(false);
@@ -1072,7 +1077,7 @@ public class KeyguardViewMediator extends SystemUI {
}
public boolean isSecure() {
- return mLockPatternUtils.isSecure()
+ return mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())
|| KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure();
}
@@ -1083,7 +1088,7 @@ public class KeyguardViewMediator extends SystemUI {
* @param newUserId The id of the incoming user.
*/
public void setCurrentUser(int newUserId) {
- mLockPatternUtils.setCurrentUser(newUserId);
+ KeyguardUpdateMonitor.setCurrentUser(newUserId);
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -1213,7 +1218,7 @@ public class KeyguardViewMediator extends SystemUI {
private void sendUserPresentBroadcast() {
synchronized (this) {
if (mBootCompleted) {
- final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
+ final UserHandle currentUser = new UserHandle(KeyguardUpdateMonitor.getCurrentUser());
final UserManager um = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
List <UserInfo> userHandles = um.getProfiles(currentUser.getIdentifier());
@@ -1393,14 +1398,9 @@ public class KeyguardViewMediator extends SystemUI {
updateActivityLockScreenState();
adjustStatusBarLocked();
sendUserPresentBroadcast();
- maybeStopListeningForFingerprint();
}
}
- private void maybeStopListeningForFingerprint() {
- mUpdateMonitor.stopListeningForFingerprint();
- }
-
private void adjustStatusBarLocked() {
if (mStatusBarManager == null) {
mStatusBarManager = (StatusBarManager)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 92bd0df..26c3b4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -87,6 +87,7 @@ import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
import com.android.internal.util.NotificationColorUtil;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SwipeHelper;
@@ -639,7 +640,7 @@ public abstract class BaseStatusBar extends SystemUI implements
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
Log.d(TAG, "user hasn't seen notification about hidden notifications");
final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
- if (!lockPatternUtils.isSecure()) {
+ if (!lockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
Log.d(TAG, "insecure lockscreen, skipping notification");
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
@@ -783,7 +784,8 @@ public abstract class BaseStatusBar extends SystemUI implements
protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
NotificationData.Entry entry) {
- if (entry.expanded.getId() != com.android.internal.R.id.status_bar_latest_event_content) {
+ if (entry.getContentView().getId()
+ != com.android.internal.R.id.status_bar_latest_event_content) {
// Using custom RemoteViews
if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
&& entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
@@ -808,8 +810,9 @@ public abstract class BaseStatusBar extends SystemUI implements
public boolean isMediaNotification(NotificationData.Entry entry) {
// TODO: confirm that there's a valid media key
- return entry.expandedBig != null &&
- entry.expandedBig.findViewById(com.android.internal.R.id.media_actions) != null;
+ return entry.getExpandedContentView() != null &&
+ entry.getExpandedContentView()
+ .findViewById(com.android.internal.R.id.media_actions) != null;
}
// The gear button in the guts that links to the app's own notification settings
@@ -1133,9 +1136,9 @@ public abstract class BaseStatusBar extends SystemUI implements
}
/**
- * if the interrupting notification had a fullscreen intent, fire it now.
+ * If there is an active heads-up notification and it has a fullscreen intent, fire it now.
*/
- public abstract void escalateHeadsUp();
+ public abstract void maybeEscalateHeadsUp();
/**
* Save the current "public" (locked and secure) state of the lockscreen.
@@ -1336,8 +1339,8 @@ public abstract class BaseStatusBar extends SystemUI implements
View publicViewLocal = null;
if (publicNotification != null) {
try {
- publicViewLocal = publicNotification.contentView.apply(mContext, contentContainerPublic,
- mOnClickHandler);
+ publicViewLocal = publicNotification.contentView.apply(mContext,
+ contentContainerPublic, mOnClickHandler);
if (publicViewLocal != null) {
publicViewLocal.setIsRootNamespace(true);
@@ -1444,9 +1447,7 @@ public abstract class BaseStatusBar extends SystemUI implements
entry.row = row;
entry.row.setHeightRange(mRowMinHeight, maxHeight);
entry.row.setOnActivatedListener(this);
- entry.expanded = contentViewLocal;
- entry.expandedPublic = publicViewLocal;
- entry.setBigContentView(bigContentViewLocal);
+ entry.row.setExpandable(bigContentViewLocal != null);
applyColorsAndBackgrounds(sbn, entry);
@@ -1535,12 +1536,13 @@ public abstract class BaseStatusBar extends SystemUI implements
// See if we have somewhere to put that remote input
if (remoteInput != null) {
- if (entry.expandedBig != null) {
- inflateRemoteInput(entry.expandedBig, remoteInput, actions);
+ View bigContentView = entry.getExpandedContentView();
+ if (bigContentView != null) {
+ inflateRemoteInput(bigContentView, remoteInput, actions);
}
- View headsUpChild = entry.row.getPrivateLayout().getHeadsUpChild();
- if (headsUpChild != null) {
- inflateRemoteInput(headsUpChild, remoteInput, actions);
+ View headsUpContentView = entry.getHeadsUpContentView();
+ if (headsUpContentView != null) {
+ inflateRemoteInput(headsUpContentView, remoteInput, actions);
}
}
@@ -1882,15 +1884,14 @@ public abstract class BaseStatusBar extends SystemUI implements
logUpdate(entry, n);
}
boolean applyInPlace = shouldApplyInPlace(entry, n);
- final boolean shouldInterrupt = shouldInterrupt(notification);
- final boolean alertAgain = alertAgain(entry, n);
+ boolean shouldInterrupt = shouldInterrupt(notification);
+ boolean alertAgain = alertAgain(entry, n);
entry.notification = notification;
mGroupManager.onEntryUpdated(entry, entry.notification);
boolean updateSuccessful = false;
if (applyInPlace) {
- // We can just reapply the notifications in place
if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
try {
if (entry.icon != null) {
@@ -1911,7 +1912,7 @@ public abstract class BaseStatusBar extends SystemUI implements
updateSuccessful = true;
}
catch (RuntimeException e) {
- // It failed to add cleanly. Log, and remove the view from the panel.
+ // It failed to apply cleanly.
Log.w(TAG, "Couldn't reapply views for package " + n.contentView.getPackage(), e);
}
}
@@ -1935,11 +1936,12 @@ public abstract class BaseStatusBar extends SystemUI implements
// swipe-dismissable)
updateNotificationVetoButton(entry.row, notification);
- // Is this for you?
- boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
- if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
+ if (DEBUG) {
+ // Is this for you?
+ boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
+ Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
+ }
- // Recalculate the position of the sliding windows and the titles.
setAreThereNotifications();
}
@@ -1950,7 +1952,7 @@ public abstract class BaseStatusBar extends SystemUI implements
StatusBarNotification oldNotification = oldEntry.notification;
Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
+ " ongoing=" + oldNotification.isOngoing()
- + " expanded=" + oldEntry.expanded
+ + " expanded=" + oldEntry.getContentView()
+ " contentView=" + oldNotification.getNotification().contentView
+ " bigContentView=" + oldNotification.getNotification().bigContentView
+ " publicView=" + oldNotification.getNotification().publicVersion
@@ -1963,7 +1965,8 @@ public abstract class BaseStatusBar extends SystemUI implements
}
/**
- * @return whether we can just reapply the RemoteViews in place when it is updated
+ * @return whether we can just reapply the RemoteViews from a notification in-place when it is
+ * updated
*/
private boolean shouldApplyInPlace(Entry entry, Notification n) {
StatusBarNotification oldNotification = entry.notification;
@@ -1981,15 +1984,15 @@ public abstract class BaseStatusBar extends SystemUI implements
final Notification publicNotification = n.publicVersion;
final RemoteViews publicContentView = publicNotification != null
? publicNotification.contentView : null;
- boolean contentsUnchanged = entry.expanded != null
+ boolean contentsUnchanged = entry.getContentView() != null
&& contentView.getPackage() != null
&& oldContentView.getPackage() != null
&& oldContentView.getPackage().equals(contentView.getPackage())
&& oldContentView.getLayoutId() == contentView.getLayoutId();
// large view may be null
boolean bigContentsUnchanged =
- (entry.getBigContentView() == null && bigContentView == null)
- || ((entry.getBigContentView() != null && bigContentView != null)
+ (entry.getExpandedContentView() == null && bigContentView == null)
+ || ((entry.getExpandedContentView() != null && bigContentView != null)
&& bigContentView.getPackage() != null
&& oldBigContentView.getPackage() != null
&& oldBigContentView.getPackage().equals(bigContentView.getPackage())
@@ -2021,12 +2024,12 @@ public abstract class BaseStatusBar extends SystemUI implements
: null;
// Reapply the RemoteViews
- contentView.reapply(mContext, entry.expanded, mOnClickHandler);
- if (bigContentView != null && entry.getBigContentView() != null) {
- bigContentView.reapply(mContext, entry.getBigContentView(),
+ contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
+ if (bigContentView != null && entry.getExpandedContentView() != null) {
+ bigContentView.reapply(mContext, entry.getExpandedContentView(),
mOnClickHandler);
}
- View headsUpChild = entry.row.getPrivateLayout().getHeadsUpChild();
+ View headsUpChild = entry.getHeadsUpContentView();
if (headsUpContentView != null && headsUpChild != null) {
headsUpContentView.reapply(mContext, headsUpChild, mOnClickHandler);
}
@@ -2049,7 +2052,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
protected void notifyHeadsUpScreenOff() {
- escalateHeadsUp();
+ maybeEscalateHeadsUp();
}
private boolean alertAgain(Entry oldEntry, Notification newNotification) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index cb8217e..9ef495d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -84,7 +84,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private ExpansionLogger mLogger;
private String mLoggingKey;
private boolean mWasReset;
-
private NotificationGuts mGuts;
private StatusBarNotification mStatusBarNotification;
private boolean mIsHeadsUp;
@@ -102,6 +101,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private ViewStub mGutsStub;
private boolean mHasExpandAction;
private boolean mIsSystemChildExpanded;
+ private boolean mIsPinned;
private OnClickListener mExpandClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
@@ -109,7 +109,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
!mChildrenExpanded);
}
};
- private boolean mInShade;
public NotificationContentView getPrivateLayout() {
return mPrivateLayout;
@@ -284,12 +283,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return realActualHeight;
}
- public void setInShade(boolean inShade) {
- mInShade = inShade;
+ /**
+ * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
+ * the notification will be rendered on top of the screen.
+ *
+ * @param pinned whether it is pinned
+ */
+ public void setPinned(boolean pinned) {
+ mIsPinned = pinned;
}
- public boolean isInShade() {
- return mInShade;
+ public boolean isPinned() {
+ return mIsPinned;
}
public int getHeadsUpHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 1c53655..110b14c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -32,37 +32,34 @@ import android.widget.FrameLayout;
import com.android.systemui.R;
/**
- * A frame layout containing the actual payload of the notification, including the contracted and
- * expanded layout. This class is responsible for clipping the content and and switching between the
- * expanded and contracted view depending on its clipped size.
+ * A frame layout containing the actual payload of the notification, including the contracted,
+ * expanded and heads up layout. This class is responsible for clipping the content and and
+ * switching between the expanded, contracted and the heads up view depending on its clipped size.
*/
public class NotificationContentView extends FrameLayout {
private static final long ANIMATION_DURATION_LENGTH = 170;
- private static final int CONTRACTED = 1;
- private static final int EXPANDED = 2;
- private static final int HEADSUP = 3;
+ private static final int VISIBLE_TYPE_CONTRACTED = 0;
+ private static final int VISIBLE_TYPE_EXPANDED = 1;
+ private static final int VISIBLE_TYPE_HEADSUP = 2;
private final Rect mClipBounds = new Rect();
+ private final int mSmallHeight;
+ private final int mHeadsUpHeight;
+ private final Interpolator mLinearInterpolator = new LinearInterpolator();
private View mContractedChild;
private View mExpandedChild;
private View mHeadsUpChild;
private NotificationViewWrapper mContractedWrapper;
-
- private final int mSmallHeight;
- private final int mHeadsUpHeight;
private int mClipTopAmount;
-
private int mContentHeight;
-
- private final Interpolator mLinearInterpolator = new LinearInterpolator();
- private int mVisibleView = CONTRACTED;
-
+ private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
private boolean mDark;
private final Paint mFadePaint = new Paint();
private boolean mAnimate;
+ private boolean mIsHeadsUp;
private ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
= new ViewTreeObserver.OnPreDrawListener() {
@Override
@@ -72,7 +69,6 @@ public class NotificationContentView extends FrameLayout {
return true;
}
};
- private boolean mIsHeadsUp;
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -105,9 +101,9 @@ public class NotificationContentView extends FrameLayout {
// An actual height is set
size = Math.min(maxSize, layoutParams.height);
}
- int spec = size == Integer.MAX_VALUE ?
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) :
- MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+ int spec = size == Integer.MAX_VALUE
+ ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
+ : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
mExpandedChild.measure(widthMeasureSpec, spec);
maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
}
@@ -153,7 +149,7 @@ public class NotificationContentView extends FrameLayout {
mContractedChild = null;
mExpandedChild = null;
mHeadsUpChild = null;
- mVisibleView = CONTRACTED;
+ mVisibleType = VISIBLE_TYPE_CONTRACTED;
if (resetActualHeight) {
mContentHeight = mSmallHeight;
}
@@ -263,30 +259,32 @@ public class NotificationContentView extends FrameLayout {
if (mContractedChild == null) {
return;
}
- int visibleView = calculateVisibleView();
- if (visibleView != mVisibleView || force) {
- if (animate && mExpandedChild != null) {
- runSwitchAnimation(visibleView);
+ int visibleType = calculateVisibleType();
+ if (visibleType != mVisibleType || force) {
+ if (animate && (visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
+ || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
+ || visibleType == VISIBLE_TYPE_CONTRACTED) {
+ runSwitchAnimation(visibleType);
} else {
- updateViewVisibilities(visibleView);
+ updateViewVisibilities(visibleType);
}
- mVisibleView = visibleView;
+ mVisibleType = visibleType;
}
}
- private void updateViewVisibilities(int visibleView) {
- boolean contractedVisible = visibleView == CONTRACTED;
+ private void updateViewVisibilities(int visibleType) {
+ boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
mContractedChild.setVisibility(contractedVisible ? View.VISIBLE : View.INVISIBLE);
mContractedChild.setAlpha(contractedVisible ? 1f : 0f);
mContractedChild.setLayerType(LAYER_TYPE_NONE, null);
if (mExpandedChild != null) {
- boolean expandedVisible = visibleView == EXPANDED;
+ boolean expandedVisible = visibleType == VISIBLE_TYPE_EXPANDED;
mExpandedChild.setVisibility(expandedVisible ? View.VISIBLE : View.INVISIBLE);
mExpandedChild.setAlpha(expandedVisible ? 1f : 0f);
mExpandedChild.setLayerType(LAYER_TYPE_NONE, null);
}
if (mHeadsUpChild != null) {
- boolean headsUpVisible = visibleView == HEADSUP;
+ boolean headsUpVisible = visibleType == VISIBLE_TYPE_HEADSUP;
mHeadsUpChild.setVisibility(headsUpVisible ? View.VISIBLE : View.INVISIBLE);
mHeadsUpChild.setAlpha(headsUpVisible ? 1f : 0f);
mHeadsUpChild.setLayerType(LAYER_TYPE_NONE, null);
@@ -294,9 +292,9 @@ public class NotificationContentView extends FrameLayout {
setLayerType(LAYER_TYPE_NONE, null);
}
- private void runSwitchAnimation(int visibleView) {
- View shownView = getViewFromFlag(visibleView);
- View hiddenView = getViewFromFlag(mVisibleView);
+ private void runSwitchAnimation(int visibleType) {
+ View shownView = getViewForVisibleType(visibleType);
+ View hiddenView = getViewForVisibleType(mVisibleType);
shownView.setVisibility(View.VISIBLE);
hiddenView.setVisibility(View.VISIBLE);
shownView.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint);
@@ -314,34 +312,42 @@ public class NotificationContentView extends FrameLayout {
.withEndAction(new Runnable() {
@Override
public void run() {
- updateViewVisibilities(mVisibleView);
+ updateViewVisibilities(mVisibleType);
}
});
}
- private View getViewFromFlag(int visibleView) {
- switch (visibleView) {
- case EXPANDED:
+ /**
+ * @param visibleType one of the static enum types in this view
+ * @return the corresponding view according to the given visible type
+ */
+ private View getViewForVisibleType(int visibleType) {
+ switch (visibleType) {
+ case VISIBLE_TYPE_EXPANDED:
return mExpandedChild;
- case HEADSUP:
+ case VISIBLE_TYPE_HEADSUP:
return mHeadsUpChild;
+ default:
+ return mContractedChild;
}
- return mContractedChild;
}
- private int calculateVisibleView() {
+ /**
+ * @return one of the static enum types in this view, calculated form the current state
+ */
+ private int calculateVisibleType() {
boolean noExpandedChild = mExpandedChild == null;
if (mIsHeadsUp && mHeadsUpChild != null) {
if (mContentHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
- return HEADSUP;
+ return VISIBLE_TYPE_HEADSUP;
} else {
- return EXPANDED;
+ return VISIBLE_TYPE_EXPANDED;
}
} else {
if (mContentHeight <= mSmallHeight || noExpandedChild) {
- return CONTRACTED;
+ return VISIBLE_TYPE_CONTRACTED;
} else {
- return EXPANDED;
+ return VISIBLE_TYPE_EXPANDED;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 429889d..2a8b4ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -45,9 +45,6 @@ public class NotificationData {
public StatusBarNotification notification;
public StatusBarIconView icon;
public ExpandableNotificationRow row; // the outer expanded view
- public View expanded; // the inflated RemoteViews
- public View expandedPublic; // for insecure lockscreens
- public View expandedBig;
private boolean interruption;
public boolean autoRedacted; // whether the redacted notification was generated by us
public boolean legacy; // whether the notification has a legacy, dark background
@@ -58,14 +55,6 @@ public class NotificationData {
this.notification = n;
this.icon = ic;
}
- public void setBigContentView(View bigContentView) {
- this.expandedBig = bigContentView;
- row.setExpandable(bigContentView != null);
- }
- public View getBigContentView() {
- return expandedBig;
- }
- public View getPublicContentView() { return expandedPublic; }
public void setInterruption() {
interruption = true;
@@ -81,15 +70,28 @@ public class NotificationData {
public void reset() {
// NOTE: Icon needs to be preserved for now.
// We should fix this at some point.
- expanded = null;
- expandedPublic = null;
- expandedBig = null;
autoRedacted = false;
legacy = false;
if (row != null) {
row.reset();
}
}
+
+ public View getContentView() {
+ return row.getPrivateLayout().getContractedChild();
+ }
+
+ public View getExpandedContentView() {
+ return row.getPrivateLayout().getExpandedChild();
+ }
+
+ public View getHeadsUpContentView() {
+ return row.getPrivateLayout().getHeadsUpChild();
+ }
+
+ public View getPublicContentView() {
+ return row.getPublicLayout().getContractedChild();
+ }
}
private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
@@ -258,7 +260,7 @@ public class NotificationData {
*/
public boolean hasActiveClearableNotifications() {
for (Entry e : mSortedAndFiltered) {
- if (e.expanded != null) { // the view successfully inflated
+ if (e.getContentView() != null) { // the view successfully inflated
if (e.notification.isClearable()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 3997807..fe7bc97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -27,7 +27,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
/**
- * A Helper class to handle touches on the heads-up views
+ * A helper class to handle touches on the heads-up views.
*/
public class HeadsUpTouchHelper implements Gefingerpoken {
@@ -37,19 +37,30 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
private float mTouchSlop;
private float mInitialTouchX;
private float mInitialTouchY;
- private boolean mMotionOnHeadsUpView;
+ private boolean mTouchingHeadsUpView;
private boolean mTrackingHeadsUp;
private boolean mCollapseSnoozes;
private NotificationPanelView mPanel;
private ExpandableNotificationRow mPickedChild;
+ public HeadsUpTouchHelper(HeadsUpManager headsUpManager,
+ NotificationStackScrollLayout stackScroller,
+ NotificationPanelView notificationPanelView) {
+ mHeadsUpManager = headsUpManager;
+ mStackScroller = stackScroller;
+ mPanel = notificationPanelView;
+ Context context = stackScroller.getContext();
+ final ViewConfiguration configuration = ViewConfiguration.get(context);
+ mTouchSlop = configuration.getScaledTouchSlop();
+ }
+
public boolean isTrackingHeadsUp() {
return mTrackingHeadsUp;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (!mMotionOnHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
+ if (!mTouchingHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
return false;
}
int pointerIndex = event.findPointerIndex(mTrackingPointer);
@@ -65,10 +76,10 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
mInitialTouchX = x;
setTrackingHeadsUp(false);
ExpandableView child = mStackScroller.getChildAtPosition(x, y);
- mMotionOnHeadsUpView = false;
+ mTouchingHeadsUpView = false;
if (child instanceof ExpandableNotificationRow) {
mPickedChild = (ExpandableNotificationRow) child;
- mMotionOnHeadsUpView = mPickedChild.isHeadsUp() && !mPickedChild.isInShade();
+ mTouchingHeadsUpView = mPickedChild.isHeadsUp() && mPickedChild.isPinned();
}
break;
case MotionEvent.ACTION_POINTER_UP:
@@ -97,7 +108,8 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
- if (mPickedChild != null && mMotionOnHeadsUpView) {
+ if (mPickedChild != null && mTouchingHeadsUpView) {
+ // We may swallow this click if the heads up just came in.
if (mHeadsUpManager.shouldSwallowClick(
mPickedChild.getStatusBarNotification().getKey())) {
endMotion();
@@ -141,20 +153,6 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
private void endMotion() {
mTrackingPointer = -1;
mPickedChild = null;
- mMotionOnHeadsUpView = false;
- }
-
- public ExpandableView getPickedChild() {
- return mPickedChild;
- }
-
- public void bind(HeadsUpManager headsUpManager, NotificationStackScrollLayout stackScroller,
- NotificationPanelView notificationPanelView) {
- mHeadsUpManager = headsUpManager;
- mStackScroller = stackScroller;
- mPanel = notificationPanelView;
- Context context = stackScroller.getContext();
- final ViewConfiguration configuration = ViewConfiguration.get(context);
- mTouchSlop = configuration.getScaledTouchSlop();
+ mTouchingHeadsUpView = 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 e5ef6ff..fabc1a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -86,7 +86,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private KeyguardAffordanceView mCameraImageView;
private KeyguardAffordanceView mPhoneImageView;
- private KeyguardAffordanceView mLockIcon;
+ private LockIcon mLockIcon;
private TextView mIndicationText;
private ViewGroup mPreviewContainer;
@@ -102,11 +102,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private AccessibilityController mAccessibilityController;
private PhoneStatusBar mPhoneStatusBar;
- private final TrustDrawable mTrustDrawable;
private final Interpolator mLinearOutSlowInInterpolator;
- private int mLastUnlockIconRes = 0;
private boolean mPrewarmSent;
- private boolean mTransientFpError;
public KeyguardBottomAreaView(Context context) {
this(context, null);
@@ -123,7 +120,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mTrustDrawable = new TrustDrawable(mContext);
mLinearOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
}
@@ -169,20 +165,19 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container);
mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button);
- mLockIcon = (KeyguardAffordanceView) findViewById(R.id.lock_icon);
+ mLockIcon = (LockIcon) findViewById(R.id.lock_icon);
mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text);
watchForCameraPolicyChanges();
updateCameraVisibility();
updatePhoneVisibility();
mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
mUnlockMethodCache.addListener(this);
- updateLockIcon();
+ mLockIcon.update();
setClipChildren(false);
setClipToPadding(false);
mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext));
inflatePreviews();
mLockIcon.setOnClickListener(this);
- mLockIcon.setBackground(mTrustDrawable);
mLockIcon.setOnLongClickListener(this);
mCameraImageView.setOnClickListener(this);
mPhoneImageView.setOnClickListener(this);
@@ -222,6 +217,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
public void setAccessibilityController(AccessibilityController accessibilityController) {
mAccessibilityController = accessibilityController;
+ mLockIcon.setAccessibilityController(accessibilityController);
accessibilityController.addStateChangedCallback(this);
}
@@ -233,9 +229,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private Intent getCameraIntent() {
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
boolean currentUserHasTrust = updateMonitor.getUserHasTrust(
- mLockPatternUtils.getCurrentUser());
- return mLockPatternUtils.isSecure() && !currentUserHasTrust
- ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
+ KeyguardUpdateMonitor.getCurrentUser());
+ boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
+ return (secure && !currentUserHasTrust) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
}
private void updateCameraVisibility() {
@@ -245,7 +241,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
PackageManager.MATCH_DEFAULT_ONLY,
- mLockPatternUtils.getCurrentUser());
+ KeyguardUpdateMonitor.getCurrentUser());
boolean visible = !isCameraDisabledByDpm() && resolved != null
&& getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance);
mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
@@ -294,21 +290,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mPhoneImageView.setClickable(touchExplorationEnabled);
mCameraImageView.setFocusable(accessibilityEnabled);
mPhoneImageView.setFocusable(accessibilityEnabled);
- updateLockIconClickability();
- }
-
- private void updateLockIconClickability() {
- if (mAccessibilityController == null) {
- return;
- }
- boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
- boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
- && !mAccessibilityController.isAccessibilityEnabled();
- boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
- && !clickToForceLock;
- mLockIcon.setClickable(clickToForceLock || clickToUnlock);
- mLockIcon.setLongClickable(longClickToForceLock);
- mLockIcon.setFocusable(mAccessibilityController.isAccessibilityEnabled());
+ mLockIcon.update();
}
@Override
@@ -339,13 +321,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
0 /* velocityDp - N/A */);
mIndicationController.showTransientIndication(
R.string.keyguard_indication_trust_disabled);
- mLockPatternUtils.requireCredentialEntry(mLockPatternUtils.getCurrentUser());
+ mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser());
}
public void prewarmCamera() {
Intent intent = getCameraIntent();
String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
- mLockPatternUtils.getCurrentUser());
+ KeyguardUpdateMonitor.getCurrentUser());
if (targetPackage != null) {
Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_PREWARM);
prewarm.setPackage(targetPackage);
@@ -361,7 +343,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mPrewarmSent = false;
Intent intent = getCameraIntent();
String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
- mLockPatternUtils.getCurrentUser());
+ KeyguardUpdateMonitor.getCurrentUser());
if (targetPackage != null) {
Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_COOLDOWN);
prewarm.setPackage(targetPackage);
@@ -375,7 +357,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mPrewarmSent = false;
final Intent intent = getCameraIntent();
boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
- mContext, intent, mLockPatternUtils.getCurrentUser());
+ mContext, intent, KeyguardUpdateMonitor.getCurrentUser());
if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
AsyncTask.execute(new Runnable() {
@Override
@@ -409,69 +391,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
- if (isShown()) {
- mTrustDrawable.start();
- } else {
- mTrustDrawable.stop();
- }
if (changedView == this && visibility == VISIBLE) {
- updateLockIcon();
+ mLockIcon.update();
updateCameraVisibility();
}
}
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mTrustDrawable.stop();
- }
-
- private void updateLockIcon() {
- boolean visible = isShown() && KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
- if (visible) {
- mTrustDrawable.start();
- } else {
- mTrustDrawable.stop();
- }
- if (!visible) {
- return;
- }
- // TODO: Real icon for facelock.
- boolean isFingerprintIcon =
- KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning();
- boolean anyFingerprintIcon = isFingerprintIcon || mTransientFpError;
- int iconRes = mTransientFpError ? R.drawable.ic_fingerprint_error
- : isFingerprintIcon ? R.drawable.ic_fingerprint
- : mUnlockMethodCache.isFaceUnlockRunning()
- ? com.android.internal.R.drawable.ic_account_circle
- : mUnlockMethodCache.isCurrentlyInsecure() ? R.drawable.ic_lock_open_24dp
- : R.drawable.ic_lock_24dp;
-
- if (mLastUnlockIconRes != iconRes) {
- Drawable icon = mContext.getDrawable(iconRes);
- int iconHeight = getResources().getDimensionPixelSize(
- R.dimen.keyguard_affordance_icon_height);
- int iconWidth = getResources().getDimensionPixelSize(
- R.dimen.keyguard_affordance_icon_width);
- if (!anyFingerprintIcon && (icon.getIntrinsicHeight() != iconHeight
- || icon.getIntrinsicWidth() != iconWidth)) {
- icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight);
- }
- mLockIcon.setImageDrawable(icon);
- mLockIcon.setPaddingRelative(0, 0, 0, anyFingerprintIcon
- ? getResources().getDimensionPixelSize(
- R.dimen.fingerprint_icon_additional_padding)
- : 0);
- mLockIcon.setRestingAlpha(
- anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
- }
-
- // Hide trust circle when fingerprint is running.
- boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !anyFingerprintIcon;
- mTrustDrawable.setTrustManaged(trustManaged);
- updateLockIconClickability();
- }
-
public KeyguardAffordanceView getPhoneView() {
return mPhoneImageView;
}
@@ -503,7 +428,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
public void onUnlockMethodStateChanged() {
- updateLockIcon();
+ mLockIcon.update();
updateCameraVisibility();
}
@@ -563,9 +488,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private final Runnable mTransientFpErrorClearRunnable = new Runnable() {
@Override
public void run() {
- mTransientFpError = false;
+ mLockIcon.setTransientFpError(false);
mIndicationController.hideTransientIndication();
- updateLockIcon();
}
};
@@ -578,17 +502,17 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
public void onScreenTurnedOn() {
- updateLockIcon();
+ mLockIcon.update();
}
@Override
public void onScreenTurnedOff(int why) {
- updateLockIcon();
+ mLockIcon.update();
}
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
- updateLockIcon();
+ mLockIcon.update();
}
@Override
@@ -597,24 +521,21 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
public void onFingerprintRunningStateChanged(boolean running) {
- updateLockIcon();
+ mLockIcon.update();
}
@Override
public void onFingerprintHelp(int msgId, String helpString) {
- mTransientFpError = true;
+ mLockIcon.setTransientFpError(true);
mIndicationController.showTransientIndication(helpString,
getResources().getColor(R.color.system_warning_color, null));
removeCallbacks(mTransientFpErrorClearRunnable);
postDelayed(mTransientFpErrorClearRunnable, TRANSIENT_FP_ERROR_TIMEOUT);
- updateLockIcon();
}
@Override
public void onFingerprintError(int msgId, String errString) {
// TODO: Go to bouncer if this is "too many attempts" (lockout) error.
- Log.i(TAG, "FP Error: " + errString);
- updateLockIcon();
}
};
@@ -622,29 +543,4 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
KeyguardIndicationController keyguardIndicationController) {
mIndicationController = keyguardIndicationController;
}
-
- /**
- * A wrapper around another Drawable that overrides the intrinsic size.
- */
- private static class IntrinsicSizeDrawable extends InsetDrawable {
-
- private final int mIntrinsicWidth;
- private final int mIntrinsicHeight;
-
- public IntrinsicSizeDrawable(Drawable drawable, int intrinsicWidth, int intrinsicHeight) {
- super(drawable, 0);
- mIntrinsicWidth = intrinsicWidth;
- mIntrinsicHeight = intrinsicHeight;
- }
-
- @Override
- public int getIntrinsicWidth() {
- return mIntrinsicWidth;
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mIntrinsicHeight;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
new file mode 100644
index 0000000..66f3232
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.KeyguardAffordanceView;
+import com.android.systemui.statusbar.policy.AccessibilityController;
+
+/**
+ * Manages the different states and animations of the unlock icon.
+ */
+public class LockIcon extends KeyguardAffordanceView {
+
+
+ private static final int STATE_LOCKED = 0;
+ private static final int STATE_LOCK_OPEN = 1;
+ private static final int STATE_FACE_UNLOCK = 2;
+ private static final int STATE_FINGERPRINT = 3;
+ private static final int STATE_FINGERPRINT_ERROR = 4;
+
+ private int mLastState = 0;
+ private boolean mTransientFpError;
+ private final TrustDrawable mTrustDrawable;
+ private final UnlockMethodCache mUnlockMethodCache;
+ private AccessibilityController mAccessibilityController;
+
+ public LockIcon(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mTrustDrawable = new TrustDrawable(context);
+ setBackground(mTrustDrawable);
+ mUnlockMethodCache = UnlockMethodCache.getInstance(context);
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ if (isShown()) {
+ mTrustDrawable.start();
+ } else {
+ mTrustDrawable.stop();
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mTrustDrawable.stop();
+ }
+
+ public void setTransientFpError(boolean transientFpError) {
+ mTransientFpError = transientFpError;
+ update();
+ }
+
+ public void update() {
+ boolean visible = isShown() && KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
+ if (visible) {
+ mTrustDrawable.start();
+ } else {
+ mTrustDrawable.stop();
+ }
+ if (!visible) {
+ return;
+ }
+ // TODO: Real icon for facelock.
+ int state = getState();
+ boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR;
+ if (state != mLastState) {
+ int iconRes = getAnimationResForTransition(mLastState, state);
+ if (iconRes == -1) {
+ iconRes = getIconForState(state);
+ }
+ Drawable icon = mContext.getDrawable(iconRes);
+ AnimatedVectorDrawable animation = null;
+ if (icon instanceof AnimatedVectorDrawable) {
+ animation = (AnimatedVectorDrawable) icon;
+ }
+ int iconHeight = getResources().getDimensionPixelSize(
+ R.dimen.keyguard_affordance_icon_height);
+ int iconWidth = getResources().getDimensionPixelSize(
+ R.dimen.keyguard_affordance_icon_width);
+ if (!anyFingerprintIcon && (icon.getIntrinsicHeight() != iconHeight
+ || icon.getIntrinsicWidth() != iconWidth)) {
+ icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight);
+ }
+ setPaddingRelative(0, 0, 0, anyFingerprintIcon
+ ? getResources().getDimensionPixelSize(
+ R.dimen.fingerprint_icon_additional_padding)
+ : 0);
+ setRestingAlpha(
+ anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
+ setImageDrawable(icon);
+ if (animation != null) {
+ animation.start();
+ }
+ }
+
+ // Hide trust circle when fingerprint is running.
+ boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !anyFingerprintIcon;
+ mTrustDrawable.setTrustManaged(trustManaged);
+ mLastState = state;
+ updateClickability();
+ }
+
+ private void updateClickability() {
+ if (mAccessibilityController == null) {
+ return;
+ }
+ boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
+ boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
+ && !mAccessibilityController.isAccessibilityEnabled();
+ boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
+ && !clickToForceLock;
+ setClickable(clickToForceLock || clickToUnlock);
+ setLongClickable(longClickToForceLock);
+ setFocusable(mAccessibilityController.isAccessibilityEnabled());
+ }
+
+ public void setAccessibilityController(AccessibilityController accessibilityController) {
+ mAccessibilityController = accessibilityController;
+ }
+
+ private int getIconForState(int state) {
+ switch (state) {
+ case STATE_LOCKED:
+ return R.drawable.ic_lock_24dp;
+ case STATE_LOCK_OPEN:
+ return R.drawable.ic_lock_open_24dp;
+ case STATE_FACE_UNLOCK:
+ return com.android.internal.R.drawable.ic_account_circle;
+ case STATE_FINGERPRINT:
+ return R.drawable.ic_fingerprint;
+ case STATE_FINGERPRINT_ERROR:
+ return R.drawable.ic_fingerprint_error;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private int getAnimationResForTransition(int oldState, int newState) {
+ if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
+ return R.drawable.lockscreen_fingerprint_error_state_animation;
+ } else {
+ return -1;
+ }
+ }
+
+ private int getState() {
+ boolean fingerprintRunning =
+ KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning();
+ if (mTransientFpError) {
+ return STATE_FINGERPRINT_ERROR;
+ } else if (fingerprintRunning) {
+ return STATE_FINGERPRINT;
+ } else if (mUnlockMethodCache.isFaceUnlockRunning()) {
+ return STATE_FACE_UNLOCK;
+ } else if (mUnlockMethodCache.isCurrentlyInsecure()) {
+ return STATE_LOCK_OPEN;
+ } else {
+ return STATE_LOCKED;
+ }
+ }
+
+ /**
+ * A wrapper around another Drawable that overrides the intrinsic size.
+ */
+ private static class IntrinsicSizeDrawable extends InsetDrawable {
+
+ private final int mIntrinsicWidth;
+ private final int mIntrinsicHeight;
+
+ public IntrinsicSizeDrawable(Drawable drawable, int intrinsicWidth, int intrinsicHeight) {
+ super(drawable, 0);
+ mIntrinsicWidth = intrinsicWidth;
+ mIntrinsicHeight = intrinsicHeight;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mIntrinsicWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mIntrinsicHeight;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b87c25b..8914fb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -182,11 +182,11 @@ public class NotificationPanelView extends PanelView implements
private float mKeyguardStatusBarAnimateAlpha = 1f;
private int mOldLayoutDirection;
- private HeadsUpTouchHelper mHeadsUpTouchHelper = new HeadsUpTouchHelper();
- private boolean mPinnedHeadsUpExist;
- private boolean mExpansionIsFromHeadsUp;
- private int mBottomBarHeight;
+ private HeadsUpTouchHelper mHeadsUpTouchHelper;
+ private boolean mIsExpansionFromHeadsUp;
+ private int mNavigationBarBottomHeight;
private boolean mExpandingFromHeadsUp;
+ private boolean mCollapsedOnDown;
private int mPositionMinSideMargin;
private int mLastOrientation = -1;
@@ -534,17 +534,16 @@ public class NotificationPanelView extends PanelView implements
}
@Override
- public boolean
- onInterceptTouchEvent(MotionEvent event) {
+ public boolean onInterceptTouchEvent(MotionEvent event) {
if (mBlockTouches) {
return false;
}
initDownStates(event);
if (mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
- mExpansionIsFromHeadsUp = true;
+ mIsExpansionFromHeadsUp = true;
return true;
}
- if (!isShadeCollapsed() && onQsIntercept(event)) {
+ if (!isFullyCollapsed() && onQsIntercept(event)) {
return true;
}
return super.onInterceptTouchEvent(event);
@@ -641,6 +640,7 @@ public class NotificationPanelView extends PanelView implements
mOnlyAffordanceInThisMotion = false;
mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
mDozingOnDown = isDozing();
+ mCollapsedOnDown = isFullyCollapsed();
}
}
@@ -695,7 +695,7 @@ public class NotificationPanelView extends PanelView implements
return true;
}
mHeadsUpTouchHelper.onTouchEvent(event);
- if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQSTouch(event)) {
+ if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
return true;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
@@ -705,7 +705,7 @@ public class NotificationPanelView extends PanelView implements
return true;
}
- private boolean handleQSTouch(MotionEvent event) {
+ private boolean handleQsTouch(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
&& mStatusBar.getBarState() != StatusBarState.KEYGUARD && !mQsExpanded
&& mQsExpansionEnabled) {
@@ -718,7 +718,7 @@ public class NotificationPanelView extends PanelView implements
mInitialTouchY = event.getX();
mInitialTouchX = event.getY();
}
- if (!isShadeCollapsed()) {
+ if (!isFullyCollapsed()) {
handleQsDown(event);
}
if (!mQsExpandImmediate && mQsTracking) {
@@ -731,7 +731,7 @@ public class NotificationPanelView extends PanelView implements
|| event.getActionMasked() == MotionEvent.ACTION_UP) {
mConflictingQsExpansionGesture = false;
}
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isShadeCollapsed()
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()
&& mQsExpansionEnabled) {
mTwoFingerQsExpandPossible = true;
}
@@ -1191,8 +1191,8 @@ public class NotificationPanelView extends PanelView implements
updateEmptyShadeView();
mQsNavbarScrim.setVisibility(mStatusBarState == StatusBarState.SHADE && mQsExpanded
&& !mStackScrollerOverscrolling && mQsScrimEnabled
- ? View.VISIBLE
- : View.INVISIBLE);
+ ? View.VISIBLE
+ : View.INVISIBLE);
if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
}
@@ -1386,7 +1386,7 @@ public class NotificationPanelView extends PanelView implements
* @return Whether we should intercept a gesture to open Quick Settings.
*/
private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
- if (!mQsExpansionEnabled) {
+ if (!mQsExpansionEnabled || mCollapsedOnDown) {
return false;
}
View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader;
@@ -1461,8 +1461,8 @@ public class NotificationPanelView extends PanelView implements
updateHeader();
updateUnlockIcon();
updateNotificationTranslucency();
- mHeadsUpManager.setIsExpanded(!isShadeCollapsed());
- mNotificationStackScroller.setShadeExpanded(!isShadeCollapsed());
+ mHeadsUpManager.setIsExpanded(!isFullyCollapsed());
+ mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed());
if (DEBUG) {
invalidate();
}
@@ -1535,21 +1535,19 @@ public class NotificationPanelView extends PanelView implements
float alpha;
if (mExpandingFromHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()) {
alpha = 1f;
- if (mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) {
- mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null);
- }
} else {
alpha = (getNotificationsTopY() + mNotificationStackScroller.getItemHeight())
/ (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
- mNotificationStackScroller.getCollapseSecondCardPadding());
alpha = Math.max(0, Math.min(alpha, 1));
alpha = (float) Math.pow(alpha, 0.75);
- if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) {
- mNotificationStackScroller.setLayerType(LAYER_TYPE_HARDWARE, null);
- } else if (alpha == 1f
- && mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) {
- mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null);
- }
+ }
+
+ if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) {
+ mNotificationStackScroller.setLayerType(LAYER_TYPE_HARDWARE, null);
+ } else if (alpha == 1f
+ && mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) {
+ mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null);
}
mNotificationStackScroller.setAlpha(alpha);
}
@@ -1615,7 +1613,7 @@ public class NotificationPanelView extends PanelView implements
}
float stackTranslation = mNotificationStackScroller.getStackTranslation();
float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR;
- if (mHeadsUpManager.hasPinnedHeadsUp() || mExpansionIsFromHeadsUp) {
+ if (mHeadsUpManager.hasPinnedHeadsUp() || mIsExpansionFromHeadsUp) {
translation = mNotificationStackScroller.getTopPadding() + stackTranslation
- mNotificationTopPadding - mQsMinExpansionHeight;
}
@@ -1683,16 +1681,16 @@ public class NotificationPanelView extends PanelView implements
mHeadsUpManager.onExpandingFinished();
mIsExpanding = false;
mScrollYOverride = -1;
- if (isShadeCollapsed()) {
+ if (isFullyCollapsed()) {
setListening(false);
} else {
setListening(true);
}
mQsExpandImmediate = false;
mTwoFingerQsExpandPossible = false;
- mExpansionIsFromHeadsUp = false;
- mNotificationStackScroller.setTrackingHeadsUp(mHeadsUpTouchHelper.isTrackingHeadsUp());
- mExpandingFromHeadsUp = mHeadsUpTouchHelper.isTrackingHeadsUp();
+ mIsExpansionFromHeadsUp = false;
+ mNotificationStackScroller.setTrackingHeadsUp(false);
+ mExpandingFromHeadsUp = false;
}
private void setListening(boolean listening) {
@@ -1793,13 +1791,13 @@ public class NotificationPanelView extends PanelView implements
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- mBottomBarHeight = insets.getSystemWindowInsetBottom();
+ mNavigationBarBottomHeight = insets.getSystemWindowInsetBottom();
updateMaxHeadsUpTranslation();
return insets;
}
private void updateMaxHeadsUpTranslation() {
- mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mBottomBarHeight);
+ mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mNavigationBarBottomHeight);
}
@Override
@@ -2160,48 +2158,43 @@ public class NotificationPanelView extends PanelView implements
}
@Override
- public void OnPinnedHeadsUpExistChanged(final boolean exist, boolean changeImmediatly) {
- if (exist != mPinnedHeadsUpExist) {
- mPinnedHeadsUpExist = exist;
- if (exist) {
- mHeadsUpExistenceChangedRunnable.run();
- updateNotificationTranslucency();
- } else {
- mNotificationStackScroller.performOnAnimationFinished(
- mHeadsUpExistenceChangedRunnable);
- }
+ public void onPinnedModeChanged(final boolean inPinnedMode) {
+ if (inPinnedMode) {
+ mHeadsUpExistenceChangedRunnable.run();
+ updateNotificationTranslucency();
+ } else {
+ mNotificationStackScroller.runAfterAnimationFinished(
+ mHeadsUpExistenceChangedRunnable);
}
}
@Override
- public void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp) {
- if (isHeadsUp) {
- mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true);
- }
+ public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+ mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true);
}
@Override
- public void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
- mNotificationStackScroller.generateHeadsUpAnimation(entry.row, isHeadsUp);
+ public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
}
@Override
- protected boolean isShadeCollapsed() {
- return mExpandedHeight == 0;
+ public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+ mNotificationStackScroller.generateHeadsUpAnimation(entry.row, isHeadsUp);
}
@Override
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
super.setHeadsUpManager(headsUpManager);
- mHeadsUpTouchHelper.bind(headsUpManager, mNotificationStackScroller, this);
+ mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, mNotificationStackScroller,
+ this);
}
public void setTrackingHeadsUp(boolean tracking) {
if (tracking) {
- // otherwise we update the state when the expansion is finished
mNotificationStackScroller.setTrackingHeadsUp(true);
mExpandingFromHeadsUp = true;
}
+ // otherwise we update the state when the expansion is finished
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 4452dd7..85f312c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -46,13 +46,13 @@ import java.io.PrintWriter;
public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
public static final String TAG = PanelView.class.getSimpleName();
- protected HeadsUpManager mHeadsUpManager;
-
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
}
protected PhoneStatusBar mStatusBar;
+ protected HeadsUpManager mHeadsUpManager;
+
private float mPeekHeight;
private float mHintDistance;
private int mEdgeTapAreaWidth;
@@ -242,15 +242,15 @@ public abstract class PanelView extends FrameLayout {
final float y = event.getY(pointerIndex);
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mGestureWaitForTouchSlop = isShadeCollapsed() || hasConflictingGestures();
- mIgnoreXTouchSlop = isShadeCollapsed() || shouldGestureIgnoreXTouchSlop(x, y);
+ mGestureWaitForTouchSlop = isFullyCollapsed() || hasConflictingGestures();
+ mIgnoreXTouchSlop = isFullyCollapsed() || shouldGestureIgnoreXTouchSlop(x, y);
}
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
mJustPeeked = false;
- mPanelClosedOnDown = isShadeCollapsed();
+ mPanelClosedOnDown = isFullyCollapsed();
mHasLayoutedSinceDown = false;
mUpdateFlingOnLayout = false;
mMotionAborted = false;
@@ -268,7 +268,7 @@ public abstract class PanelView extends FrameLayout {
|| mPeekPending || mPeekAnimator != null;
onTrackingStarted();
}
- if (isShadeCollapsed()) {
+ if (isFullyCollapsed()) {
schedulePeek();
}
break;
@@ -472,7 +472,7 @@ public abstract class PanelView extends FrameLayout {
mTouchSlopExceeded = false;
mJustPeeked = false;
mMotionAborted = false;
- mPanelClosedOnDown = isShadeCollapsed();
+ mPanelClosedOnDown = isFullyCollapsed();
mHasLayoutedSinceDown = false;
mUpdateFlingOnLayout = false;
mTouchAboveFalsingThreshold = false;
@@ -707,7 +707,7 @@ public abstract class PanelView extends FrameLayout {
// If the user isn't actively poking us, let's update the height
if ((!mTracking || isTrackingBlocked())
&& mHeightAnimator == null
- && !isShadeCollapsed()
+ && !isFullyCollapsed()
&& currentMaxPanelHeight != mExpandedHeight
&& !mPeekPending
&& mPeekAnimator == null
@@ -1057,8 +1057,6 @@ public abstract class PanelView extends FrameLayout {
*/
protected abstract int getClearAllHeight();
- protected abstract boolean isShadeCollapsed();
-
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
mHeadsUpManager = headsUpManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index bf85ed5..bf27e84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1152,11 +1152,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public void removeNotification(String key, RankingMap ranking) {
- boolean defferRemoval = false;
+ boolean deferRemoval = false;
if (mHeadsUpManager.isHeadsUp(key)) {
- defferRemoval = !mHeadsUpManager.removeNotification(key);
+ deferRemoval = !mHeadsUpManager.removeNotification(key);
}
- if (defferRemoval) {
+ if (deferRemoval) {
mLatestRankingMap = ranking;
mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
return;
@@ -1293,13 +1293,20 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
updateClearAll();
updateEmptyShadeView();
- // Disable QS if device not provisioned.
- // If the user switcher is simple then disable QS during setup because
- // the user intends to use the lock screen user switcher, QS in not needed.
+ updateQsExpansionEnabled();
+ mShadeUpdates.check();
+ }
+
+ /**
+ * Disable QS if device not provisioned.
+ * If the user switcher is simple then disable QS during setup because
+ * the user intends to use the lock screen user switcher, QS in not needed.
+ */
+ private void updateQsExpansionEnabled() {
mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
&& (mUserSetup || mUserSwitcherController == null
- || !mUserSwitcherController.isSimpleUserSwitcher()));
- mShadeUpdates.check();
+ || !mUserSwitcherController.isSimpleUserSwitcher())
+ && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0));
}
private void updateNotificationShadeForChildren() {
@@ -1732,6 +1739,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
flagdbg.append(((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
flagdbg.append(((state1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
flagdbg.append(((diff1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
+ flagdbg.append(((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "QUICK_SETTINGS"
+ : "quick_settings");
+ flagdbg.append(((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "* " : " ");
flagdbg.append(">");
Log.d(TAG, flagdbg.toString());
@@ -1780,6 +1790,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
(state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
mHeadsUpObserver.onChange(true);
}
+
+ if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
+ updateQsExpansionEnabled();
+ }
}
@Override
@@ -1838,8 +1852,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly) {
- if (exist) {
+ public void onPinnedModeChanged(boolean inPinnedMode) {
+ if (inPinnedMode) {
mStatusBarWindowManager.setHeadsUpShowing(true);
} else {
Runnable endRunnable = new Runnable() {
@@ -1850,20 +1864,24 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
};
- if (changeImmediatly) {
+ if (!mNotificationPanel.isFullyCollapsed()) {
endRunnable.run();
} else {
- mStackScroller.performOnAnimationFinished(endRunnable);
+ mStackScroller.runAfterAnimationFinished(endRunnable);
}
}
}
@Override
- public void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp) {
+ public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+ }
+
+ @Override
+ public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
}
@Override
- public void OnHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
if (!isHeadsUp && mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
removeNotification(entry.key, mLatestRankingMap);
mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
@@ -1880,10 +1898,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
boolean alertAgain) {
final boolean wasHeadsUp = isHeadsUp(key);
if (wasHeadsUp) {
- mHeadsUpManager.updateNotification(entry, alertAgain);
if (!shouldInterrupt) {
// We don't want this to be interrupting anymore, lets remove it
mHeadsUpManager.removeNotification(key);
+ } else {
+ mHeadsUpManager.updateNotification(entry, alertAgain);
}
} else if (shouldInterrupt && alertAgain) {
// This notification was updated to be a heads-up, show it!
@@ -1929,7 +1948,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public void escalateHeadsUp() {
+ public void maybeEscalateHeadsUp() {
TreeSet<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getSortedEntries();
for (HeadsUpManager.HeadsUpEntry entry : entries) {
final StatusBarNotification sbn = entry.entry.notification;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index e701783..ae98e76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -80,7 +80,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
private float mCurrentInFrontAlpha;
private float mCurrentBehindAlpha;
private float mCurrentHeadsUpAlpha = 1;
- private int mAmountOfPinnedHeadsUps;
+ private int mPinnedHeadsUpCount;
private float mTopHeadsUpDragAmount;
private View mDraggedHeadsUpView;
@@ -347,25 +347,27 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
}
@Override
- public void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly) {
+ public void onPinnedModeChanged(boolean inPinnedMode) {
}
@Override
- public void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp) {
- if (isHeadsUp) {
- mAmountOfPinnedHeadsUps++;
- } else {
- mAmountOfPinnedHeadsUps--;
- if (headsUp == mDraggedHeadsUpView) {
- mDraggedHeadsUpView = null;
- mTopHeadsUpDragAmount = 0.0f;
- }
+ public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+ mPinnedHeadsUpCount++;
+ updateHeadsUpScrim(true);
+ }
+
+ @Override
+ public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+ mPinnedHeadsUpCount--;
+ if (headsUp == mDraggedHeadsUpView) {
+ mDraggedHeadsUpView = null;
+ mTopHeadsUpDragAmount = 0.0f;
}
updateHeadsUpScrim(true);
}
@Override
- public void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
}
private void updateHeadsUpScrim(boolean animate) {
@@ -374,12 +376,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
TAG_KEY_ANIM);
float animEndValue = -1;
if (previousAnimator != null) {
- if ((animate || alpha == mCurrentHeadsUpAlpha)) {
- // lets cancel any running animators
+ if (animate || alpha == mCurrentHeadsUpAlpha) {
previousAnimator.cancel();
}
- animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
- TAG_HUN_START_ALPHA);
+ animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, TAG_HUN_START_ALPHA);
}
if (alpha != mCurrentHeadsUpAlpha && alpha != animEndValue) {
if (animate) {
@@ -390,7 +390,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
if (previousAnimator != null) {
float previousStartValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
TAG_HUN_START_ALPHA);
- float previousEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
+ float previousEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
TAG_HUN_END_ALPHA);
// we need to increase all animation keyframes of the previous animator by the
// relative change to the end value
@@ -410,6 +410,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
}
}
+ /**
+ * Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means
+ * the heads up is in its resting space and 1 means it's fully dragged out.
+ *
+ * @param draggedHeadsUpView the dragged view
+ * @param topHeadsUpDragAmount how far is it dragged
+ */
public void setTopHeadsUpDragAmount(View draggedHeadsUpView, float topHeadsUpDragAmount) {
mTopHeadsUpDragAmount = topHeadsUpDragAmount;
mDraggedHeadsUpView = draggedHeadsUpView;
@@ -417,9 +424,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
}
private float calculateHeadsUpAlpha() {
- if (mAmountOfPinnedHeadsUps >= 2) {
+ if (mPinnedHeadsUpCount >= 2) {
return 1.0f;
- } else if (mAmountOfPinnedHeadsUps == 0) {
+ } else if (mPinnedHeadsUpCount == 0) {
return 0.0f;
} else {
return 1.0f - mTopHeadsUpDragAmount;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java
index 4a43c47..45c8938 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java
@@ -27,6 +27,7 @@ import android.provider.MediaStore;
import android.util.Log;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
import java.util.HashMap;
import java.util.List;
@@ -228,7 +229,7 @@ public class SecureCameraLaunchManager {
// Get the list of applications that can handle the intent.
final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
- intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser());
+ intent, PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser());
if (appList.size() == 0) {
if (DEBUG) Log.d(TAG, "No targets found for secure camera intent");
return false;
@@ -237,7 +238,7 @@ public class SecureCameraLaunchManager {
// Get the application that the intent resolves to.
ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
- mLockPatternUtils.getCurrentUser());
+ KeyguardUpdateMonitor.getCurrentUser());
if (resolved == null || resolved.activityInfo == null) {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 65cd268..66d71f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -80,8 +80,8 @@ public class UnlockMethodCache {
}
private void update(boolean updateAlways) {
- int user = mLockPatternUtils.getCurrentUser();
- boolean secure = mLockPatternUtils.isSecure();
+ int user = KeyguardUpdateMonitor.getCurrentUser();
+ boolean secure = mLockPatternUtils.isSecure(user);
boolean currentlyInsecure = !secure || mKeyguardUpdateMonitor.getUserHasTrust(user);
boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
boolean faceUnlockRunning = mKeyguardUpdateMonitor.isFaceUnlockRunning(user)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index b4e4773..8f83daa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -35,11 +35,16 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Stack;
import java.util.TreeSet;
+/**
+ * A manager which handles heads up notifications which is a special mode where
+ * they simply peek from the top of the screen.
+ */
public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsListener {
private static final String TAG = "HeadsUpManager";
private static final boolean DEBUG = false;
@@ -48,7 +53,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
private final int mHeadsUpNotificationDecay;
private final int mMinimumDisplayTime;
- private final int mTouchSensitivityDelay;
+ private final int mTouchAcceptanceDelay;
private final ArrayMap<String, Long> mSnoozedPackages;
private final HashSet<OnHeadsUpChangedListener> mListeners = new HashSet<>();
private final int mDefaultSnoozeLengthMs;
@@ -67,13 +72,12 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
@Override
public boolean release(HeadsUpEntry instance) {
- instance.removeAutoCancelCallbacks();
+ instance.reset();
mPoolObjects.push(instance);
return true;
}
};
-
private PhoneStatusBar mBar;
private int mSnoozeLengthMs;
private ContentObserver mSettingsObserver;
@@ -86,13 +90,12 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
private boolean mTrackingHeadsUp;
private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
private boolean mIsExpanded;
- private boolean mHasPinnedHeadsUp;
+ private boolean mHasPinnedNotification;
private int[] mTmpTwoArray = new int[2];
public HeadsUpManager(final Context context, ViewTreeObserver observer) {
Resources resources = context.getResources();
- mTouchSensitivityDelay = resources.getInteger(R.integer.heads_up_sensitivity_delay);
- if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
+ mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
mSnoozedPackages = new ArrayMap<>();
mDefaultSnoozeLengthMs = resources.getInteger(R.integer.heads_up_default_snooze_length_ms);
mSnoozeLengthMs = mDefaultSnoozeLengthMs;
@@ -116,7 +119,6 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
context.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false,
mSettingsObserver);
- if (DEBUG) Log.v(TAG, "mSnoozeLengthMs = " + mSnoozeLengthMs);
observer.addOnComputeInternalInsetsListener(this);
}
@@ -154,7 +156,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
if (alert) {
HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(headsUp.key);
headsUpEntry.updateEntry();
- setEntryToShade(headsUpEntry, mIsExpanded, false /* justAdded */, false);
+ setEntryPinned(headsUpEntry, !mIsExpanded /* isPinned */);
}
}
@@ -165,22 +167,23 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
headsUpEntry.setEntry(entry);
mHeadsUpEntries.put(entry.key, headsUpEntry);
entry.row.setHeadsUp(true);
- setEntryToShade(headsUpEntry, mIsExpanded /* inShade */, true /* justAdded */, false);
+ setEntryPinned(headsUpEntry, !mIsExpanded /* isPinned */);
for (OnHeadsUpChangedListener listener : mListeners) {
- listener.OnHeadsUpStateChanged(entry, true);
+ listener.onHeadsUpStateChanged(entry, true);
}
entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
}
- private void setEntryToShade(HeadsUpEntry headsUpEntry, boolean inShade, boolean justAdded,
- boolean forceImmediate) {
+ private void setEntryPinned(HeadsUpEntry headsUpEntry, boolean isPinned) {
ExpandableNotificationRow row = headsUpEntry.entry.row;
- if (row.isInShade() != inShade || justAdded) {
- row.setInShade(inShade);
- if (!justAdded || !inShade) {
- updatePinnedHeadsUpState(forceImmediate);
- for (OnHeadsUpChangedListener listener : mListeners) {
- listener.OnHeadsUpPinnedChanged(row, !inShade);
+ if (row.isPinned() != isPinned) {
+ row.setPinned(isPinned);
+ updatePinnedMode();
+ for (OnHeadsUpChangedListener listener : mListeners) {
+ if (isPinned) {
+ listener.onHeadsUpPinned(row);
+ } else {
+ listener.onHeadsUpUnPinned(row);
}
}
}
@@ -189,24 +192,23 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
private void removeHeadsUpEntry(NotificationData.Entry entry) {
HeadsUpEntry remove = mHeadsUpEntries.remove(entry.key);
mSortedEntries.remove(remove);
- mEntryPool.release(remove);
entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
entry.row.setHeadsUp(false);
- setEntryToShade(remove, true /* inShade */, false /* justAdded */,
- false /* forceImmediate */);
+ setEntryPinned(remove, false /* isPinned */);
for (OnHeadsUpChangedListener listener : mListeners) {
- listener.OnHeadsUpStateChanged(entry, false);
+ listener.onHeadsUpStateChanged(entry, false);
}
+ mEntryPool.release(remove);
}
- private void updatePinnedHeadsUpState(boolean forceImmediate) {
- boolean hasPinnedHeadsUp = hasPinnedHeadsUpInternal();
- if (hasPinnedHeadsUp == mHasPinnedHeadsUp) {
+ private void updatePinnedMode() {
+ boolean hasPinnedNotification = hasPinnedNotificationInternal();
+ if (hasPinnedNotification == mHasPinnedNotification) {
return;
}
- mHasPinnedHeadsUp = hasPinnedHeadsUp;
- for (OnHeadsUpChangedListener listener :mListeners) {
- listener.OnPinnedHeadsUpExistChanged(hasPinnedHeadsUp, forceImmediate);
+ mHasPinnedNotification = hasPinnedNotification;
+ for (OnHeadsUpChangedListener listener : mListeners) {
+ listener.onPinnedModeChanged(hasPinnedNotification);
}
}
@@ -222,7 +224,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
releaseImmediately(key);
return true;
} else {
- getHeadsUpEntry(key).hideAsSoonAsPossible();
+ getHeadsUpEntry(key).removeAsSoonAsPossible();
return false;
}
}
@@ -245,14 +247,13 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
return mHeadsUpEntries.containsKey(key);
}
-
/**
* Push any current Heads Up notification down into the shade.
*/
public void releaseAllImmediately() {
if (DEBUG) Log.v(TAG, "releaseAllImmediately");
- HashSet<String> keys = new HashSet<>(mHeadsUpEntries.keySet());
- for (String key: keys) {
+ ArrayList<String> keys = new ArrayList<>(mHeadsUpEntries.keySet());
+ for (String key : keys) {
releaseImmediately(key);
}
}
@@ -280,7 +281,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
}
public void snooze() {
- for (String key: mHeadsUpEntries.keySet()) {
+ for (String key : mHeadsUpEntries.keySet()) {
HeadsUpEntry entry = mHeadsUpEntries.get(key);
String packageName = entry.entry.notification.getPackageName();
mSnoozedPackages.put(snoozeKey(packageName, mUser),
@@ -310,8 +311,11 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
}
/**
+ * Decides whether a click is invalid for a notification, i.e it has not been shown long enough
+ * that a user might have consciously clicked on it.
+ *
* @param key the key of the touched notification
- * @return whether the touch is valid and should not be discarded
+ * @return whether the touch is invalid and should be discarded
*/
public boolean shouldSwallowClick(String key) {
HeadsUpEntry entry = mHeadsUpEntries.get(key);
@@ -322,14 +326,14 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
}
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
- if (!mIsExpanded && mHasPinnedHeadsUp) {
+ if (!mIsExpanded && mHasPinnedNotification) {
int minX = Integer.MAX_VALUE;
int maxX = 0;
int minY = Integer.MAX_VALUE;
int maxY = 0;
- for (HeadsUpEntry entry: mSortedEntries) {
+ for (HeadsUpEntry entry : mSortedEntries) {
ExpandableNotificationRow row = entry.entry.row;
- if (!row.isInShade()) {
+ if (row.isPinned()) {
row.getLocationOnScreen(mTmpTwoArray);
minX = Math.min(minX, mTmpTwoArray[0]);
minY = Math.min(minY, 0);
@@ -349,7 +353,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("HeadsUpManager state:");
- pw.print(" mTouchSensitivityDelay="); pw.println(mTouchSensitivityDelay);
+ pw.print(" mTouchAcceptanceDelay="); pw.println(mTouchAcceptanceDelay);
pw.print(" mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
pw.print(" now="); pw.println(SystemClock.elapsedRealtime());
pw.print(" mUser="); pw.println(mUser);
@@ -365,38 +369,32 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
}
public boolean hasPinnedHeadsUp() {
- return mHasPinnedHeadsUp;
+ return mHasPinnedNotification;
}
- private boolean hasPinnedHeadsUpInternal() {
- for (String key: mHeadsUpEntries.keySet()) {
+ private boolean hasPinnedNotificationInternal() {
+ for (String key : mHeadsUpEntries.keySet()) {
HeadsUpEntry entry = mHeadsUpEntries.get(key);
- if (!entry.entry.row.isInShade()) {
+ if (entry.entry.row.isPinned()) {
return true;
}
}
return false;
}
- public void addSwipedOutKey(String key) {
+ /**
+ * Notifies that a notification was swiped out and will be removed.
+ *
+ * @param key the notification key
+ */
+ public void addSwipedOutNotification(String key) {
mSwipedOutKeys.add(key);
}
- public float getHighestPinnedHeadsUp() {
- float max = 0;
- for (HeadsUpEntry entry: mSortedEntries) {
- if (!entry.entry.row.isInShade()) {
- max = Math.max(max, entry.entry.row.getActualHeight());
- }
- }
- return max;
- }
-
- public void releaseAllToShade() {
- for (String key: mHeadsUpEntries.keySet()) {
+ public void unpinAll() {
+ for (String key : mHeadsUpEntries.keySet()) {
HeadsUpEntry entry = mHeadsUpEntries.get(key);
- setEntryToShade(entry, true /* toShade */, false /* justAdded */,
- true /* forceImmediate */);
+ setEntryPinned(entry, false /* isPinned */);
}
}
@@ -420,7 +418,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
if (isExpanded != mIsExpanded) {
mIsExpanded = isExpanded;
if (isExpanded) {
- releaseAllToShade();
+ unpinAll();
}
}
}
@@ -430,6 +428,12 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
return topEntry != null ? topEntry.entry.row.getHeadsUpHeight() : 0;
}
+ /**
+ * Compare two entries and decide how they should be ranked.
+ *
+ * @return -1 if the first argument should be ranked higher than the second, 1 if the second
+ * one should be ranked higher and 0 if they are equal.
+ */
public int compare(NotificationData.Entry a, NotificationData.Entry b) {
HeadsUpEntry aEntry = getHeadsUpEntry(a.key);
HeadsUpEntry bEntry = getHeadsUpEntry(b.key);
@@ -439,6 +443,11 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
return aEntry.compareTo(bEntry);
}
+
+ /**
+ * This represents a notification and how long it is in a heads up mode. It also manages its
+ * lifecycle automatically when created.
+ */
public class HeadsUpEntry implements Comparable<HeadsUpEntry> {
public NotificationData.Entry entry;
public long postTime;
@@ -449,7 +458,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
this.entry = entry;
// The actual post time will be just after the heads-up really slided in
- postTime = mClock.currentTimeMillis() + mTouchSensitivityDelay;
+ postTime = mClock.currentTimeMillis() + mTouchAcceptanceDelay;
mRemoveHeadsUpRunnable = new Runnable() {
@Override
public void run() {
@@ -467,7 +476,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
long currentTime = mClock.currentTimeMillis();
earliestRemovaltime = currentTime + mMinimumDisplayTime;
postTime = Math.max(postTime, currentTime);
- removeAutoCancelCallbacks();
+ removeAutoRemovalCallbacks();
if (canEntryDecay()) {
long finishTime = postTime + mHeadsUpNotificationDecay;
long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
@@ -487,7 +496,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
: -1;
}
- public void removeAutoCancelCallbacks() {
+ public void removeAutoRemovalCallbacks() {
mHandler.removeCallbacks(mRemoveHeadsUpRunnable);
}
@@ -495,11 +504,17 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
return earliestRemovaltime < mClock.currentTimeMillis();
}
- public void hideAsSoonAsPossible() {
- removeAutoCancelCallbacks();
+ public void removeAsSoonAsPossible() {
+ removeAutoRemovalCallbacks();
mHandler.postDelayed(mRemoveHeadsUpRunnable,
earliestRemovaltime - mClock.currentTimeMillis());
}
+
+ public void reset() {
+ removeAutoRemovalCallbacks();
+ entry = null;
+ mRemoveHeadsUpRunnable = null;
+ }
}
/**
@@ -519,8 +534,29 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
}
public interface OnHeadsUpChangedListener {
- void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly);
- void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp);
- void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp);
+ /**
+ * The state whether there exist pinned heads-ups or not changed.
+ *
+ * @param inPinnedMode whether there are any pinned heads-ups
+ */
+ void onPinnedModeChanged(boolean inPinnedMode);
+
+ /**
+ * A notification was just pinned to the top.
+ */
+ void onHeadsUpPinned(ExpandableNotificationRow headsUp);
+
+ /**
+ * A notification was just unpinned from the top.
+ */
+ void onHeadsUpUnPinned(ExpandableNotificationRow headsUp);
+
+ /**
+ * A notification just became a heads up or turned back to its normal state.
+ *
+ * @param entry the entry of the changed notification
+ * @param isHeadsUp whether the notification is now a headsUp notification
+ */
+ void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
index 0dce82f..5d89e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -26,6 +26,7 @@ import android.view.LayoutInflater;
import android.view.View;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.statusbar.phone.KeyguardPreviewContainer;
import java.util.List;
@@ -80,13 +81,13 @@ public class PreviewInflater {
WidgetInfo info = new WidgetInfo();
PackageManager packageManager = mContext.getPackageManager();
final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
- intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser());
+ intent, PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser());
if (appList.size() == 0) {
return null;
}
ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
- mLockPatternUtils.getCurrentUser());
+ KeyguardUpdateMonitor.getCurrentUser());
if (wouldLaunchResolverActivity(resolved, appList)) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java
new file mode 100644
index 0000000..05c0099
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import android.graphics.Path;
+import android.view.animation.PathInterpolator;
+
+/**
+ * An interpolator specifically designed for the appear animation of heads up notifications.
+ */
+public class HeadsUpAppearInterpolator extends PathInterpolator {
+ public HeadsUpAppearInterpolator() {
+ super(getAppearPath());
+ }
+
+ private static Path getAppearPath() {
+ Path path = new Path();
+ path.moveTo(0, 0);
+ float x1 = 250f;
+ float x2 = 150f;
+ float x3 = 100f;
+ float y1 = 90f;
+ float y2 = 78f;
+ float y3 = 80f;
+ float xTot = (x1 + x2 + x3);
+ path.cubicTo(x1 * 0.9f / xTot, 0f,
+ x1 * 0.8f / xTot, y1 / y3,
+ x1 / xTot , y1 / y3);
+ path.cubicTo((x1 + x2 * 0.4f) / xTot, y1 / y3,
+ (x1 + x2 * 0.2f) / xTot, y2 / y3,
+ (x1 + x2) / xTot, y2 / y3);
+ path.cubicTo((x1 + x2 + x3 * 0.4f) / xTot, y2 / y3,
+ (x1 + x2 + x3 * 0.2f) / xTot, 1f,
+ 1f, 1f);
+ return path;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 88fc602..a1b0cae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -204,7 +204,6 @@ public class NotificationStackScrollLayout extends ViewGroup
private ViewGroup mScrollView;
private boolean mInterceptDelegateEnabled;
private boolean mDelegateToScrollView;
-
private boolean mDisallowScrollingInThisMotion;
private long mGoToFullShadeDelay;
private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
@@ -487,9 +486,9 @@ public class NotificationStackScrollLayout extends ViewGroup
int stackHeight;
float paddingOffset;
boolean trackingHeadsUp = mTrackingHeadsUp;
- int normalExpandPositionStart = trackingHeadsUp ? mHeadsUpManager.getTopHeadsUpHeight()
+ int normalUnfoldPositionStart = trackingHeadsUp ? mHeadsUpManager.getTopHeadsUpHeight()
: minStackHeight;
- if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalExpandPositionStart
+ if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalUnfoldPositionStart
|| getNotGoneChildCount() == 0) {
paddingOffset = mTopPaddingOverflow;
stackHeight = newStackHeight;
@@ -582,7 +581,7 @@ public class NotificationStackScrollLayout extends ViewGroup
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
if (row.isHeadsUp()) {
- mHeadsUpManager.addSwipedOutKey(row.getStatusBarNotification().getKey());
+ mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey());
}
}
final View veto = v.findViewById(R.id.veto);
@@ -626,10 +625,10 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
}
- public boolean isPinnedHeadsUp(View v) {
+ public static boolean isPinnedHeadsUp(View v) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
- return row.isHeadsUp() && !row.isInShade();
+ return row.isHeadsUp() && row.isPinned();
}
return false;
}
@@ -711,7 +710,7 @@ public class NotificationStackScrollLayout extends ViewGroup
if (touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
if (slidingChild instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
- if (row.isHeadsUp() && !row.isInShade()
+ if (row.isHeadsUp() && row.isPinned()
&& mHeadsUpManager.getTopEntry().entry.row != row) {
continue;
}
@@ -812,7 +811,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
- if (!mSwipingInProgress && !mOnlyScrollingInThisMotion && isScrollingEnabled()) {
+ if (mIsExpanded && !mSwipingInProgress && !mOnlyScrollingInThisMotion
+ && isScrollingEnabled()) {
if (isCancelOrUp) {
mExpandHelper.onlyObserveMovements(false);
}
@@ -824,7 +824,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
boolean scrollerWantsIt = false;
- if (!mSwipingInProgress && !mExpandingNotification && !mDisallowScrollingInThisMotion) {
+ if (mIsExpanded && !mSwipingInProgress && !mExpandingNotification
+ && !mDisallowScrollingInThisMotion) {
scrollerWantsIt = onScrollTouch(ev);
}
boolean horizontalSwipeWantsIt = false;
@@ -1872,15 +1873,15 @@ public class NotificationStackScrollLayout extends ViewGroup
boolean onBottom = false;
if (!mIsExpanded && !isHeadsUp) {
type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
- } else if (mAddedHeadsUpChildren.contains(row) || (!row.isInShade() && !mIsExpanded)) {
- if (!row.isInShade() || shouldHunAppearFromBottom(row)) {
+ } else if (mAddedHeadsUpChildren.contains(row) || (row.isPinned() && !mIsExpanded)) {
+ if (row.isPinned() || shouldHunAppearFromBottom(row)) {
// Our custom add animation
type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR;
} else {
// Normal add animation
type = AnimationEvent.ANIMATION_TYPE_ADD;
}
- onBottom = row.isInShade();
+ onBottom = !row.isPinned();
}
AnimationEvent event = new AnimationEvent(row, type);
event.headsUpFromBottom = onBottom;
@@ -2670,7 +2671,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
- public void performOnAnimationFinished(Runnable runnable) {
+ public void runAfterAnimationFinished(Runnable runnable) {
mAnimationFinishedRunnables.add(runnable);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 2a49a4c..202063a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -311,7 +311,8 @@ public class StackScrollAlgorithm {
StackViewState viewState = resultState.getViewStateForView(
nextChild);
// The child below the dragged one must be fully visible
- if (!isPinnedHeadsUpView(draggedView) || isPinnedHeadsUpView(nextChild)) {
+ if (!NotificationStackScrollLayout.isPinnedHeadsUp(draggedView)
+ || NotificationStackScrollLayout.isPinnedHeadsUp(nextChild)) {
viewState.alpha = 1;
}
}
@@ -324,14 +325,6 @@ public class StackScrollAlgorithm {
}
}
- private boolean isPinnedHeadsUpView(View view) {
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- return row.isHeadsUp() && !row.isInShade();
- }
- return false;
- }
-
/**
* Update the visible children on the state.
*/
@@ -380,7 +373,7 @@ public class StackScrollAlgorithm {
/**
* Determine the positions for the views. This is the main part of the algorithm.
*
- * @param resultState The result state to update if a change to the properties of a child occurs
+ * @param resultState The result state to update if a change to the properties of a child occurs
* @param algorithmState The state in which the current pass of the algorithm is currently in
* @param ambientState The current ambient state
*/
@@ -515,11 +508,12 @@ public class StackScrollAlgorithm {
}
StackViewState childState = resultState.getViewStateForView(row);
boolean isTopEntry = topHeadsUpEntry == row;
- if (!row.isInShade()) {
+ if (row.isPinned()) {
childState.yTranslation = 0;
childState.height = row.getHeadsUpHeight();
if (!isTopEntry) {
- // Ensure that a headsUp is never below the topmost headsUp
+ // Ensure that a headsUp doesn't vertically extend further than the heads-up at
+ // the top most z-position
StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
childState.height = row.getHeadsUpHeight();
childState.yTranslation = topState.yTranslation + topState.height
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index f5d94c8..b9466d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -21,11 +21,9 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
-import android.graphics.Path;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -78,6 +76,7 @@ public class StackStateAnimator {
private final Interpolator mFastOutSlowInInterpolator;
private final Interpolator mHeadsUpAppearInterpolator;
private final int mGoToFullShadeAppearingTranslation;
+ private final StackViewState mTmpState = new StackViewState();
public NotificationStackScrollLayout mHostLayout;
private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
new ArrayList<>();
@@ -95,7 +94,6 @@ public class StackStateAnimator {
private ValueAnimator mTopOverScrollAnimator;
private ValueAnimator mBottomOverScrollAnimator;
private ExpandableNotificationRow mChildExpandingView;
- private StackViewState mTmpState = new StackViewState();
private int mHeadsUpAppearHeightBottom;
private boolean mShadeExpanded;
@@ -106,25 +104,7 @@ public class StackStateAnimator {
mGoToFullShadeAppearingTranslation =
hostLayout.getContext().getResources().getDimensionPixelSize(
R.dimen.go_to_full_shade_appearing_translation);
- Path path = new Path();
- path.moveTo(0, 0);
- float x1 = 250f;
- float x2 = 150f;
- float x3 = 100f;
- float y1 = 90f;
- float y2 = 78f;
- float y3 = 80f;
- float xTot = (x1 + x2 + x3);
- path.cubicTo(x1 * 0.9f / xTot, 0f,
- x1 * 0.8f / xTot, y1 / y3,
- x1 / xTot , y1 / y3);
- path.cubicTo((x1 + x2 * 0.4f) / xTot, y1 / y3,
- (x1 + x2 * 0.2f) / xTot, y2 / y3,
- (x1 + x2) / xTot, y2 / y3);
- path.cubicTo((x1 + x2 + x3 * 0.4f) / xTot, y2 / y3,
- (x1 + x2 + x3 * 0.2f) / xTot, 1f,
- 1f, 1f);
- mHeadsUpAppearInterpolator = new PathInterpolator(path);
+ mHeadsUpAppearInterpolator = new HeadsUpAppearInterpolator();
}
public boolean isRunning() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index dda40d3..a5684a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -121,7 +121,7 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- public void escalateHeadsUp() {
+ public void maybeEscalateHeadsUp() {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 240c210..deed895 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -24,11 +24,17 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.MoveCallback;
+import android.os.Handler;
import android.os.UserHandle;
import android.os.storage.DiskInfo;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.util.Log;
import com.android.internal.R;
@@ -39,12 +45,14 @@ import java.util.List;
public class StorageNotification extends SystemUI {
private static final String TAG = "StorageNotification";
- private static final int NOTIF_ID = 0x53544f52; // STOR
+ private static final int PUBLIC_ID = 0x53505542; // SPUB
+ private static final int PRIVATE_ID = 0x53505256; // SPRV
+ private static final int DISK_ID = 0x5344534b; // SDSK
+ private static final int MOVE_ID = 0x534d4f56; // SMOV
private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
// TODO: delay some notifications to avoid bumpy fast operations
- // TODO: annoy user when private media is missing
private NotificationManager mNotificationManager;
private StorageManager mStorageManager;
@@ -52,17 +60,29 @@ public class StorageNotification extends SystemUI {
private final StorageEventListener mListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
- onVolumeStateChangedInternal(vol, oldState, newState);
+ onVolumeStateChangedInternal(vol);
}
@Override
- public void onVolumeMetadataChanged(VolumeInfo vol) {
+ public void onVolumeMetadataChanged(String fsUuid) {
// Avoid kicking notifications when getting early metadata before
// mounted. If already mounted, we're being kicked because of a
// nickname or init'ed change.
- if (vol.isMountedReadable()) {
- onVolumeStateChangedInternal(vol, vol.getState(), vol.getState());
+ final VolumeInfo vol = mStorageManager.findVolumeByUuid(fsUuid);
+ if (vol != null && vol.isMountedReadable()) {
+ onVolumeStateChangedInternal(vol);
}
+
+ final VolumeRecord rec = mStorageManager.findRecordByUuid(fsUuid);
+ if (rec == null) {
+ // Private volume was probably just forgotten
+ mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
+ }
+ }
+
+ @Override
+ public void onDiskScanned(DiskInfo disk, int volumeCount) {
+ onDiskScannedInternal(disk, volumeCount);
}
};
@@ -70,8 +90,19 @@ public class StorageNotification extends SystemUI {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: kick this onto background thread
- final String volId = intent.getStringExtra(VolumeInfo.EXTRA_VOLUME_ID);
- mStorageManager.setVolumeSnoozed(volId, true);
+ final String fsUuid = intent.getStringExtra(VolumeRecord.EXTRA_FS_UUID);
+ mStorageManager.setVolumeSnoozed(fsUuid, true);
+ }
+ };
+
+ private final MoveCallback mMoveCallback = new MoveCallback() {
+ @Override
+ public void onStatusChanged(int moveId, String moveTitle, int status, long estMillis) {
+ if (PackageManager.isMoveStatusFinished(status)) {
+ onMoveFinished(moveId, moveTitle, status);
+ } else {
+ onMoveProgress(moveId, moveTitle, status, estMillis);
+ }
}
};
@@ -88,20 +119,99 @@ public class StorageNotification extends SystemUI {
// Kick current state into place
final List<VolumeInfo> vols = mStorageManager.getVolumes();
for (VolumeInfo vol : vols) {
- onVolumeStateChangedInternal(vol, vol.getState(), vol.getState());
+ onVolumeStateChangedInternal(vol);
}
+
+ mContext.getPackageManager().registerMoveCallback(mMoveCallback, new Handler());
+
+ updateMissingPrivateVolumes();
}
- public void onVolumeStateChangedInternal(VolumeInfo vol, int oldState, int newState) {
- // We only care about public volumes
- if (vol.getType() != VolumeInfo.TYPE_PUBLIC) {
- return;
+ private void updateMissingPrivateVolumes() {
+ final List<VolumeRecord> recs = mStorageManager.getVolumeRecords();
+ for (VolumeRecord rec : recs) {
+ if (rec.getType() != VolumeInfo.TYPE_PRIVATE) continue;
+
+ final String fsUuid = rec.getFsUuid();
+ final VolumeInfo info = mStorageManager.findVolumeByUuid(fsUuid);
+ if (info != null && info.isMountedWritable()) {
+ // Yay, private volume is here!
+ mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
+
+ } else {
+ // Boo, annoy the user to reinsert the private volume
+ final CharSequence title = mContext.getString(R.string.ext_media_missing_title,
+ rec.getNickname());
+ final CharSequence text = mContext.getString(R.string.ext_media_missing_message);
+
+ final Notification notif = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.stat_notify_sdcard)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setLocalOnly(true)
+ .setContentIntent(buildForgetPendingIntent(rec))
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setOngoing(true)
+ .build();
+
+ mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, notif, UserHandle.ALL);
+ }
+ }
+ }
+
+ private void onDiskScannedInternal(DiskInfo disk, int volumeCount) {
+ if (volumeCount == 0) {
+ // No supported volumes found, give user option to format
+ final CharSequence title = mContext.getString(
+ R.string.ext_media_unmountable_notification_title, disk.getDescription());
+ final CharSequence text = mContext.getString(
+ R.string.ext_media_unmountable_notification_message, disk.getDescription());
+
+ final Notification notif = new Notification.Builder(mContext)
+ .setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE))
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setLocalOnly(true)
+ .setContentIntent(buildInitPendingIntent(disk))
+ .setCategory(Notification.CATEGORY_ERROR)
+ .build();
+
+ mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, notif, UserHandle.ALL);
+
+ } else {
+ // Yay, we have volumes!
+ mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
}
+ }
- Log.d(TAG, vol.toString());
+ private void onVolumeStateChangedInternal(VolumeInfo vol) {
+ switch (vol.getType()) {
+ case VolumeInfo.TYPE_PRIVATE:
+ onPrivateVolumeStateChangedInternal(vol);
+ break;
+ case VolumeInfo.TYPE_PUBLIC:
+ onPublicVolumeStateChangedInternal(vol);
+ break;
+ }
+ }
+
+ private void onPrivateVolumeStateChangedInternal(VolumeInfo vol) {
+ Log.d(TAG, "Notifying about private volume: " + vol.toString());
+
+ updateMissingPrivateVolumes();
+ }
+
+ private void onPublicVolumeStateChangedInternal(VolumeInfo vol) {
+ Log.d(TAG, "Notifying about public volume: " + vol.toString());
final Notification notif;
- switch (newState) {
+ switch (vol.getState()) {
case VolumeInfo.STATE_UNMOUNTED:
notif = onVolumeUnmounted(vol);
break;
@@ -133,9 +243,9 @@ public class StorageNotification extends SystemUI {
}
if (notif != null) {
- mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
+ mNotificationManager.notifyAsUser(vol.getId(), PUBLIC_ID, notif, UserHandle.ALL);
} else {
- mNotificationManager.cancelAsUser(vol.getId(), NOTIF_ID, UserHandle.ALL);
+ mNotificationManager.cancelAsUser(vol.getId(), PUBLIC_ID, UserHandle.ALL);
}
}
@@ -159,20 +269,24 @@ public class StorageNotification extends SystemUI {
}
private Notification onVolumeMounted(VolumeInfo vol) {
+ final VolumeRecord rec = mStorageManager.findRecordByUuid(vol.getFsUuid());
+
// Don't annoy when user dismissed in past
- if (vol.isSnoozed()) return null;
+ if (rec.isSnoozed()) return null;
final DiskInfo disk = vol.getDisk();
- if (disk.isAdoptable() && !vol.isInited()) {
+ if (disk.isAdoptable() && !rec.isInited()) {
final CharSequence title = disk.getDescription();
final CharSequence text = mContext.getString(
R.string.ext_media_new_notification_message, disk.getDescription());
+ final PendingIntent initAction = buildInitPendingIntent(vol);
return buildNotificationBuilder(vol, title, text)
.addAction(new Action(0, mContext.getString(R.string.ext_media_init_action),
- buildInitPendingIntent(vol)))
+ initAction))
.addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
buildUnmountPendingIntent(vol)))
+ .setContentIntent(initAction)
.setDeleteIntent(buildSnoozeIntent(vol))
.setCategory(Notification.CATEGORY_SYSTEM)
.build();
@@ -182,11 +296,13 @@ public class StorageNotification extends SystemUI {
final CharSequence text = mContext.getString(
R.string.ext_media_ready_notification_message, disk.getDescription());
+ final PendingIntent browseAction = buildBrowsePendingIntent(vol);
return buildNotificationBuilder(vol, title, text)
.addAction(new Action(0, mContext.getString(R.string.ext_media_browse_action),
- buildBrowsePendingIntent(vol)))
+ browseAction))
.addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
buildUnmountPendingIntent(vol)))
+ .setContentIntent(browseAction)
.setDeleteIntent(buildSnoozeIntent(vol))
.setCategory(Notification.CATEGORY_SYSTEM)
.setPriority(Notification.PRIORITY_LOW)
@@ -260,16 +376,84 @@ public class StorageNotification extends SystemUI {
.build();
}
- private int getSmallIcon(VolumeInfo vol) {
- if (vol.disk.isSd()) {
- switch (vol.getState()) {
+ private void onMoveProgress(int moveId, String moveTitle, int status, long estMillis) {
+ final CharSequence title;
+ if (!TextUtils.isEmpty(moveTitle)) {
+ title = mContext.getString(R.string.ext_media_move_specific_title, moveTitle);
+ } else {
+ title = mContext.getString(R.string.ext_media_move_title);
+ }
+
+ final CharSequence text;
+ if (estMillis < 0) {
+ text = null;
+ } else {
+ text = DateUtils.formatDuration(estMillis);
+ }
+
+ final Notification notif = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.stat_notify_sdcard)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setLocalOnly(true)
+ .setCategory(Notification.CATEGORY_PROGRESS)
+ .setPriority(Notification.PRIORITY_LOW)
+ .setProgress(100, status, false)
+ .setOngoing(true)
+ .build();
+
+ mNotificationManager.notifyAsUser(moveTitle, MOVE_ID, notif, UserHandle.ALL);
+ }
+
+ private void onMoveFinished(int moveId, String moveTitle, int status) {
+ if (!TextUtils.isEmpty(moveTitle)) {
+ // We currently ignore finished app moves; just clear the last
+ // published progress
+ mNotificationManager.cancelAsUser(moveTitle, MOVE_ID, UserHandle.ALL);
+ return;
+ }
+
+ final VolumeInfo vol = mContext.getPackageManager().getPrimaryStorageCurrentVolume();
+ final String descrip = mStorageManager.getBestVolumeDescription(vol);
+
+ final CharSequence title;
+ final CharSequence text;
+ if (status == PackageManager.MOVE_SUCCEEDED) {
+ title = mContext.getString(R.string.ext_media_move_success_title);
+ text = mContext.getString(R.string.ext_media_move_success_message, descrip);
+ } else {
+ title = mContext.getString(R.string.ext_media_move_failure_title);
+ text = mContext.getString(R.string.ext_media_move_failure_message);
+ }
+
+ final Notification notif = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.stat_notify_sdcard)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setLocalOnly(true)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setPriority(Notification.PRIORITY_LOW)
+ .build();
+
+ mNotificationManager.notifyAsUser(moveTitle, MOVE_ID, notif, UserHandle.ALL);
+ }
+
+ private int getSmallIcon(DiskInfo disk, int state) {
+ if (disk.isSd()) {
+ switch (state) {
case VolumeInfo.STATE_CHECKING:
case VolumeInfo.STATE_EJECTING:
return R.drawable.stat_notify_sdcard_prepare;
default:
return R.drawable.stat_notify_sdcard;
}
- } else if (vol.disk.isUsb()) {
+ } else if (disk.isUsb()) {
return R.drawable.stat_sys_data_usb;
} else {
return R.drawable.stat_notify_sdcard;
@@ -279,7 +463,7 @@ public class StorageNotification extends SystemUI {
private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
CharSequence text) {
return new Notification.Builder(mContext)
- .setSmallIcon(getSmallIcon(vol))
+ .setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(text)
@@ -288,6 +472,17 @@ public class StorageNotification extends SystemUI {
.setLocalOnly(true);
}
+ private PendingIntent buildInitPendingIntent(DiskInfo disk) {
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings",
+ "com.android.settings.deviceinfo.StorageWizardInit");
+ intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId());
+
+ final int requestKey = disk.getId().hashCode();
+ return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+ }
+
private PendingIntent buildInitPendingIntent(VolumeInfo vol) {
final Intent intent = new Intent();
intent.setClassName("com.android.settings",
@@ -321,7 +516,7 @@ public class StorageNotification extends SystemUI {
private PendingIntent buildDetailsPendingIntent(VolumeInfo vol) {
final Intent intent = new Intent();
intent.setClassName("com.android.settings",
- "com.android.settings.Settings$StorageVolumeSettingsActivity");
+ "com.android.settings.Settings$PublicVolumeSettingsActivity");
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
final int requestKey = vol.getId().hashCode();
@@ -331,10 +526,21 @@ public class StorageNotification extends SystemUI {
private PendingIntent buildSnoozeIntent(VolumeInfo vol) {
final Intent intent = new Intent(ACTION_SNOOZE_VOLUME);
- intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
+ intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.getFsUuid());
final int requestKey = vol.getId().hashCode();
return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
}
+
+ private PendingIntent buildForgetPendingIntent(VolumeRecord rec) {
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings",
+ "com.android.settings.Settings$PrivateVolumeForgetActivity");
+ intent.putExtra(VolumeRecord.EXTRA_FS_UUID, rec.getFsUuid());
+
+ final int requestKey = rec.getFsUuid().hashCode();
+ return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+ }
}