Skip to content

Commit 80a7627

Browse files
committed
Add visual feedback for notification expandability.
Change-Id: I0b82a465a126a6d0ec6cf6af87dc56817765b995
1 parent cd3e6e2 commit 80a7627

File tree

10 files changed

+110
-15
lines changed

10 files changed

+110
-15
lines changed
1.47 KB
Loading
1.46 KB
Loading

packages/SystemUI/res/layout/status_bar_notification_row.xml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44
android:background="@*android:drawable/notification_bg"
55
>
66

7+
<View
8+
android:id="@+id/top_glow"
9+
android:alpha="0"
10+
android:layout_width="match_parent"
11+
android:layout_height="@dimen/notification_divider_height"
12+
android:layout_gravity="top|center_horizontal"
13+
android:background="@drawable/top_divider_glow"
14+
/>
15+
716
<Button
817
android:id="@+id/veto"
918
android:layout_width="48dp"
@@ -19,6 +28,7 @@
1928
android:layout_width="match_parent"
2029
android:layout_height="wrap_content"
2130
android:layout_marginBottom="@dimen/notification_divider_height"
31+
android:layout_marginTop="@dimen/notification_divider_height"
2232
android:focusable="true"
2333
android:clickable="true"
2434
>
@@ -31,10 +41,12 @@
3141
</com.android.systemui.statusbar.LatestItemView>
3242

3343
<View
44+
android:id="@+id/bottom_glow"
45+
android:alpha="0"
3446
android:layout_width="match_parent"
3547
android:layout_height="@dimen/notification_divider_height"
36-
android:gravity="bottom"
37-
android:background="@*android:drawable/notification_bg"
48+
android:layout_gravity="bottom|center_horizontal"
49+
android:background="@drawable/bottom_divider_glow"
3850
/>
3951

4052
</FrameLayout>

packages/SystemUI/res/values-hdpi/dimens.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
<resources>
1919
<!-- thickness (height) of each notification row, including any separators or padding -->
2020
<!-- Note: this is 64dip + 1px divider = 97px. -->
21-
<dimen name="notification_height">97px</dimen>
21+
<dimen name="notification_height">99px</dimen>
2222

2323
<!-- thickness (height) of dividers between each notification row; see math for
2424
notification_height above -->
25-
<dimen name="notification_divider_height">1px</dimen>
25+
<dimen name="notification_divider_height">4px</dimen>
2626
</resources>

packages/SystemUI/res/values-xhdpi/dimens.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
<!-- thickness (height) of each notification row, including any separators or padding -->
2020
<!-- note: this is the same value as in values/dimens.xml; the value is overridden in
2121
values-hdpi/dimens.xml and so we need to re-assert the general value here -->
22-
<dimen name="notification_height">65dp</dimen>
22+
<dimen name="notification_height">68dp</dimen>
2323

2424
<!-- thickness (height) of dividers between each notification row -->
2525
<!-- same as in values/dimens.xml; see note at notification_height -->
26-
<dimen name="notification_divider_height">1dp</dimen>
26+
<dimen name="notification_divider_height">2dp</dimen>
2727
</resources>

packages/SystemUI/res/values/dimens.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
<dimen name="navigation_bar_deadzone_size">12dp</dimen>
5151

5252
<!-- thickness (height) of each notification row, including any separators or padding -->
53-
<dimen name="notification_height">65dp</dimen>
53+
<dimen name="notification_height">68dp</dimen>
5454

5555
<!-- Height of notification icons in the status bar -->
5656
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
@@ -72,7 +72,7 @@
7272
<dimen name="status_bar_icon_padding">0dp</dimen>
7373

7474
<!-- thickness (height) of dividers between each notification row -->
75-
<dimen name="notification_divider_height">1dp</dimen>
75+
<dimen name="notification_divider_height">4dp</dimen>
7676

7777
<!-- Notification drawer tuning parameters (phone UI) -->
7878
<!-- Initial velocity of the shade when expanding on its own -->
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright (C) 2012 The Android Open Source Project
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
18+
<resources>
19+
<item type="id" name="expandable_tag" />
20+
</resources>

packages/SystemUI/src/com/android/systemui/ExpandHelper.java

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,28 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
3232
public interface Callback {
3333
View getChildAtPosition(MotionEvent ev);
3434
View getChildAtPosition(float x, float y);
35+
boolean canChildBeExpanded(View v);
3536
}
3637

3738
private static final String TAG = "ExpandHelper";
3839
protected static final boolean DEBUG = false;
3940
private static final long EXPAND_DURATION = 250;
4041

42+
// amount of overstretch for maximum brightness expressed in U
43+
// 2f: maximum brightness is stretching a 1U to 3U, or a 4U to 6U
44+
private static final float STRETCH_INTERVAL = 2f;
45+
46+
// level of glow for a touch, without overstretch
47+
// overstretch fills the range (GLOW_BASE, 1.0]
48+
private static final float GLOW_BASE = 0.5f;
49+
4150
@SuppressWarnings("unused")
4251
private Context mContext;
4352

4453
private boolean mStretching;
4554
private View mCurrView;
55+
private View mCurrViewTopGlow;
56+
private View mCurrViewBottomGlow;
4657
private float mOldHeight;
4758
private float mNaturalHeight;
4859
private float mInitialTouchSpan;
@@ -53,7 +64,7 @@ public interface Callback {
5364

5465
private int mSmallSize;
5566
private int mLargeSize;
56-
67+
private float mMaximumStretch;
5768

5869
private class ViewScaler {
5970
View mView;
@@ -62,7 +73,7 @@ public void setView(View v) {
6273
mView = v;
6374
}
6475
public void setHeight(float h) {
65-
Log.v(TAG, "SetHeight: setting to " + h);
76+
if (DEBUG) Log.v(TAG, "SetHeight: setting to " + h);
6677
ViewGroup.LayoutParams lp = mView.getLayoutParams();
6778
lp.height = (int)h;
6879
mView.setLayoutParams(lp);
@@ -94,6 +105,7 @@ public int getNaturalHeight(int maximum) {
94105

95106
public ExpandHelper(Context context, Callback callback, int small, int large) {
96107
mSmallSize = small;
108+
mMaximumStretch = mSmallSize * STRETCH_INTERVAL;
97109
mLargeSize = large;
98110
mContext = context;
99111
mCallback = callback;
@@ -120,10 +132,16 @@ public boolean onScale(ScaleGestureDetector detector) {
120132
float h = Math.abs(detector.getCurrentSpanY());
121133
if (DEBUG) Log.d(TAG, "current span is: " + h);
122134
h = h + mOldHeight - mInitialTouchSpan;
135+
float target = h;
136+
if (DEBUG) Log.d(TAG, "target is: " + target);
123137
h = h<mSmallSize?mSmallSize:(h>mLargeSize?mLargeSize:h);
124138
h = h>mNaturalHeight?mNaturalHeight:h;
125139
if (DEBUG) Log.d(TAG, "scale continues: h=" + h);
126140
mScaler.setHeight(h);
141+
float stretch = (float) Math.abs((target - h) / mMaximumStretch);
142+
float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
143+
if (DEBUG) Log.d(TAG, "stretch: " + stretch + " strength: " + strength);
144+
setGlow(GLOW_BASE + strength * (1f - GLOW_BASE));
127145
return true;
128146
}
129147

@@ -136,6 +154,14 @@ public void onScaleEnd(ScaleGestureDetector detector) {
136154
}
137155
});
138156
}
157+
public void setGlow(float glow) {
158+
if (mCurrViewTopGlow != null) {
159+
mCurrViewTopGlow.setAlpha(glow);
160+
}
161+
if (mCurrViewBottomGlow != null) {
162+
mCurrViewBottomGlow.setAlpha(glow);
163+
}
164+
}
139165

140166
public boolean onInterceptTouchEvent(MotionEvent ev) {
141167
if (DEBUG) Log.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
@@ -154,7 +180,7 @@ public boolean onTouchEvent(MotionEvent ev) {
154180
case MotionEvent.ACTION_UP:
155181
case MotionEvent.ACTION_CANCEL:
156182
mStretching = false;
157-
mCurrView = null;
183+
clearView();
158184
break;
159185
}
160186
return true;
@@ -163,14 +189,20 @@ private boolean initScale(View v) {
163189
if (v != null) {
164190
if (DEBUG) Log.d(TAG, "scale begins on view: " + v);
165191
mStretching = true;
166-
mCurrView = v;
192+
setView(v);
193+
setGlow(GLOW_BASE);
167194
mScaler.setView(v);
168195
mOldHeight = mScaler.getHeight();
169-
mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
196+
if (mCallback.canChildBeExpanded(v)) {
197+
if (DEBUG) Log.d(TAG, "working on an expandable child");
198+
mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
199+
} else {
200+
if (DEBUG) Log.d(TAG, "working on a non-expandable child");
201+
mNaturalHeight = mOldHeight;
202+
}
170203
if (DEBUG) Log.d(TAG, "got mOldHeight: " + mOldHeight +
171204
" mNaturalHeight: " + mNaturalHeight);
172205
v.getParent().requestDisallowInterceptTouchEvent(true);
173-
if (DEBUG) v.setBackgroundColor(0xFFFFFF00);
174206
}
175207
return mStretching;
176208
}
@@ -183,11 +215,33 @@ private void finishScale(boolean force) {
183215
} else {
184216
h = (force || h < mNaturalHeight) ? mSmallSize : mNaturalHeight;
185217
}
186-
if (DEBUG) mCurrView.setBackgroundColor(0);
218+
if (DEBUG && mCurrView != null) mCurrView.setBackgroundColor(0);
187219
mAnimation = ObjectAnimator.ofFloat(mScaler, "height", h).setDuration(EXPAND_DURATION);
188220
mAnimation.start();
189221
mStretching = false;
222+
setGlow(0f);
223+
clearView();
224+
}
225+
226+
private void clearView() {
190227
mCurrView = null;
228+
mCurrViewTopGlow = null;
229+
mCurrViewBottomGlow = null;
230+
}
231+
232+
private void setView(View v) {
233+
mCurrView = null;
234+
if (v instanceof ViewGroup) {
235+
ViewGroup g = (ViewGroup) v;
236+
mCurrViewTopGlow = g.findViewById(R.id.top_glow);
237+
mCurrViewBottomGlow = g.findViewById(R.id.bottom_glow);
238+
if (DEBUG) {
239+
String debugLog = "Looking for glows: " +
240+
(mCurrViewTopGlow != null ? "found top " : "didn't find top") +
241+
(mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom");
242+
Log.v(TAG, debugLog);
243+
}
244+
}
191245
}
192246

193247
@Override

packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,12 +397,15 @@ protected boolean inflateViews(NotificationData.Entry entry, ViewGroup parent)
397397

398398
// XXX: temporary: while testing big notifications, auto-expand all of them
399399
ViewGroup.LayoutParams lp = row.getLayoutParams();
400+
Boolean expandable = Boolean.FALSE;
400401
if (large != null) {
401402
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
403+
expandable = Boolean.TRUE;
402404
} else {
403405
lp.height = minHeight;
404406
}
405407
row.setLayoutParams(lp);
408+
row.setTag(R.id.expandable_tag, expandable);
406409
workAroundBadLayerDrawableOpacity(row);
407410
View vetoButton = updateNotificationVetoButton(row, sbn);
408411
vetoButton.setContentDescription(mContext.getString(

packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ public boolean canChildBeDismissed(View v) {
165165
return (veto != null && veto.getVisibility() != View.GONE);
166166
}
167167

168+
public boolean canChildBeExpanded(View v) {
169+
Object isExpandable = v.getTag(R.id.expandable_tag);
170+
return isExpandable != null && isExpandable instanceof Boolean &&
171+
((Boolean)isExpandable).booleanValue();
172+
}
173+
168174
public void onChildDismissed(View v) {
169175
final View veto = v.findViewById(R.id.veto);
170176
if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {

0 commit comments

Comments
 (0)