summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI
diff options
context:
space:
mode:
authord34d <clark@cyngn.com>2016-06-27 10:57:49 -0700
committerGerrit Code Review <gerrit@cyanogenmod.org>2016-07-21 14:41:02 -0700
commit1c93b57a38aabff28a46eacd56d46bae4c803352 (patch)
treee712c7d9e6c1b6211506a298245403287ef5b541 /packages/SystemUI
parenteee0f89ac8c7afcb3b71d0f669dc3c5eeb118155 (diff)
downloadframeworks_base-1c93b57a38aabff28a46eacd56d46bae4c803352.zip
frameworks_base-1c93b57a38aabff28a46eacd56d46bae4c803352.tar.gz
frameworks_base-1c93b57a38aabff28a46eacd56d46bae4c803352.tar.bz2
SysUI: Add first time use lock screen hints
This adds a set of hints that will be displayed on the keyguard when the screen is turned on. Each of the hints provides the user with a hint on how to interact with the lock screen. Once the user has performed the hinted action the hint should not be shown again. Change-Id: I438316cbf7a01c3f215330a5ca1aed5b78ab3fdc
Diffstat (limited to 'packages/SystemUI')
-rw-r--r--packages/SystemUI/res/drawable/ic_empty_space.xml26
-rw-r--r--packages/SystemUI/res/drawable/ic_keyboard_arrow_down.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_keyboard_arrow_left.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_keyboard_arrow_right.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_keyboard_arrow_up.xml28
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml2
-rw-r--r--packages/SystemUI/res/values/cm_strings.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java94
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java212
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java19
12 files changed, 541 insertions, 9 deletions
diff --git a/packages/SystemUI/res/drawable/ic_empty_space.xml b/packages/SystemUI/res/drawable/ic_empty_space.xml
new file mode 100644
index 0000000..7327894
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_empty_space.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2016 The CyanogenMod 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:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M7.41,7.84 L12,12.42 L16.59,7.84 L18,9.25 L12,15.25 L6,9.25 Z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_keyboard_arrow_down.xml b/packages/SystemUI/res/drawable/ic_keyboard_arrow_down.xml
new file mode 100644
index 0000000..59f9daa
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_keyboard_arrow_down.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2016 The CyanogenMod 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:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M7.41,7.84 L12,12.42 L16.59,7.84 L18,9.25 L12,15.25 L6,9.25 Z" />
+ <path
+ android:pathData="M0,-0.75 L24,-0.75 L24,23.25 L0,23.25 Z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_keyboard_arrow_left.xml b/packages/SystemUI/res/drawable/ic_keyboard_arrow_left.xml
new file mode 100644
index 0000000..182c865
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_keyboard_arrow_left.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2016 The CyanogenMod 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:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M15.41,16.09 L10.83,11.5 L15.41,6.91 L14,5.5 L8,11.5 L14,17.5 Z" />
+ <path
+ android:pathData="M0,-0.5 L24,-0.5 L24,23.5 L0,23.5 Z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_keyboard_arrow_right.xml b/packages/SystemUI/res/drawable/ic_keyboard_arrow_right.xml
new file mode 100644
index 0000000..68e056e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_keyboard_arrow_right.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2016 The CyanogenMod 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:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M8.59,16.34 L13.17,11.75 L8.59,7.16 L10,5.75 L16,11.75 L10,17.75 Z" />
+ <path
+ android:pathData="M0,-0.25 L24,-0.25 L24,23.75 L0,23.75 Z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_keyboard_arrow_up.xml b/packages/SystemUI/res/drawable/ic_keyboard_arrow_up.xml
new file mode 100644
index 0000000..3b222a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_keyboard_arrow_up.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2016 The CyanogenMod 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:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M7.41,15.41 L12,10.83 L16.59,15.41 L18,14 L12,8 L6,14 Z" />
+ <path
+ android:pathData="M0,0 L24,0 L24,24 L0,24 Z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 2c2ad91..20ed3bc 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -26,7 +26,7 @@
<com.android.systemui.statusbar.phone.KeyguardIndicationTextView
android:id="@+id/keyguard_indication_text"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
android:layout_gravity="bottom|center_horizontal"
diff --git a/packages/SystemUI/res/values/cm_strings.xml b/packages/SystemUI/res/values/cm_strings.xml
index 3890de8..2996d21 100644
--- a/packages/SystemUI/res/values/cm_strings.xml
+++ b/packages/SystemUI/res/values/cm_strings.xml
@@ -276,4 +276,8 @@
<!-- Weather string format in keyguard -->
<string name="keyguard_status_view_weather_format"><xliff:g id="temp">%1$s</xliff:g> <xliff:g id="condition">%2$s</xliff:g></string>
+ <string name="expand_hint">Swipe down to expand</string>
+ <string name="swipe_left_hint">Swipe left to <xliff:g id="app_name">%1$s</xliff:g></string>
+ <string name="swipe_right_hint">Swipe right to notifications</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 318ef5e..faf60f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.hardware.fingerprint.FingerprintManager;
@@ -74,12 +75,14 @@ public class KeyguardIndicationController {
private int mChargingSpeed;
private int mChargingCurrent;
private String mMessageToShowOnScreenOn;
+ private IndicationDirection mIndicationDirection;
public KeyguardIndicationController(Context context, KeyguardIndicationTextView textView,
LockIcon lockIcon) {
mContext = context;
mTextView = textView;
mLockIcon = lockIcon;
+ mIndicationDirection = IndicationDirection.NONE;
Resources res = context.getResources();
mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
@@ -121,6 +124,20 @@ public class KeyguardIndicationController {
/**
* Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
*/
+ public void showTransientIndication(int transientIndication, IndicationDirection direction) {
+ showTransientIndication(mContext.getResources().getString(transientIndication), direction);
+ }
+
+ /**
+ * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
+ */
+ public void showTransientIndication(String transientIndication, IndicationDirection direction) {
+ showTransientIndication(transientIndication, Color.WHITE, direction);
+ }
+
+ /**
+ * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
+ */
public void showTransientIndication(int transientIndication) {
showTransientIndication(mContext.getResources().getString(transientIndication));
}
@@ -129,15 +146,24 @@ public class KeyguardIndicationController {
* Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
*/
public void showTransientIndication(String transientIndication) {
- showTransientIndication(transientIndication, Color.WHITE);
+ showTransientIndication(transientIndication, Color.WHITE, IndicationDirection.NONE);
}
/**
* Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
*/
public void showTransientIndication(String transientIndication, int textColor) {
+ showTransientIndication(transientIndication, textColor, IndicationDirection.NONE);
+ }
+
+ /**
+ * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
+ */
+ public void showTransientIndication(String transientIndication, int textColor,
+ IndicationDirection direction) {
mTransientIndication = transientIndication;
mTransientTextColor = textColor;
+ mIndicationDirection = direction;
mHandler.removeMessages(MSG_HIDE_TRANSIENT);
updateIndication();
}
@@ -160,8 +186,30 @@ public class KeyguardIndicationController {
private void updateIndication() {
if (mVisible) {
+ final int color = computeColor();
mTextView.switchIndication(computeIndication());
- mTextView.setTextColor(computeColor());
+ mTextView.setTextColor(color);
+ // pad the bottom using ic_empty_space to keep text vertically aligned
+ int top = 0, bottom = R.drawable.ic_empty_space, left = 0, right = 0;
+ switch (mIndicationDirection) {
+ case UP:
+ top = R.drawable.ic_keyboard_arrow_up;
+ break;
+ case DOWN:
+ bottom = R.drawable.ic_keyboard_arrow_down;
+ break;
+ case LEFT:
+ left = R.drawable.ic_keyboard_arrow_left;
+ break;
+ case RIGHT:
+ right = R.drawable.ic_keyboard_arrow_right;
+ break;
+ case NONE:
+ default:
+ break;
+ }
+ mTextView.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
+ mTextView.setCompoundDrawableTintList(ColorStateList.valueOf(color));
}
}
@@ -176,6 +224,7 @@ public class KeyguardIndicationController {
if (!TextUtils.isEmpty(mTransientIndication)) {
return mTransientIndication;
}
+ mIndicationDirection = IndicationDirection.NONE;
if (mPowerPluggedIn) {
String indication = computePowerIndication();
if (DEBUG_CHARGING_CURRENT) {
@@ -326,4 +375,12 @@ public class KeyguardIndicationController {
StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
}
+
+ public enum IndicationDirection {
+ NONE,
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT
+ }
}
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 a105f24..6992379 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -26,6 +26,7 @@ import android.content.ContentResolver;
import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -39,6 +40,7 @@ import android.net.Uri;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.Display;
@@ -111,6 +113,15 @@ public class NotificationPanelView extends PanelView implements
private static final long SLIDE_PANEL_IN_ANIMATION_DURATION = 300;
+ private static final String KEY_USER_EXPANDED_NOTIFICATIONS_IN_KEYGUARD =
+ "user_expanded_notifications_in_keyguard";
+ private static final String KEY_USER_INTERACTED_WITH_LLS =
+ "user_interacted_with_lls";
+ private static final String KEY_USER_UNLOCKED =
+ "user_unlocked";
+ private static final String KEY_USER_RETURNED_FROM_LLS =
+ "user_returned_from_lls";
+
public static final long DOZE_ANIMATION_DURATION = 700;
@@ -273,6 +284,12 @@ public class NotificationPanelView extends PanelView implements
private TextView mKeyguardWeatherInfo;
private WeatherControllerImpl mWeatherController;
+ // Keep track of common user interactions on the lock screen
+ private boolean mUserUnlocked;
+ private boolean mUserExpandedNotifications;
+ private boolean mUserInteractedWithLiveLockScreen;
+ private boolean mUserReturnedFromLiveLockScreen;
+
private enum SwipeLockedDirection {
UNKNOWN,
HORIZONTAL,
@@ -301,6 +318,13 @@ public class NotificationPanelView extends PanelView implements
mCanDismissKeyguard = false;
mStatusBar.focusKeyguardExternalView();
mLiveLockscreenController.onLiveLockScreenFocusChanged(true /* hasFocus */);
+ if (!mUserInteractedWithLiveLockScreen) {
+ mUserInteractedWithLiveLockScreen = true;
+ saveUserInteractedWithLls(true);
+ }
+ if (!mUserReturnedFromLiveLockScreen) {
+ startShowNotificationsHintAnimation();
+ }
resetAlphaTranslation();
// Enables the left edge gesture to allow user
// to return to keyguard
@@ -400,6 +424,11 @@ public class NotificationPanelView extends PanelView implements
display.getSize(point);
mScreenHeight = point.y;
mUnlockMethodCache = UnlockMethodCache.getInstance(context);
+
+ mUserUnlocked = getUserUnlocked();
+ mUserExpandedNotifications = getUserExpandedNotificationsInKeyguard();
+ mUserInteractedWithLiveLockScreen = getUserInteractedWithLls();
+ mUserReturnedFromLiveLockScreen = getUserReturnedFromLls();
}
public void setStatusBar(PhoneStatusBar bar) {
@@ -1354,8 +1383,13 @@ public class NotificationPanelView extends PanelView implements
mCanDismissKeyguard = true;
}
- if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
- && statusBarState == StatusBarState.SHADE_LOCKED)) {
+ boolean keyguardToShadeLocked = oldState == StatusBarState.KEYGUARD
+ && statusBarState == StatusBarState.SHADE_LOCKED;
+ if (goingToFullShade || keyguardToShadeLocked) {
+ if (keyguardToShadeLocked && !mUserExpandedNotifications) {
+ mUserExpandedNotifications = true;
+ saveUserExpandedNotificationsInKeyguard(true);
+ }
animateKeyguardStatusBarOut();
animateHeaderSlidingIn();
} else if (oldState == StatusBarState.SHADE_LOCKED
@@ -1370,6 +1404,11 @@ public class NotificationPanelView extends PanelView implements
mAfforanceHelper.updatePreviews();
}
}
+ if (oldState != StatusBarState.SHADE && statusBarState == StatusBarState.SHADE &&
+ !mUserUnlocked) {
+ mUserUnlocked = true;
+ saveUserUnlocked(true);
+ }
if (statusBarState == StatusBarState.KEYGUARD ||
statusBarState == StatusBarState.SHADE_LOCKED) {
updateDozingVisibilities(false /* animate */);
@@ -2386,6 +2425,7 @@ public class NotificationPanelView extends PanelView implements
}
mHintAnimationRunning = true;
mKeyguardBottomArea.expand(true);
+ mKeyguardBottomArea.getIndicationView().animate().cancel();
mAfforanceHelper.startHintAnimation(rightIcon, new Runnable() {
@Override
public void run() {
@@ -2589,6 +2629,9 @@ public class NotificationPanelView extends PanelView implements
public void onScreenTurningOn() {
mKeyguardStatusView.refreshTime();
+ startScreenOnHintAnimation(mLiveLockscreenController.isLiveLockScreenInteractive() &&
+ !mUserInteractedWithLiveLockScreen,
+ !mUserUnlocked, !mUserExpandedNotifications);
}
@Override
@@ -2974,5 +3017,52 @@ public class NotificationPanelView extends PanelView implements
animator.addUpdateListener(mSlideInAnimationListener);
animator.addListener(mSlideInAnimationListener);
animator.start();
+
+ if (!mUserReturnedFromLiveLockScreen) {
+ mUserReturnedFromLiveLockScreen = true;
+ saveUserReturnedFromLls(true);
+ }
+ }
+
+ private void saveBooleanSharedPreference(String key, boolean value) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+ prefs.edit().putBoolean(key, value).apply();
+ }
+
+ private boolean getSharedPreferenceBoolean(String key, boolean defValue) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+ return prefs.getBoolean(key, defValue);
+ }
+
+ private void saveUserExpandedNotificationsInKeyguard(boolean expanded) {
+ saveBooleanSharedPreference(KEY_USER_EXPANDED_NOTIFICATIONS_IN_KEYGUARD, expanded);
+ }
+
+ private boolean getUserExpandedNotificationsInKeyguard() {
+ return getSharedPreferenceBoolean(KEY_USER_EXPANDED_NOTIFICATIONS_IN_KEYGUARD, false);
+ }
+
+ private void saveUserInteractedWithLls(boolean interacted) {
+ saveBooleanSharedPreference(KEY_USER_INTERACTED_WITH_LLS, interacted);
+ }
+
+ private boolean getUserInteractedWithLls() {
+ return getSharedPreferenceBoolean(KEY_USER_INTERACTED_WITH_LLS, false);
+ }
+
+ private void saveUserUnlocked(boolean unlocked) {
+ saveBooleanSharedPreference(KEY_USER_UNLOCKED, unlocked);
+ }
+
+ private boolean getUserUnlocked() {
+ return getSharedPreferenceBoolean(KEY_USER_UNLOCKED, false);
+ }
+
+ private void saveUserReturnedFromLls(boolean revealed) {
+ saveBooleanSharedPreference(KEY_USER_RETURNED_FROM_LLS, revealed);
+ }
+
+ private boolean getUserReturnedFromLls() {
+ return getSharedPreferenceBoolean(KEY_USER_RETURNED_FROM_LLS, false);
}
}
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 ae565ed..638a5d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -49,6 +49,9 @@ public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
public static final String TAG = PanelView.class.getSimpleName();
+ private static final long ANIMATION_FADE_DURATION = 1000L;
+ private static final long HINT_DELAY_DURATION = 1500L;
+
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
}
@@ -121,6 +124,9 @@ public abstract class PanelView extends FrameLayout {
private boolean mPeekPending;
private boolean mCollapseAfterPeek;
+ private boolean mShowExpandHint;
+ private boolean mShowUnlockHint;
+ private boolean mScreenOnHintAnimationRunning;
/**
* Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time.
@@ -928,6 +934,7 @@ public abstract class PanelView extends FrameLayout {
private void abortAnimations() {
cancelPeek();
cancelHeightAnimator();
+ mKeyguardBottomArea.getIndicationView().animate().cancel();
removeCallbacks(mPostCollapseRunnable);
removeCallbacks(mFlingCollapseRunnable);
}
@@ -946,6 +953,8 @@ public abstract class PanelView extends FrameLayout {
}
cancelPeek();
notifyExpandingStarted();
+ mKeyguardBottomArea.getIndicationView().animate().cancel();
+ mStatusBar.onUnlockHintStarted();
startUnlockHintAnimationPhase1(new Runnable() {
@Override
public void run() {
@@ -954,8 +963,8 @@ public abstract class PanelView extends FrameLayout {
mHintAnimationRunning = false;
}
});
- mStatusBar.onUnlockHintStarted();
mHintAnimationRunning = true;
+ mShowExpandHint = false;
}
/**
@@ -989,6 +998,7 @@ public abstract class PanelView extends FrameLayout {
mKeyguardBottomArea.getIndicationView().animate()
.translationY(-mHintDistance)
.setDuration(250)
+ .setStartDelay(0)
.setInterpolator(mFastOutSlowInInterpolator)
.withEndAction(new Runnable() {
@Override
@@ -1011,17 +1021,213 @@ public abstract class PanelView extends FrameLayout {
animator.setDuration(450);
animator.setInterpolator(mBounceInterpolator);
animator.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
mHeightAnimator = null;
- onAnimationFinished.run();
- notifyBarPanelExpansionChanged();
+ if (mCancelled) {
+ onAnimationFinished.run();
+ } else {
+ if (mShowExpandHint) {
+ startUnlockHintFadeOutAnimationPhase(onAnimationFinished);
+ } else {
+ onAnimationFinished.run();
+ notifyBarPanelExpansionChanged();
+ }
+ }
}
});
animator.start();
mHeightAnimator = animator;
}
+ /**
+ * Fade in unlock hint
+ */
+ private void startUnlockHintFadeInAnimationPhase(final Runnable onAnimationFinished) {
+ mStatusBar.onUnlockHintStarted();
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(1)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(0)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ if (mShowExpandHint) {
+ startUnlockHintFadeOutAnimationPhase(onAnimationFinished);
+ } else {
+ onAnimationFinished.run();
+ notifyBarPanelExpansionChanged();
+ }
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Fade out unlock hint
+ */
+ private void startUnlockHintFadeOutAnimationPhase(final Runnable onAnimationFinished) {
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(0)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(HINT_DELAY_DURATION)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ startExpandHintAnimation(onAnimationFinished);
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Fade in Lls hint
+ */
+ private void startLlsHintFadeInAnimationPhase(final Runnable onAnimationFinished) {
+ mKeyguardBottomArea.getIndicationView().setAlpha(0);
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(1)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(0)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ if (mShowUnlockHint || mShowExpandHint) {
+ startLlsHintFadeOutAnimationPhase(onAnimationFinished);
+ } else {
+ onAnimationFinished.run();;
+ }
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Fade out Lls hint
+ */
+ private void startLlsHintFadeOutAnimationPhase(final Runnable onAnimationFinished) {
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(0)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(HINT_DELAY_DURATION)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ if (mShowUnlockHint) {
+ startUnlockHintFadeInAnimationPhase(onAnimationFinished);
+ } else if (mShowExpandHint) {
+ startExpandHintAnimation(onAnimationFinished);
+ } else {
+ onAnimationFinished.run();
+ }
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Fade in expand hint
+ */
+ private void startExpandHintAnimation(final Runnable onAnimationFinished) {
+ mStatusBar.onExpandHintStarted();
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(1)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setStartDelay(0)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ onAnimationFinished.run();
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Show notifications hint (swipe right hint)
+ */
+ protected void startShowNotificationsHintAnimation() {
+ cancelPeek();
+ mStatusBar.onNotificationsHintStarted();
+ mHintAnimationRunning = true;
+ mKeyguardBottomArea.getIndicationView().setAlpha(0);
+ mKeyguardBottomArea.getIndicationView().animate()
+ .alpha(1)
+ .setDuration(ANIMATION_FADE_DURATION)
+ .setInterpolator(null)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ mStatusBar.onHintFinished();
+ mHintAnimationRunning = false;
+ }
+ })
+ .start();
+ }
+
+ protected void startScreenOnHintAnimation(boolean showSwipeLeftHint, boolean showUnlockHint,
+ boolean showExpandHint) {
+ // We don't need to hint the user if an animation is already running or the user is changing
+ // the expansion.
+ if (mHintAnimationRunning || mScreenOnHintAnimationRunning) return;
+
+ final View indicationView = mKeyguardBottomArea.getIndicationView();
+ indicationView.animate().cancel();
+ indicationView.animate().setListener(
+ new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) { }
+
+ @Override
+ public void onAnimationEnd(Animator animation) { }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mScreenOnHintAnimationRunning = false;
+ indicationView.setAlpha(1f);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) { }
+ });
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ mStatusBar.onHintFinished();
+ mScreenOnHintAnimationRunning = false;
+ }
+ };
+ if (showSwipeLeftHint) {
+ mStatusBar.onLlsHintStarted();
+ startLlsHintFadeInAnimationPhase(r);
+ } else if (showUnlockHint) {
+ mStatusBar.onUnlockHintStarted();
+ startUnlockHintFadeInAnimationPhase(r);
+ } else if (showExpandHint) {
+ mStatusBar.onExpandHintStarted();
+ startExpandHintAnimation(r);
+ } else {
+ return;
+ }
+ indicationView.setAlpha(0);
+ mShowUnlockHint = showUnlockHint;
+ mShowExpandHint = showExpandHint;
+ mScreenOnHintAnimationRunning = true;
+ }
+
private ValueAnimator createHeightAnimator(float targetHeight) {
ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, targetHeight);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
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 d435f20..8f06328 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -4795,7 +4795,25 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
public void onUnlockHintStarted() {
- mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
+ mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock,
+ KeyguardIndicationController.IndicationDirection.UP);
+ }
+
+ public void onLlsHintStarted() {
+ String llsName = mLiveLockScreenController.getLiveLockScreenName();
+ mKeyguardIndicationController.showTransientIndication(
+ mContext.getString(R.string.swipe_left_hint, llsName),
+ KeyguardIndicationController.IndicationDirection.LEFT);
+ }
+
+ public void onExpandHintStarted() {
+ mKeyguardIndicationController.showTransientIndication(R.string.expand_hint,
+ KeyguardIndicationController.IndicationDirection.DOWN);
+ }
+
+ public void onNotificationsHintStarted() {
+ mKeyguardIndicationController.showTransientIndication(R.string.swipe_right_hint,
+ KeyguardIndicationController.IndicationDirection.RIGHT);
}
public void onHintFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java
index ccbe911..69720ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java
@@ -3,6 +3,8 @@ package com.android.systemui.statusbar.policy;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
@@ -43,6 +45,8 @@ public class LiveLockScreenController {
private boolean mScreenOnAndInteractive;
+ private String mLlsName;
+
public LiveLockScreenController(Context context, PhoneStatusBar bar,
NotificationPanelView panelView) {
mContext = context;
@@ -265,6 +269,20 @@ public class LiveLockScreenController {
return mLlsHasFocus;
}
+ public String getLiveLockScreenName() {
+ return mLlsName;
+ }
+
+ private String getLlsNameFromComponentName(ComponentName cn) {
+ if (cn == null) return null;
+
+ PackageManager pm = mContext.getPackageManager();
+ Intent intent = new Intent();
+ intent.setComponent(cn);
+ ResolveInfo ri = pm.resolveService(intent, 0);
+ return ri != null ? ri.serviceInfo.loadLabel(pm).toString() : null;
+ }
+
private Runnable mAddNewLiveLockScreenRunnable = new Runnable() {
@Override
public void run() {
@@ -290,6 +308,7 @@ public class LiveLockScreenController {
// If mThirdPartyKeyguardViewComponent differs from cn, go ahead and update
if (!Objects.equals(mLiveLockScreenComponentName, cn)) {
mLiveLockScreenComponentName = cn;
+ mLlsName = getLlsNameFromComponentName(cn);
if (mLiveLockScreenView != null) {
mLiveLockScreenView.unregisterKeyguardExternalViewCallback(
mExternalKeyguardViewCallbacks);