summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI')
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java158
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivatable.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java119
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java19
14 files changed, 446 insertions, 49 deletions
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c6298de..2f2914c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -268,4 +268,7 @@
<dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen>
<dimen name="notifications_top_padding">8dp</dimen>
+
+ <!-- Minimum distance the user has to drag down to go to the full shade. -->
+ <dimen name="keyguard_drag_down_min_distance">100dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 0f32dc0..5a55292 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -88,14 +88,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
if (mDownY > getActualHeight()) {
return false;
}
-
- // Call the listener tentatively directly, even if we don't know whether the user
- // will stay within the touch slop, as the listener is implemented as a scale
- // animation, which is cancellable without jarring effects when swiping away
- // notifications.
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onActivated(this);
- }
break;
case MotionEvent.ACTION_MOVE:
if (!isWithinTouchSlop(event)) {
@@ -109,8 +101,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
makeActive(event.getX(), event.getY());
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
} else {
- performClick();
makeInactive();
+ performClick();
}
} else {
makeInactive();
@@ -128,6 +120,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private void makeActive(float x, float y) {
mCustomBackground.setHotspot(0, x, y);
mActivated = true;
+ if (mOnActivatedListener != null) {
+ mOnActivatedListener.onActivated(this);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 9149e2d..829cee4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -167,7 +167,11 @@ public abstract class BaseStatusBar extends SystemUI implements
protected int mZenMode;
- protected boolean mOnKeyguard;
+ /**
+ * The {@link StatusBarState} of the status bar.
+ */
+ protected int mState;
+
protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
public boolean isDeviceProvisioned() {
@@ -1057,9 +1061,10 @@ public abstract class BaseStatusBar extends SystemUI implements
mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
int n = mNotificationData.size();
int visibleNotifications = 0;
+ boolean onKeyguard = mState == StatusBarState.KEYGUARD;
for (int i = n-1; i >= 0; i--) {
NotificationData.Entry entry = mNotificationData.get(i);
- if (mOnKeyguard) {
+ if (onKeyguard) {
entry.row.setExpansionDisabled(true);
} else {
entry.row.setExpansionDisabled(false);
@@ -1068,10 +1073,10 @@ public abstract class BaseStatusBar extends SystemUI implements
entry.row.setSystemExpanded(top);
}
}
- entry.row.setDimmed(mOnKeyguard);
- entry.row.setLocked(mOnKeyguard);
+ entry.row.setDimmed(onKeyguard);
+ entry.row.setLocked(onKeyguard);
boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
- if (mOnKeyguard && (visibleNotifications >= maxKeyguardNotifications
+ if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
|| !showOnKeyguard)) {
entry.row.setVisibility(View.GONE);
if (showOnKeyguard) {
@@ -1087,7 +1092,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- if (mOnKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
+ if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
} else {
mKeyguardIconOverflowContainer.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
new file mode 100644
index 0000000..af4c8b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2014 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;
+
+import android.content.Context;
+import android.util.ArraySet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.Gefingerpoken;
+import com.android.systemui.R;
+
+import java.util.HashSet;
+
+/**
+ * A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
+ * the notification where the drag started.
+ */
+public class DragDownHelper implements Gefingerpoken {
+
+ private int mMinDragDistance;
+ private ExpandHelper.Callback mCallback;
+ private float mInitialTouchX;
+ private float mInitialTouchY;
+ private boolean mDraggingDown;
+ private float mTouchSlop;
+ private OnDragDownListener mOnDragDownListener;
+ private View mHost;
+ private final int[] mTemp2 = new int[2];
+ private final ArraySet<View> mHoveredChildren = new ArraySet<View>();
+ private boolean mDraggedFarEnough;
+ private View mStartingChild;
+
+ public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
+ OnDragDownListener onDragDownListener) {
+ mMinDragDistance = context.getResources().getDimensionPixelSize(
+ R.dimen.keyguard_drag_down_min_distance);
+ mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ mCallback = callback;
+ mOnDragDownListener = onDragDownListener;
+ mHost = host;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ final float x = event.getX();
+ final float y = event.getY();
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mHoveredChildren.clear();
+ mDraggedFarEnough = false;
+ mDraggingDown = false;
+ mStartingChild = null;
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
+ mDraggingDown = true;
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (!mDraggingDown) {
+ return false;
+ }
+ final float x = event.getX();
+ final float y = event.getY();
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ View child = findView(x, y);
+ if (child != null) {
+ hoverChild(findView(x, y));
+ }
+ if (h > mMinDragDistance) {
+ if (!mDraggedFarEnough) {
+ mDraggedFarEnough = true;
+ mOnDragDownListener.onThresholdReached();
+ }
+ } else {
+ if (mDraggedFarEnough) {
+ mDraggedFarEnough = false;
+ mOnDragDownListener.onReset();
+ }
+ }
+ return true;
+ case MotionEvent.ACTION_UP:
+ if (mDraggedFarEnough) {
+ mOnDragDownListener.onDraggedDown(mStartingChild);
+ } else {
+ stopDragging();
+ return false;
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ stopDragging();
+ return false;
+ }
+ return false;
+ }
+
+ private void stopDragging() {
+ mDraggingDown = false;
+ mOnDragDownListener.onReset();
+ }
+
+ private void hoverChild(View child) {
+ if (mHoveredChildren.isEmpty()) {
+ mStartingChild = child;
+ }
+ if (!mHoveredChildren.contains(child)) {
+ mOnDragDownListener.onHover(child);
+ mHoveredChildren.add(child);
+ }
+ }
+
+ private View findView(float x, float y) {
+ mHost.getLocationOnScreen(mTemp2);
+ x += mTemp2[0];
+ y += mTemp2[1];
+ return mCallback.getChildAtRawPosition(x, y);
+ }
+
+ public interface OnDragDownListener {
+ void onHover(View child);
+ void onDraggedDown(View startingChild);
+ void onReset();
+ void onThresholdReached();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 61aad6f..5b70cd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -23,7 +23,8 @@ import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.R;
-public class ExpandableNotificationRow extends ActivatableNotificationView {
+public class ExpandableNotificationRow extends ActivatableNotificationView implements
+ NotificationActivatable {
private int mRowMinHeight;
private int mRowMaxHeight;
@@ -64,7 +65,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
- mActivator = new NotificationActivator(this);
+ mActivator = new NotificationActivator(this, this);
}
@Override
@@ -113,6 +114,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setUserExpanded(boolean userExpanded) {
mHasUserChangedExpansion = true;
mUserExpanded = userExpanded;
+ applyExpansionToLayout();
}
public boolean isUserLocked() {
@@ -225,6 +227,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return mMaxExpandHeight;
}
+ @Override
public NotificationActivator getActivator() {
return mActivator;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivatable.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivatable.java
new file mode 100644
index 0000000..410a3aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivatable.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2014 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;
+
+/**
+ * An interface which defines a view to be activatable in the meaning of
+ * {@link NotificationActivator}.
+ */
+public interface NotificationActivatable {
+ NotificationActivator getActivator();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
index 620e457..097857c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
@@ -34,14 +34,40 @@ public class NotificationActivator {
private static final float INVERSE_ALPHA = 0.9f;
private static final float DIMMED_SCALE = 0.95f;
- private final View mTargetView;
+ /**
+ * Normal state. Notification is fully interactable.
+ */
+ private static final int STATE_NORMAL = 0;
+
+ /**
+ * Dimmed state. Neutral state when on the lockscreen, with slight transparency and scaled down
+ * a bit.
+ */
+ private static final int STATE_DIMMED = 1;
+
+ /**
+ * Activated state. Used after tapping a notification on the lockscreen. Normal transparency and
+ * normal scale.
+ */
+ private static final int STATE_ACTIVATED = 2;
+ /**
+ * Inverse activated state. Used for the other notifications on the lockscreen when tapping on
+ * one.
+ */
+ private static final int STATE_ACTIVATED_INVERSE = 3;
+
+ private final View mTargetView;
+ private final View mHotspotView;
private final Interpolator mFastOutSlowInInterpolator;
private final Interpolator mLinearOutSlowInInterpolator;
private final int mTranslationZ;
- public NotificationActivator(View targetView) {
+ private int mState;
+
+ public NotificationActivator(View targetView, View hotspotView) {
mTargetView = targetView;
+ mHotspotView = hotspotView;
Context ctx = targetView.getContext();
mFastOutSlowInInterpolator =
AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
@@ -53,18 +79,37 @@ public class NotificationActivator {
}
public void activateInverse() {
+ if (mState == STATE_ACTIVATED_INVERSE) {
+ return;
+ }
+ mTargetView.animate().cancel();
mTargetView.animate().withLayer().alpha(INVERSE_ALPHA);
+ mState = STATE_ACTIVATED_INVERSE;
+ }
+
+ public void addHotspot() {
+ mHotspotView.getBackground().setHotspot(
+ 0, mHotspotView.getWidth()/2, mHotspotView.getHeight()/2);
}
public void activate() {
+ if (mState == STATE_ACTIVATED) {
+ return;
+ }
+ mTargetView.animate().cancel();
mTargetView.animate()
.setInterpolator(mLinearOutSlowInInterpolator)
.scaleX(1)
.scaleY(1)
.translationZBy(mTranslationZ);
+ mState = STATE_ACTIVATED;
}
public void reset() {
+ if (mState == STATE_DIMMED) {
+ return;
+ }
+ mTargetView.animate().cancel();
mTargetView.animate()
.setInterpolator(mFastOutSlowInInterpolator)
.scaleX(DIMMED_SCALE)
@@ -73,15 +118,21 @@ public class NotificationActivator {
if (mTargetView.getAlpha() != 1.0f) {
mTargetView.animate().withLayer().alpha(1);
}
+ mHotspotView.getBackground().removeHotspot(0);
+ mState = STATE_DIMMED;
}
public void setDimmed(boolean dimmed) {
if (dimmed) {
+ mTargetView.animate().cancel();
mTargetView.setScaleX(DIMMED_SCALE);
mTargetView.setScaleY(DIMMED_SCALE);
+ mState = STATE_DIMMED;
} else {
+ mTargetView.animate().cancel();
mTargetView.setScaleX(1);
mTargetView.setScaleY(1);
+ mState = STATE_NORMAL;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index 8ebd50d..6f9cbf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -25,7 +25,8 @@ import com.android.systemui.R;
/**
* Container view for overflowing notification icons on Keyguard.
*/
-public class NotificationOverflowContainer extends ActivatableNotificationView {
+public class NotificationOverflowContainer extends ActivatableNotificationView implements
+ NotificationActivatable {
private NotificationOverflowIconsView mIconsView;
private NotificationActivator mActivator;
@@ -60,7 +61,7 @@ public class NotificationOverflowContainer extends ActivatableNotificationView {
mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
- mActivator = new NotificationActivator(this);
+ mActivator = new NotificationActivator(this, this);
mActivator.setDimmed(true);
setLocked(true);
setDimmed(true);
@@ -70,6 +71,7 @@ public class NotificationOverflowContainer extends ActivatableNotificationView {
return mIconsView;
}
+ @Override
public NotificationActivator getActivator() {
return mActivator;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
new file mode 100644
index 0000000..9d75228
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 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;
+
+/**
+ * Class to encapsulate all possible status bar states regarding Keyguard.
+ */
+public class StatusBarState {
+
+ /**
+ * The status bar is in the "normal" shade mode.
+ */
+ public static final int SHADE = 0;
+
+ /**
+ * Status bar is currently the Keyguard.
+ */
+ public static final int KEYGUARD = 1;
+
+ /**
+ * Status bar is in the special mode, where it is fully interactive but still locked. So
+ * dismissing the shade will still show the bouncer.
+ */
+ public static final int SHADE_LOCKED = 2;
+
+}
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 712eec8..ec7d80a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -25,6 +25,7 @@ import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
public class NotificationPanelView extends PanelView implements
@@ -76,7 +77,7 @@ public class NotificationPanelView extends PanelView implements
super.onLayout(changed, left, top, right, bottom);
int keyguardBottomMargin =
((MarginLayoutParams) mKeyguardStatusView.getLayoutParams()).bottomMargin;
- mNotificationStackScroller.setTopPadding(mStatusBar.isOnKeyguard()
+ mNotificationStackScroller.setTopPadding(mStatusBar.getBarState() == StatusBarState.KEYGUARD
? mKeyguardStatusView.getBottom() + keyguardBottomMargin
: mHeader.getBottom() + mNotificationTopPadding);
}
@@ -107,14 +108,18 @@ public class NotificationPanelView extends PanelView implements
public boolean onInterceptTouchEvent(MotionEvent event) {
// intercept for quick settings
if (event.getAction() == MotionEvent.ACTION_DOWN) {
- final View target = mStatusBar.isOnKeyguard() ? mKeyguardStatusView : mHeader;
+ final View target = mStatusBar.getBarState() == StatusBarState.KEYGUARD
+ ? mKeyguardStatusView
+ : mHeader;
final boolean inTarget = PhoneStatusBar.inBounds(target, event, true);
if (inTarget && !isInSettings()) {
mTrackingSettings = true;
+ requestDisallowInterceptTouchEvent(true);
return true;
}
if (!inTarget && isInSettings()) {
mTrackingSettings = true;
+ requestDisallowInterceptTouchEvent(true);
return true;
}
}
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 0c3462c..7d8f3ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -96,13 +96,17 @@ import com.android.systemui.R;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.DragDownHelper;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.InterceptedNotifications;
+import com.android.systemui.statusbar.NotificationActivatable;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.NotificationOverflowContainer;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.DateView;
@@ -120,7 +124,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
+public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
+ DragDownHelper.OnDragDownListener {
static final String TAG = "PhoneStatusBar";
public static final boolean DEBUG = BaseStatusBar.DEBUG;
public static final boolean SPEW = false;
@@ -233,6 +238,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
View mNotificationPanelHeader;
View mKeyguardStatusView;
View mKeyguardBottomArea;
+ boolean mLeaveOpenOnKeyguardHide;
KeyguardIndicationTextView mKeyguardIndicationTextView;
// TODO: Fetch phrase from search/hotword provider.
@@ -470,6 +476,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
};
+ private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ goToLockedShade(null);
+ }
+ };
+
@Override
public void setZenMode(int mode) {
super.setZenMode(mode);
@@ -619,6 +632,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
mKeyguardIconOverflowContainer.setOnActivatedListener(this);
mKeyguardCarrierLabel = mStatusBarWindow.findViewById(R.id.keyguard_carrier_text);
+ mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
mStackScroller.addView(mKeyguardIconOverflowContainer);
mExpandedContents = mStackScroller;
@@ -784,7 +798,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
} else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL)) {
final float dy = event.getY() - mSettingsDownY;
- final FlipperButton flipper = mOnKeyguard ? mKeyguardFlipper : mHeaderFlipper;
+ final FlipperButton flipper = mState == StatusBarState.KEYGUARD
+ ? mKeyguardFlipper
+ : mHeaderFlipper;
final boolean inButton = flipper.inHolderBounds(event);
final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
if (!qsTap && !inButton) {
@@ -1192,7 +1208,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
- && !mNotificationPanel.isTracking() && !mOnKeyguard) {
+ && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) {
animateCollapsePanels();
}
}
@@ -1346,7 +1362,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
&& mStackScroller.getHeight() < (mNotificationPanel.getHeight()
- mCarrierLabelHeight - mNotificationHeaderHeight)
&& mStackScroller.getVisibility() == View.VISIBLE
- && !mOnKeyguard;
+ && mState != StatusBarState.KEYGUARD;
if (force || mCarrierLabelVisible != makeVisible) {
mCarrierLabelVisible = makeVisible;
@@ -2097,7 +2113,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (mDemoMode) return;
int sbMode = mStatusBarMode;
if (panelsEnabled() && (mInteractingWindows & StatusBarManager.WINDOW_STATUS_BAR) != 0
- && !mOnKeyguard) {
+ && mState != StatusBarState.KEYGUARD) {
// if panels are expandable, force the status bar opaque on any interaction
sbMode = MODE_OPAQUE;
}
@@ -2957,28 +2973,37 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
}
- public boolean isOnKeyguard() {
- return mOnKeyguard;
+ /**
+ * @return The {@link StatusBarState} the status bar is in.
+ */
+ public int getBarState() {
+ return mState;
}
public void showKeyguard() {
- mOnKeyguard = true;
+ setBarState(StatusBarState.KEYGUARD);
updateKeyguardState();
instantExpandNotificationsPanel();
+ mLeaveOpenOnKeyguardHide = false;
}
public void hideKeyguard() {
- mOnKeyguard = false;
+ setBarState(StatusBarState.SHADE);
+ if (mLeaveOpenOnKeyguardHide) {
+ mLeaveOpenOnKeyguardHide = false;
+ } else {
+ instantCollapseNotificationPanel();
+ }
updateKeyguardState();
- instantCollapseNotificationPanel();
}
private void updatePublicMode() {
- setLockscreenPublicMode(mOnKeyguard && mStatusBarKeyguardViewManager.isSecure());
+ setLockscreenPublicMode(mState == StatusBarState.KEYGUARD
+ && mStatusBarKeyguardViewManager.isSecure());
}
private void updateKeyguardState() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD) {
if (isFlippedToSettings()) {
flipToNotifications(false /*animate*/);
}
@@ -3010,17 +3035,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
public void userActivity() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD) {
mKeyguardViewMediatorCallback.userActivity();
}
}
public boolean onMenuPressed() {
- return mOnKeyguard && mStatusBarKeyguardViewManager.onMenuPressed();
+ return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed();
}
public boolean onBackPressed() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
return mStatusBarKeyguardViewManager.onBackPressed();
} else {
animateCollapsePanels();
@@ -3029,7 +3054,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
private void showBouncer() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
mStatusBarKeyguardViewManager.dismiss();
}
}
@@ -3065,6 +3090,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
super.onActivated(view);
}
+ /**
+ * @param state The {@link StatusBarState} to set.
+ */
+ public void setBarState(int state) {
+ mState = state;
+ mStatusBarWindowManager.setStatusBarState(state);
+ }
+
@Override
public void onReset(View view) {
super.onReset(view);
@@ -3072,13 +3105,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
public void onTrackingStarted() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationTextView.switchIndication(R.string.keyguard_unlock);
}
}
public void onTrackingStopped() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
}
}
@@ -3092,6 +3125,56 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
return mNavigationBarView;
}
+ // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
+
+ @Override
+ public void onDraggedDown(View startingChild) {
+ goToLockedShade(startingChild);
+ }
+
+ @Override
+ public void onReset() {
+ onReset(null);
+ }
+
+ public void onHover(View child) {
+ if (child instanceof NotificationActivatable) {
+ NotificationActivatable activatable = (NotificationActivatable) child;
+ activatable.getActivator().activate();
+ activatable.getActivator().addHotspot();
+ }
+ }
+
+ public void onThresholdReached() {
+ // TODO: Add visual hint that threshold is reached.
+ }
+
+ /**
+ * If secure with redaction: Show bouncer, go to unlocked shade.
+ *
+ * <p>If secure without redaction: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
+ *
+ * <p>Otherwise go directly to unlocked shade.</p>
+ *
+ * @param expandView The view to expand after going to the shade.
+ */
+ public void goToLockedShade(View expandView) {
+ if (expandView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) expandView;
+ row.setUserExpanded(true);
+ }
+ if (isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(mCurrentUserId)) {
+ mLeaveOpenOnKeyguardHide = true;
+ showBouncer();
+ } else if (mStatusBarKeyguardViewManager.isSecure()) {
+ setBarState(StatusBarState.SHADE_LOCKED);
+ updateKeyguardState();
+ } else {
+ mLeaveOpenOnKeyguardHide = true;
+ mStatusBarKeyguardViewManager.dismiss();
+ }
+ }
+
/**
* @return a ViewGroup that spans the entire panel which contains the quick settings
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 79c63f7..c9c2867 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -29,6 +29,7 @@ import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarState;
public class PhoneStatusBarView extends PanelBar {
private static final String TAG = "PhoneStatusBarView";
@@ -187,7 +188,9 @@ public class PhoneStatusBarView extends PanelBar {
if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()
&& mBar.mStatusBarWindow != null) {
if (mShouldFade) {
- int scrimColor = mBar.isOnKeyguard() ? mScrimColorKeyguard : mScrimColor;
+ int scrimColor = mBar.getBarState() == StatusBarState.KEYGUARD
+ ? mScrimColorKeyguard
+ : mScrimColor;
frac = mPanelExpandedFractionSum; // don't judge me
// let's start this 20% of the way down the screen
frac = frac * 1.2f - 0.2f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index d175d7a..a04baea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import android.app.ActionBar;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
@@ -28,6 +27,8 @@ import android.view.ViewGroup;
import android.view.WindowManager;
import com.android.keyguard.R;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.StatusBarState;
/**
* Encapsulates all logic for the status bar window state management.
@@ -137,7 +138,8 @@ public class StatusBarWindowManager {
}
private void applyUserActivityTimeout(State state) {
- if (state.isKeyguardShowingAndNotOccluded()) {
+ if (state.isKeyguardShowingAndNotOccluded()
+ && state.statusBarState == StatusBarState.KEYGUARD) {
mLp.userActivityTimeout = state.keyguardUserActivityTimeout;
} else {
mLp.userActivityTimeout = -1;
@@ -194,6 +196,14 @@ public class StatusBarWindowManager {
apply(mCurrentState);
}
+ /**
+ * @param state The {@link StatusBarState} of the status bar.
+ */
+ public void setStatusBarState(int state) {
+ mCurrentState.statusBarState = state;
+ apply(mCurrentState);
+ }
+
private static class State {
boolean keyguardShowing;
boolean keyguardOccluded;
@@ -202,6 +212,11 @@ public class StatusBarWindowManager {
boolean statusBarFocusable;
long keyguardUserActivityTimeout;
+ /**
+ * The {@link BaseStatusBar} state from the status bar.
+ */
+ int statusBarState;
+
private boolean isKeyguardShowingAndNotOccluded() {
return keyguardShowing && !keyguardOccluded;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 6b5ef5a..3e5ba16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -31,16 +31,17 @@ import android.widget.FrameLayout;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.policy.ScrollAdapter;
+import com.android.systemui.statusbar.DragDownHelper;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
-public class StatusBarWindowView extends FrameLayout
-{
+public class StatusBarWindowView extends FrameLayout {
public static final String TAG = "StatusBarWindowView";
public static final boolean DEBUG = BaseStatusBar.DEBUG;
private ExpandHelper mExpandHelper;
+ private DragDownHelper mDragDownHelper;
private NotificationStackScrollLayout mStackScrollLayout;
private NotificationPanelView mNotificationPanel;
@@ -75,6 +76,7 @@ public class StatusBarWindowView extends FrameLayout
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(mStackScrollLayout);
+ mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService);
// We really need to be able to animate while window animations are going on
// so that activities may be started asynchronously from panel animations
@@ -106,8 +108,12 @@ public class StatusBarWindowView extends FrameLayout
boolean intercept = false;
if (mNotificationPanel.isFullyExpanded()
&& mStackScrollLayout.getVisibility() == View.VISIBLE
- && !mService.isOnKeyguard()) {
+ && mService.getBarState() != StatusBarState.KEYGUARD) {
intercept = mExpandHelper.onInterceptTouchEvent(ev);
+ } else if (mNotificationPanel.isFullyExpanded()
+ && mStackScrollLayout.getVisibility() == View.VISIBLE
+ && mService.getBarState() == StatusBarState.KEYGUARD) {
+ intercept = mDragDownHelper.onInterceptTouchEvent(ev);
}
if (!intercept) {
super.onInterceptTouchEvent(ev);
@@ -124,8 +130,11 @@ public class StatusBarWindowView extends FrameLayout
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean handled = false;
- if (mNotificationPanel.isFullyExpanded()) {
+ if (mNotificationPanel.isFullyExpanded()
+ && mService.getBarState() != StatusBarState.KEYGUARD) {
handled = mExpandHelper.onTouchEvent(ev);
+ } else if (mService.getBarState() == StatusBarState.KEYGUARD) {
+ handled = mDragDownHelper.onTouchEvent(ev);
}
if (!handled) {
handled = super.onTouchEvent(ev);