diff options
author | Danesh M <daneshm90@gmail.com> | 2016-03-28 15:04:29 -0700 |
---|---|---|
committer | Gerrit Code Review <gerrit@cyanogenmod.org> | 2016-04-01 12:51:54 -0700 |
commit | 9a8df5bc8488c19dc0a1951cad44956894a75a09 (patch) | |
tree | 8a2de2c0b8d4337f4b3d4c664ccdca2f1d0fc22f /packages | |
parent | 16a065df515225bf4da78df7ccea63ca860b2b20 (diff) | |
download | frameworks_base-9a8df5bc8488c19dc0a1951cad44956894a75a09.zip frameworks_base-9a8df5bc8488c19dc0a1951cad44956894a75a09.tar.gz frameworks_base-9a8df5bc8488c19dc0a1951cad44956894a75a09.tar.bz2 |
Implement left swipe on lockscreen
Allows user to left swipe to live lockscreen and back.
Change-Id: Ia94d735695b77a091a240e13858641cf95ac0647
Diffstat (limited to 'packages')
16 files changed, 497 insertions, 114 deletions
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java index 77215a7..827b378 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -19,6 +19,7 @@ import android.app.Activity; import android.app.AlertDialog; import android.app.admin.DevicePolicyManager; import android.content.Context; +import android.os.RemoteException; import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; @@ -26,6 +27,7 @@ import android.util.Slog; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; +import android.view.WindowManagerGlobal; import android.widget.FrameLayout; import com.android.internal.widget.LockPatternUtils; @@ -353,6 +355,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } } if (finish) { + try { + WindowManagerGlobal.getWindowManagerService() + .setLiveLockscreenEdgeDetector(false); + } catch (RemoteException e){ + Log.e(TAG, e.getMessage()); + } mSecurityCallback.finish(strongAuth); } return finish; diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index afb98be..82c7965 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -19,9 +19,10 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" android:id="@+id/keyguard_bottom_area" - android:layout_height="match_parent" + android:layout_height="wrap_content" android:layout_width="match_parent" android:outlineProvider="none" + android:visibility="gone" android:elevation="5dp" > <!-- Put it above the status bar header --> <com.android.systemui.statusbar.phone.KeyguardIndicationTextView @@ -39,7 +40,7 @@ <FrameLayout android:id="@+id/preview_container" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="wrap_content"> </FrameLayout> <com.android.systemui.statusbar.KeyguardAffordanceView diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 996fb71..794a755 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -94,10 +94,6 @@ </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer> - <include - layout="@layout/keyguard_bottom_area" - android:visibility="gone" /> - <include layout="@layout/status_bar_expanded_header" /> <com.android.systemui.statusbar.AlphaOptimizedView diff --git a/packages/SystemUI/res/layout/unlock_fab.xml b/packages/SystemUI/res/layout/unlock_fab.xml deleted file mode 100644 index c80bc19..0000000 --- a/packages/SystemUI/res/layout/unlock_fab.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<ImageView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/show_bouncer" - android:layout_width="@dimen/unlock_fab_size" - android:layout_height="@dimen/unlock_fab_size" - android:layout_gravity="bottom|center_horizontal" - android:alpha="0.5" - android:src="@drawable/ic_lock_open_24dp" /> diff --git a/packages/SystemUI/res/values/cm_colors.xml b/packages/SystemUI/res/values/cm_colors.xml index 109b147..5b6e2c0 100644 --- a/packages/SystemUI/res/values/cm_colors.xml +++ b/packages/SystemUI/res/values/cm_colors.xml @@ -122,4 +122,7 @@ <color name="notification_guts_media_bg_color">#ff606060</color> <color name="queue_background">#ff303030</color> <color name="queue_background_pressed">#ff606060</color> + + <color name="live_lockscreen_gradient_start">#00000000</color> + <color name="live_lockscreen_gradient_end">#66000000</color> </resources> diff --git a/packages/SystemUI/res/values/cm_dimens.xml b/packages/SystemUI/res/values/cm_dimens.xml index 5e549f8..60774cd 100644 --- a/packages/SystemUI/res/values/cm_dimens.xml +++ b/packages/SystemUI/res/values/cm_dimens.xml @@ -53,9 +53,6 @@ <dimen name="detail_exterior_padding">8dp</dimen> - <!-- Size of unlock FAB used when showing external keyguard views --> - <dimen name="unlock_fab_size">48dp</dimen> - <dimen name="queue_row_height">52dp</dimen> <dimen name="queue_top_shadow">3dp</dimen> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 33f6564..23e9d8a 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -45,9 +45,15 @@ public class SwipeHelper implements Gefingerpoken { public static final int X = 0; public static final int Y = 1; + public static final int SWIPE_ZONE_LEFT = 0x1; + public static final int SWIPE_ZONE_RIGHT = 0x2; + public static final int SWIPE_ZONE_TOP = 0x4; + public static final int SWIPE_ZONE_BOTTOM = 0x8; private static LinearInterpolator sLinearInterpolator = new LinearInterpolator(); private final Interpolator mFastOutLinearInInterpolator; + private final int mTouchSlop; + private int mSwipeZone; private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms @@ -69,6 +75,7 @@ public class SwipeHelper implements Gefingerpoken { private VelocityTracker mVelocityTracker; private float mInitialTouchPos; + private float mPerpendicularInitialTouchPos; private boolean mDragging; private View mCurrView; private View mCurrAnimView; @@ -91,12 +98,27 @@ public class SwipeHelper implements Gefingerpoken { mVelocityTracker = VelocityTracker.obtain(); mDensityScale = context.getResources().getDisplayMetrics().density; mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop(); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press! mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_linear_in); mFalsingThreshold = context.getResources().getDimensionPixelSize( R.dimen.swipe_helper_falsing_threshold); + if (swipeDirection == X) { + mSwipeZone = SWIPE_ZONE_LEFT | SWIPE_ZONE_RIGHT; + } else { + mSwipeZone = SWIPE_ZONE_TOP | SWIPE_ZONE_BOTTOM; + } + } + + public SwipeHelper(int swipeDirection, int swipeZone, Callback callback, Context context) { + this(swipeDirection, callback, context); + mSwipeZone = swipeZone; + } + + public boolean isDragging() { + return mDragging; } public void setLongPressListener(LongPressListener listener) { @@ -115,6 +137,10 @@ public class SwipeHelper implements Gefingerpoken { return mSwipeDirection == X ? ev.getX() : ev.getY(); } + private float getPerpendicularPos(MotionEvent ev) { + return mSwipeDirection == X ? ev.getY() : ev.getX(); + } + private float getTranslation(View v) { return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY(); } @@ -236,6 +262,7 @@ public class SwipeHelper implements Gefingerpoken { mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView); mVelocityTracker.addMovement(ev); mInitialTouchPos = getPos(ev); + mPerpendicularInitialTouchPos = getPerpendicularPos(ev); if (mLongPressListener != null) { if (mWatchLongPress == null) { @@ -413,11 +440,30 @@ public class SwipeHelper implements Gefingerpoken { case MotionEvent.ACTION_OUTSIDE: case MotionEvent.ACTION_MOVE: if (mCurrView != null) { + float pos = getPos(ev); + float altPos = getPerpendicularPos(ev); float delta = getPos(ev) - mInitialTouchPos; float absDelta = Math.abs(delta); if (absDelta >= getFalsingThreshold()) { mTouchAboveFalsingThreshold = true; } + + boolean touchBeyondZoneLimit = true; + if (mSwipeDirection == X) { + if ((mSwipeZone & SWIPE_ZONE_RIGHT) == 0 && pos > mInitialTouchPos) { + touchBeyondZoneLimit = false; + } else if ((mSwipeZone & SWIPE_ZONE_LEFT) == 0 && pos < mInitialTouchPos) { + touchBeyondZoneLimit = false; + } + } else { + if ((mSwipeZone & SWIPE_ZONE_TOP) == 0 && altPos < mPerpendicularInitialTouchPos) { + touchBeyondZoneLimit = false; + } else if ((mSwipeZone & SWIPE_ZONE_BOTTOM) == 0 && pos > mInitialTouchPos) { + touchBeyondZoneLimit = false; + } + } + if (!touchBeyondZoneLimit) return false; + // don't let items that can't be dismissed be dragged more than // maxScrollDistance if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) { @@ -505,6 +551,49 @@ public class SwipeHelper implements Gefingerpoken { float getFalsingThresholdFactor(); } + public static abstract class SimpleCallback implements Callback { + public abstract View getChildAtPosition(MotionEvent ev); + public abstract View getChildContentView(View v); + + @Override + public boolean canChildBeDismissed(View v) { + return false; + } + + @Override + public boolean isAntiFalsingNeeded() { + return false; + } + + @Override + public void onBeginDrag(View v) { + } + + @Override + public void onChildDismissed(View v) { + } + + @Override + public void onDragCancelled(View v) { + } + + @Override + public void onChildSnappedBack(View animView) { + } + + @Override + public boolean updateSwipeProgress(View animView, + boolean dismissable, + float swipeProgress) { + return false; + } + + @Override + public float getFalsingThresholdFactor() { + return 0; + } + } + /** * Equivalent to View.OnLongClickListener with coordinates */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index d2c60ef..a6ca6a0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -90,6 +90,12 @@ public class KeyguardService extends Service { mKeyguardViewMediator.setOccluded(isOccluded); } + @Override + public void showKeyguard() { + checkPermission(); + mKeyguardViewMediator.showKeyguard(); + } + @Override // Binder interface public void dismiss() { checkPermission(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 06ce8cc..cd94c06 100755 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -351,6 +351,8 @@ public class KeyguardViewMediator extends SystemUI { private IKeyguardDrawnCallback mDrawnCallback; private LockscreenEnabledSettingsObserver mSettingsObserver; + private PhoneStatusBar mStatusBar; + public static class LockscreenEnabledSettingsObserver extends UserContentObserver { private static final String KEY_ENABLED = "lockscreen_enabled"; @@ -1291,6 +1293,15 @@ public class KeyguardViewMediator extends SystemUI { mHandler.sendEmptyMessage(DISMISS); } + public void showKeyguard() { + mHandler.post(new Runnable() { + @Override + public void run() { + mStatusBar.showKeyguard(); + } + }); + } + /** * Send message to keyguard telling it to reset its state. * @see #handleReset @@ -1865,6 +1876,7 @@ public class KeyguardViewMediator extends SystemUI { FingerprintUnlockController fingerprintUnlockController) { mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container, statusBarWindowManager, scrimController, fingerprintUnlockController); + mStatusBar = phoneStatusBar; return mStatusBarKeyguardViewManager; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java index 26b9c8e..902073d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java @@ -187,7 +187,7 @@ public class KeyguardAffordanceView extends ImageView implements Palette.Palette if (mPreviewView != null) { mPreviewView.setVisibility(mLaunchingAffordance ? oldPreviewView.getVisibility() : INVISIBLE); - mPreviewView.setVisibility(INVISIBLE); + mPreviewView.setVisibility(GONE); addOverlay(); } } @@ -386,7 +386,7 @@ public class KeyguardAffordanceView extends ImageView implements Palette.Palette invalidate(); if (nowHidden) { if (mPreviewView != null) { - mPreviewView.setVisibility(View.INVISIBLE); + mPreviewView.setVisibility(View.GONE); } } } else if (!mCircleWillBeHidden) { @@ -425,7 +425,7 @@ public class KeyguardAffordanceView extends ImageView implements Palette.Palette mPreviewClipper.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mPreviewView.setVisibility(View.INVISIBLE); + mPreviewView.setVisibility(View.GONE); } }); mPreviewClipper.start(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java index 60ebfdf..d0e8fbd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java @@ -49,7 +49,7 @@ public class KeyguardAffordanceHelper { private VelocityTracker mVelocityTracker; private boolean mSwipingInProgress; private float mInitialTouchX; - private float mInitialTouchY; + private float mInitialTouchYRaw; private float mTranslation; private float mTranslationOnDown; private int mTouchSlop; @@ -146,7 +146,7 @@ public class KeyguardAffordanceHelper { } startSwiping(targetView); mInitialTouchX = x; - mInitialTouchY = y; + mInitialTouchYRaw = event.getRawY(); mTranslationOnDown = mTranslation; initVelocityTracker(); trackMovement(event); @@ -159,7 +159,7 @@ public class KeyguardAffordanceHelper { case MotionEvent.ACTION_MOVE: trackMovement(event); float xDist = x - mInitialTouchX; - float yDist = y - mInitialTouchY; + float yDist = y - mInitialTouchYRaw; float distance = (float) Math.hypot(xDist, yDist); if (!mTouchSlopExeeded && distance > mTouchSlop) { mTouchSlopExeeded = true; @@ -488,7 +488,7 @@ public class KeyguardAffordanceHelper { float aX = mVelocityTracker.getXVelocity(); float aY = mVelocityTracker.getYVelocity(); float bX = lastX - mInitialTouchX; - float bY = lastY - mInitialTouchY; + float bY = lastY - mInitialTouchYRaw; float bLen = (float) Math.hypot(bX, bY); // Project the velocity onto the distance vector: a * b / |b| float projectedVelocity = (aX * bX + aY * bY) / bLen; 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 d95a46a..8ce84ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -29,14 +29,10 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; -import android.hardware.fingerprint.FingerprintManager; -import android.content.res.Resources; -import android.graphics.Bitmap; +import android.graphics.PixelFormat; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.hardware.fingerprint.FingerprintManager; import android.os.AsyncTask; import android.os.Bundle; import android.os.IBinder; @@ -50,8 +46,11 @@ import android.telecom.TelecomManager; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; @@ -126,6 +125,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private boolean mUserSetupComplete; private boolean mPrewarmBound; private Messenger mPrewarmMessenger; + private final WindowManager mWindowManager; + private boolean mBottomAreaAttached; + private final WindowManager.LayoutParams mWindowLayoutParams; + private OnInterceptTouchEventListener mInterceptTouchListener; + private final ServiceConnection mPrewarmConnection = new ServiceConnection() { @Override @@ -139,6 +143,50 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } }; + @Override + public void setVisibility(int visibility) { + if (visibility != getVisibility()) { + if (visibility == View.VISIBLE) { + if (!mBottomAreaAttached) { + addKeyguardBottomArea(false); + } + } else if (mBottomAreaAttached) { + removeKeyguardBottomArea(); + } + } + super.setVisibility(visibility); + } + + public void expand(boolean expand) { + addKeyguardBottomArea(expand); + } + + private void addKeyguardBottomArea(boolean fullyExpand) { + mWindowLayoutParams.height = fullyExpand ? WindowManager.LayoutParams.MATCH_PARENT : + WindowManager.LayoutParams.WRAP_CONTENT; + if (!mBottomAreaAttached) { + try { + mWindowManager.addView(this, mWindowLayoutParams); + } catch (IllegalStateException e) { + Log.e(TAG, e.getMessage()); + } + mBottomAreaAttached = true; + } else { + mWindowManager.updateViewLayout(this, mWindowLayoutParams); + } + } + + private void removeKeyguardBottomArea() { + if (mBottomAreaAttached) { + try { + mWindowManager.removeViewImmediate(this); + } catch (IllegalArgumentException e) { + Log.e(TAG, e.getMessage()); + } + mBottomAreaAttached = false; + } + } + private AssistManager mAssistManager; public KeyguardBottomAreaView(Context context) { @@ -161,6 +209,18 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL ColorMatrix cm = new ColorMatrix(); cm.setSaturation(0); mGrayScaleFilter = new ColorMatrixColorFilter(cm); + mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + + mWindowLayoutParams = new WindowManager.LayoutParams(); + mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; + mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + mWindowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + mWindowLayoutParams.format = PixelFormat.TRANSPARENT; + mWindowLayoutParams.setTitle("KeyguardBottomArea"); + mWindowLayoutParams.gravity = Gravity.BOTTOM; } private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() { @@ -659,7 +719,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent()); if (mCameraPreview != null) { mPreviewContainer.addView(mCameraPreview); - mCameraPreview.setVisibility(View.INVISIBLE); + mCameraPreview.setVisibility(View.GONE); } } } @@ -681,7 +741,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } if (mLeftPreview != null) { mPreviewContainer.addView(mLeftPreview); - mLeftPreview.setVisibility(View.INVISIBLE); + mLeftPreview.setVisibility(View.GONE); } } @@ -842,4 +902,20 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mShortcutHelper.cleanup(); mUnlockMethodCache.removeListener(this); } + + public interface OnInterceptTouchEventListener { + boolean onInterceptTouchEvent(MotionEvent e); + } + + public void setOnInterceptTouchListener(OnInterceptTouchEventListener listener) { + mInterceptTouchListener = listener; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (mInterceptTouchListener != null) { + return mInterceptTouchListener.onInterceptTouchEvent(ev); + } + return super.onInterceptTouchEvent(ev); + } } 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 98e9566..125e3f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; @@ -27,22 +28,29 @@ import android.app.StatusBarManager; import android.content.Context; import android.content.pm.ResolveInfo; import android.content.res.Configuration; +import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; import android.os.Handler; import android.os.PowerManager; +import android.os.RemoteException; import android.util.AttributeSet; import android.util.MathUtils; +import android.view.Display; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewTreeObserver; import android.view.WindowInsets; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; @@ -56,6 +64,7 @@ import com.android.systemui.DejankUtils; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.R; +import com.android.systemui.SwipeHelper; import com.android.systemui.qs.QSContainer; import com.android.systemui.qs.QSDragPanel; import com.android.systemui.statusbar.ExpandableNotificationRow; @@ -67,6 +76,7 @@ import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; +import com.android.systemui.statusbar.policy.LiveLockScreenController; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.StackStateAnimator; @@ -234,6 +244,86 @@ public class NotificationPanelView extends PanelView implements private int mStatusBarHeaderHeight; private GestureDetector mDoubleTapGesture; + // Used to identify whether showUnlock() can dismiss the keyguard + // or not. + // TODO - add a new state to make it easier to identify keyguard vs + // LiveLockscreen + public boolean mCanDismissKeyguard; + + // Used to track which direction the user is currently + // interacting with and ensure they don't alternate back + // and forth. Reset every MOTION_UP/MOTION_CANCEL + private SwipeLockedDirection mLockedDirection; + + private SwipeHelper mSwipeHelper; + public boolean mShowingExternalKeyguard; + private final int mMinimumFlingVelocity; + private final int mScreenHeight; + private LiveLockScreenController mLiveLockscreenController; + private final GestureDetector mGestureDetector; + + private enum SwipeLockedDirection { + UNKNOWN, + HORIZONTAL, + VERTICAL + } + + // Handles swiping to the LiveLockscreen from keyguard + SwipeHelper.SimpleCallback mSwipeCallback = new SwipeHelper.SimpleCallback() { + @Override + public View getChildAtPosition(MotionEvent ev) { + return mNotificationStackScroller; + } + + @Override + public View getChildContentView(View v) { + return mNotificationStackScroller; + } + + @Override + public boolean canChildBeDismissed(View v) { + return true; + } + + @Override + public void onChildDismissed(View v) { + mShowingExternalKeyguard = true; + mCanDismissKeyguard = false; + mStatusBar.focusKeyguardExternalView(); + resetAlphaTranslation(); + // Enables the left edge gesture to allow user + // to return to keyguard + try { + WindowManagerGlobal.getWindowManagerService() + .setLiveLockscreenEdgeDetector(true); + } catch (RemoteException e){ + e.printStackTrace(); + } + } + + @Override + public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) { + // Let live lockscreen know of swipe progress to allow + // them to translate content in. + mLiveLockscreenController.getLiveLockScreenView() + .onLockscreenSlideOffsetChanged(swipeProgress); + + // Ensures the status view and notifications are kept in sync when + // being swiped away + mKeyguardStatusView.setTranslationX(mNotificationStackScroller.getTranslationX()); + mKeyguardStatusView.setAlpha(mNotificationStackScroller.getAlpha()); + return false; + } + + private void resetAlphaTranslation() { + mNotificationStackScroller.setTranslationX(0); + mNotificationStackScroller.setAlpha(1f); + + mKeyguardStatusView.setTranslationX(0); + mKeyguardStatusView.setAlpha(1f); + } + }; + public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(!DEBUG); @@ -248,12 +338,65 @@ public class NotificationPanelView extends PanelView implements return true; } }); + + Resources res = getContext().getResources(); + final int gradientStart = res.getColor(R.color.live_lockscreen_gradient_start); + final int gradientEnd = res.getColor(R.color.live_lockscreen_gradient_end); + mGestureDetector = new GestureDetector(getContext(), + new GestureDetector.SimpleOnGestureListener() { + public float mDown; + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + // Ensure we only capture swipes in the up direction + if (velocityY > 0 || Math.abs(velocityY) <= mMinimumFlingVelocity) { + return false; + } + mCanDismissKeyguard = true; + mShowingExternalKeyguard = false; + mStatusBar.showBouncer(); + return true; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + float delta = mDown - e2.getRawY(); + float screenHeightHalf = (float) mScreenHeight / 2f; + int color = (Integer) ArgbEvaluator.getInstance() + .evaluate(delta / screenHeightHalf, gradientStart, gradientEnd); + mKeyguardBottomArea.setBackgroundColor(color); + return super.onScroll(e1, e2, distanceX, distanceY); + } + + @Override + public boolean onDown(MotionEvent e) { + mDown = e.getRawY(); + mKeyguardBottomArea.expand(true); + return true; + } + }); + + mSwipeHelper = new SwipeHelper(SwipeHelper.X, + SwipeHelper.SWIPE_ZONE_LEFT, mSwipeCallback, mContext); + mMinimumFlingVelocity = ViewConfiguration.get(getContext()) + .getScaledMinimumFlingVelocity(); + + WindowManager windowManager = (WindowManager) mContext + .getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + Point point = new Point(); + display.getSize(point); + mScreenHeight = point.y; } public void setStatusBar(PhoneStatusBar bar) { mStatusBar = bar; } + public void setLiveController(LiveLockScreenController liveController) { + mLiveLockscreenController = liveController; + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -281,7 +424,51 @@ public class NotificationPanelView extends PanelView implements android.R.interpolator.fast_out_linear_in); mDozeAnimationInterpolator = AnimationUtils.loadInterpolator(getContext(), android.R.interpolator.linear_out_slow_in); - mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area); + + mKeyguardBottomArea = (KeyguardBottomAreaView) View.inflate(getContext(), + R.layout.keyguard_bottom_area, null); + /** Keyguard bottom area lives in a separate window, and as such, + * we must redirect its touch events through the proper flow + */ + mKeyguardBottomArea.setOnInterceptTouchListener(new KeyguardBottomAreaView.OnInterceptTouchEventListener() { + @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + boolean intercept = mAfforanceHelper.onInterceptTouchEvent(e); + if (!intercept) { + if (mShowingExternalKeyguard) { + // Handles swipe up to fade/dismiss when showing + // live lock screen + intercept = mGestureDetector.onTouchEvent(e); + } else { + intercept = NotificationPanelView.this.onInterceptTouchEvent(e); + } + } + return intercept; + } + }); + mKeyguardBottomArea.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent e) { + int action = e.getAction(); + // Ensure we collapse and clear fade + if (action == MotionEvent.ACTION_UP || + action == MotionEvent.ACTION_CANCEL) { + mKeyguardBottomArea.expand(false); + mKeyguardBottomArea.setBackground(null); + } + + boolean intercept = mAfforanceHelper.onTouchEvent(e); + if (!intercept) { + if (mShowingExternalKeyguard) { + intercept = mGestureDetector.onTouchEvent(e); + } else { + intercept = NotificationPanelView.this.onTouchEvent(e); + } + } + return intercept; + } + }); + mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim); mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext()); mLastOrientation = getResources().getConfiguration().orientation; @@ -590,6 +777,10 @@ public class NotificationPanelView extends PanelView implements @Override public boolean onInterceptTouchEvent(MotionEvent event) { + // Reset locked direction + mLockedDirection = SwipeLockedDirection.UNKNOWN; + mCanDismissKeyguard = true; + if (mBlockTouches) { return false; } @@ -611,7 +802,14 @@ public class NotificationPanelView extends PanelView implements if (!isFullyCollapsed() && onQsIntercept(event)) { return true; } - return super.onInterceptTouchEvent(event); + + if (isKeyguardInteractiveAndShowing()) { + return super.onInterceptTouchEvent(event); + } + + // We want both, we really do + return mSwipeHelper.onInterceptTouchEvent(event) + & super.onInterceptTouchEvent(event); } private boolean onQsIntercept(MotionEvent event) { @@ -766,6 +964,13 @@ public class NotificationPanelView extends PanelView implements if (mBlockTouches) { return false; } + + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + mKeyguardBottomArea.expand(false); + mKeyguardBottomArea.setBackground(null); + } + if (mDoubleTapToSleepEnabled && mStatusBarState == StatusBarState.KEYGUARD && event.getY() < mStatusBarHeaderHeight) { @@ -793,8 +998,32 @@ public class NotificationPanelView extends PanelView implements MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1); updateVerticalPanelPosition(event.getX()); } - super.onTouchEvent(event); - return true; + + if (isKeyguardInteractiveAndShowing()) { + super.onTouchEvent(event); + return true; + } + + if (!mSwipeHelper.isDragging() && super.onTouchEvent(event)) { + mLockedDirection = SwipeLockedDirection.VERTICAL; + return true; + } + + if ((!mIsExpanding || mHintAnimationRunning) + && !mQsExpanded + && mLockedDirection != SwipeLockedDirection.VERTICAL + && mStatusBar.getBarState() != StatusBarState.SHADE) { + if (mSwipeHelper.onTouchEvent(event)) { + mLockedDirection = SwipeLockedDirection.HORIZONTAL; + return true; + } + } + return false; + } + + private boolean isKeyguardInteractiveAndShowing() { + return mShowingExternalKeyguard || mStatusBar.getBarState() != StatusBarState.KEYGUARD || + !mLiveLockscreenController.isLiveLockScreenInteractive(); } private boolean handleQsTouch(MotionEvent event) { @@ -1365,8 +1594,7 @@ public class NotificationPanelView extends PanelView implements if (mKeyguardShowing) { updateHeaderKeyguard(); } - if (mStatusBarState == StatusBarState.SHADE_LOCKED - || mStatusBarState == StatusBarState.KEYGUARD) { + if (mStatusBarState == StatusBarState.KEYGUARD) { updateKeyguardBottomAreaAlpha(); } if (mStatusBarState == StatusBarState.SHADE && mQsExpanded @@ -1617,6 +1845,10 @@ public class NotificationPanelView extends PanelView implements updateNotificationTranslucency(); updatePanelExpanded(); mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed()); + if (mShowingExternalKeyguard && expandedHeight >= getMaxPanelHeight()) { + mStatusBar.unfocusKeyguardExternalView(); + mShowingExternalKeyguard = false; + } if (DEBUG) { invalidate(); } @@ -1792,6 +2024,9 @@ public class NotificationPanelView extends PanelView implements alpha = getNotificationsTopY() / (mKeyguardStatusBar.getHeight() + mNotificationsHeaderCollideDistance); + } else if (mStatusBar.getBarState() == StatusBarState.SHADE && + mLiveLockscreenController.isShowingLiveLockScreenView()) { + alpha = 1; } else { // In SHADE_LOCKED, the top card is already really close to the header. Hide it as @@ -2080,11 +2315,13 @@ public class NotificationPanelView extends PanelView implements requestDisallowInterceptTouchEvent(true); mOnlyAffordanceInThisMotion = true; mQsTracking = false; + mKeyguardBottomArea.expand(true); } @Override public void onSwipingAborted() { mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */); + mKeyguardBottomArea.expand(false); } @Override @@ -2462,6 +2699,10 @@ public class NotificationPanelView extends PanelView implements return mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway; } + public KeyguardBottomAreaView getKeyguardBottomArea() { + return mKeyguardBottomArea; + } + class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler) { super(handler); 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 3189d60..949d9d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -17,14 +17,11 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.settings.BrightnessController.BRIGHTNESS_ADJ_RESOLUTION; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManagerNative; -import android.app.ActivityOptions; import android.app.IActivityManager; import android.app.Notification; import android.app.PendingIntent; @@ -103,7 +100,6 @@ import android.view.ViewGroup.LayoutParams; import android.view.ViewStub; import android.view.ViewTreeObserver; import android.view.WindowManager; -import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; @@ -136,10 +132,7 @@ import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.qs.QSDragPanel; -import com.android.systemui.qs.QSPanel; -import com.android.systemui.qs.QSTile; import com.android.systemui.recents.ScreenPinningRequest; -import com.android.systemui.settings.BrightnessController; import com.android.systemui.statusbar.ActivatableNotificationView; import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.BaseStatusBar; @@ -925,6 +918,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } mLiveLockScreenController = new LiveLockScreenController(mContext, this, mNotificationPanel); + mNotificationPanel.setLiveController(mLiveLockScreenController); if (mHeadsUpManager == null) { mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow); @@ -1037,12 +1031,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mHeader.setActivityStarter(this); mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindowContent.findViewById(R.id.keyguard_header); mKeyguardStatusView = mStatusBarWindowContent.findViewById(R.id.keyguard_status_view); - mKeyguardBottomArea = - (KeyguardBottomAreaView) mStatusBarWindowContent.findViewById(R.id.keyguard_bottom_area); + mKeyguardBottomArea = mNotificationPanel.getKeyguardBottomArea(); + mKeyguardBottomArea.setActivityStarter(this); mKeyguardBottomArea.setAssistManager(mAssistManager); mKeyguardIndicationController = new KeyguardIndicationController(mContext, - (KeyguardIndicationTextView) mStatusBarWindowContent.findViewById( + (KeyguardIndicationTextView) mKeyguardBottomArea.findViewById( R.id.keyguard_indication_text), mKeyguardBottomArea.getLockIcon()); mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController); @@ -1971,7 +1965,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - protected void updateRowStates() { + public void updateRowStates() { super.updateRowStates(); mNotificationPanel.notifyVisibleChildrenChanged(); } @@ -4665,8 +4659,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } public void showBouncer() { - if (!mRecreating && - (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { + if (!mRecreating && mNotificationPanel.mCanDismissKeyguard) { mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing(); mStatusBarKeyguardViewManager.dismiss(); } @@ -4681,6 +4674,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } } + protected void unfocusKeyguardExternalView() { + setBarState(StatusBarState.KEYGUARD); + mStatusBarKeyguardViewManager.setKeyguardExternalViewFocus(false); + } + public void focusKeyguardExternalView() { mStatusBarView.collapseAllPanels(/*animate=*/ false, false /* delayed*/, 1.0f /* speedUpFactor */); @@ -4764,10 +4762,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } public void onTrackingStopped(boolean expand) { - if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { + if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED || mStatusBarWindowManager.keyguardExternalViewHasFocus()) { if (!expand && (!mUnlockMethodCache.canSkipBouncer() || mLiveLockScreenController.isShowingLiveLockScreenView())) { - showBouncerOrFocusKeyguardExternalView(); + showBouncer(); } } else if (expand && mStatusBarWindowManager.keyguardExternalViewHasFocus()) { mStatusBarKeyguardViewManager.setKeyguardExternalViewFocus(false); @@ -4777,7 +4775,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override protected int getMaxKeyguardNotifications() { - return mKeyguardMaxNotificationCount; + int max = mKeyguardMaxNotificationCount; + // When an interactive live lockscreen is showing + // we want to limit the number of maximum notifications + // by 1 so there is additional space for the user to dismiss keygard + if (mLiveLockScreenController.isLiveLockScreenInteractive()) { + max--; + } + return max; } public NavigationBarView getNavigationBarView() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 3626b16..5be7d09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -83,8 +83,6 @@ public class StatusBarKeyguardViewManager { private boolean mDeviceWillWakeUp; private boolean mDeferScrimFadeOut; - private View mUnlockFab; - public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback, LockPatternUtils lockPatternUtils) { mContext = context; @@ -257,8 +255,8 @@ public class StatusBarKeyguardViewManager { mOccluded = occluded; mStatusBarWindowManager.setKeyguardOccluded(occluded); mPhoneStatusBar.getVisualizer().setOccluded(occluded); - if (mUnlockFab != null && mUnlockFab.isAttachedToWindow() && !occluded) { - hideUnlockFab(); + if (!occluded) { + mPhoneStatusBar.mKeyguardBottomArea.setVisibility(View.GONE); } reset(false); } @@ -393,20 +391,10 @@ public class StatusBarKeyguardViewManager { } } - /** - * Dismisses the keyguard by going to the next screen or making it gone. - */ public void dismiss() { - dismiss(false); - } - - public void dismiss(boolean focusKeyguardExternalView) { - if ((mDeviceInteractive || mDeviceWillWakeUp) && !focusKeyguardExternalView) { + if ((mDeviceInteractive || mDeviceWillWakeUp)) { showBouncer(); - hideUnlockFab(); - } else if (focusKeyguardExternalView) { - showUnlockFab(); - mStatusBarWindowManager.setKeyguardExternalViewFocus(true); + mPhoneStatusBar.mKeyguardBottomArea.setVisibility(View.GONE); } } @@ -566,7 +554,7 @@ public class StatusBarKeyguardViewManager { false /* delayed */, speedUpFactor); if (mStatusBarWindowManager.keyguardExternalViewHasFocus()) { mStatusBarWindowManager.setKeyguardExternalViewFocus(false); - dismiss(false); + dismiss(); } } @@ -591,50 +579,6 @@ public class StatusBarKeyguardViewManager { } public void setKeyguardExternalViewFocus(boolean hasFocus) { - if (hasFocus) { - showUnlockFab(); - } else { - hideUnlockFab(); - } mStatusBarWindowManager.setKeyguardExternalViewFocus(hasFocus); } - - private void showUnlockFab() { - if (mUnlockFab == null) { - mUnlockFab = View.inflate(mContext, R.layout.unlock_fab, null); - } - if (!mUnlockFab.isAttachedToWindow()) { - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, - WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH - | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS - | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, - PixelFormat.TRANSLUCENT); - lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; - lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - lp.setTitle("UnlockFab"); - lp.packageName = mContext.getPackageName(); - lp.width = lp.height = - mContext.getResources().getDimensionPixelSize(R.dimen.unlock_fab_size); - WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - wm.addView(mUnlockFab, lp); - mUnlockFab.setOnClickListener(mUnlockFabClickListener); - } - } - - private void hideUnlockFab() { - if (mUnlockFab != null && mUnlockFab.isAttachedToWindow()) { - WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - wm.removeViewImmediate(mUnlockFab); - } - } - - private View.OnClickListener mUnlockFabClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - mStatusBarWindowManager.setKeyguardExternalViewFocus(false); - dismiss(false); - } - }; } 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 a338bf3..6d14cbd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java @@ -77,6 +77,7 @@ public class LiveLockScreenController { } } if (mLiveLockScreenView != null && !mLiveLockScreenView.isAttachedToWindow()) { + mBar.updateRowStates(); mPanelView.addView(mLiveLockScreenView, 0); } } @@ -174,6 +175,18 @@ public class LiveLockScreenController { mExternalKeyguardViewCallbacks); mLiveLockScreenView = null; } + + @Override + public void slideLockscreenIn() { + if (mPanelView.mShowingExternalKeyguard) { + mHandler.post(new Runnable() { + @Override + public void run() { + mBar.showKeyguard(); + } + }); + } + } }; public boolean isShowingLiveLockScreenView() { |