Add visual feedback for notification expandability.
Change-Id: I0b82a465a126a6d0ec6cf6af87dc56817765b995
This commit is contained in:
BIN
packages/SystemUI/res/drawable-xhdpi/bottom_divider_glow.png
Normal file
BIN
packages/SystemUI/res/drawable-xhdpi/bottom_divider_glow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
packages/SystemUI/res/drawable-xhdpi/top_divider_glow.png
Normal file
BIN
packages/SystemUI/res/drawable-xhdpi/top_divider_glow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -4,6 +4,15 @@
|
||||
android:background="@*android:drawable/notification_bg"
|
||||
>
|
||||
|
||||
<View
|
||||
android:id="@+id/top_glow"
|
||||
android:alpha="0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/notification_divider_height"
|
||||
android:layout_gravity="top|center_horizontal"
|
||||
android:background="@drawable/top_divider_glow"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/veto"
|
||||
android:layout_width="48dp"
|
||||
@@ -19,6 +28,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/notification_divider_height"
|
||||
android:layout_marginTop="@dimen/notification_divider_height"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
>
|
||||
@@ -31,10 +41,12 @@
|
||||
</com.android.systemui.statusbar.LatestItemView>
|
||||
|
||||
<View
|
||||
android:id="@+id/bottom_glow"
|
||||
android:alpha="0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/notification_divider_height"
|
||||
android:gravity="bottom"
|
||||
android:background="@*android:drawable/notification_bg"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:background="@drawable/bottom_divider_glow"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
<resources>
|
||||
<!-- thickness (height) of each notification row, including any separators or padding -->
|
||||
<!-- Note: this is 64dip + 1px divider = 97px. -->
|
||||
<dimen name="notification_height">97px</dimen>
|
||||
<dimen name="notification_height">99px</dimen>
|
||||
|
||||
<!-- thickness (height) of dividers between each notification row; see math for
|
||||
notification_height above -->
|
||||
<dimen name="notification_divider_height">1px</dimen>
|
||||
<dimen name="notification_divider_height">4px</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
<!-- thickness (height) of each notification row, including any separators or padding -->
|
||||
<!-- note: this is the same value as in values/dimens.xml; the value is overridden in
|
||||
values-hdpi/dimens.xml and so we need to re-assert the general value here -->
|
||||
<dimen name="notification_height">65dp</dimen>
|
||||
<dimen name="notification_height">68dp</dimen>
|
||||
|
||||
<!-- thickness (height) of dividers between each notification row -->
|
||||
<!-- same as in values/dimens.xml; see note at notification_height -->
|
||||
<dimen name="notification_divider_height">1dp</dimen>
|
||||
<dimen name="notification_divider_height">2dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<dimen name="navigation_bar_deadzone_size">12dp</dimen>
|
||||
|
||||
<!-- thickness (height) of each notification row, including any separators or padding -->
|
||||
<dimen name="notification_height">65dp</dimen>
|
||||
<dimen name="notification_height">68dp</dimen>
|
||||
|
||||
<!-- Height of notification icons in the status bar -->
|
||||
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
|
||||
@@ -72,7 +72,7 @@
|
||||
<dimen name="status_bar_icon_padding">0dp</dimen>
|
||||
|
||||
<!-- thickness (height) of dividers between each notification row -->
|
||||
<dimen name="notification_divider_height">1dp</dimen>
|
||||
<dimen name="notification_divider_height">4dp</dimen>
|
||||
|
||||
<!-- Notification drawer tuning parameters (phone UI) -->
|
||||
<!-- Initial velocity of the shade when expanding on its own -->
|
||||
|
||||
20
packages/SystemUI/res/values/ids.xml
Normal file
20
packages/SystemUI/res/values/ids.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2012 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<item type="id" name="expandable_tag" />
|
||||
</resources>
|
||||
@@ -32,17 +32,28 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
public interface Callback {
|
||||
View getChildAtPosition(MotionEvent ev);
|
||||
View getChildAtPosition(float x, float y);
|
||||
boolean canChildBeExpanded(View v);
|
||||
}
|
||||
|
||||
private static final String TAG = "ExpandHelper";
|
||||
protected static final boolean DEBUG = false;
|
||||
private static final long EXPAND_DURATION = 250;
|
||||
|
||||
// amount of overstretch for maximum brightness expressed in U
|
||||
// 2f: maximum brightness is stretching a 1U to 3U, or a 4U to 6U
|
||||
private static final float STRETCH_INTERVAL = 2f;
|
||||
|
||||
// level of glow for a touch, without overstretch
|
||||
// overstretch fills the range (GLOW_BASE, 1.0]
|
||||
private static final float GLOW_BASE = 0.5f;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Context mContext;
|
||||
|
||||
private boolean mStretching;
|
||||
private View mCurrView;
|
||||
private View mCurrViewTopGlow;
|
||||
private View mCurrViewBottomGlow;
|
||||
private float mOldHeight;
|
||||
private float mNaturalHeight;
|
||||
private float mInitialTouchSpan;
|
||||
@@ -53,7 +64,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
|
||||
private int mSmallSize;
|
||||
private int mLargeSize;
|
||||
|
||||
private float mMaximumStretch;
|
||||
|
||||
private class ViewScaler {
|
||||
View mView;
|
||||
@@ -62,7 +73,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
mView = v;
|
||||
}
|
||||
public void setHeight(float h) {
|
||||
Log.v(TAG, "SetHeight: setting to " + h);
|
||||
if (DEBUG) Log.v(TAG, "SetHeight: setting to " + h);
|
||||
ViewGroup.LayoutParams lp = mView.getLayoutParams();
|
||||
lp.height = (int)h;
|
||||
mView.setLayoutParams(lp);
|
||||
@@ -94,6 +105,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
|
||||
public ExpandHelper(Context context, Callback callback, int small, int large) {
|
||||
mSmallSize = small;
|
||||
mMaximumStretch = mSmallSize * STRETCH_INTERVAL;
|
||||
mLargeSize = large;
|
||||
mContext = context;
|
||||
mCallback = callback;
|
||||
@@ -120,10 +132,16 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
float h = Math.abs(detector.getCurrentSpanY());
|
||||
if (DEBUG) Log.d(TAG, "current span is: " + h);
|
||||
h = h + mOldHeight - mInitialTouchSpan;
|
||||
float target = h;
|
||||
if (DEBUG) Log.d(TAG, "target is: " + target);
|
||||
h = h<mSmallSize?mSmallSize:(h>mLargeSize?mLargeSize:h);
|
||||
h = h>mNaturalHeight?mNaturalHeight:h;
|
||||
if (DEBUG) Log.d(TAG, "scale continues: h=" + h);
|
||||
mScaler.setHeight(h);
|
||||
float stretch = (float) Math.abs((target - h) / mMaximumStretch);
|
||||
float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
|
||||
if (DEBUG) Log.d(TAG, "stretch: " + stretch + " strength: " + strength);
|
||||
setGlow(GLOW_BASE + strength * (1f - GLOW_BASE));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -136,6 +154,14 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
}
|
||||
});
|
||||
}
|
||||
public void setGlow(float glow) {
|
||||
if (mCurrViewTopGlow != null) {
|
||||
mCurrViewTopGlow.setAlpha(glow);
|
||||
}
|
||||
if (mCurrViewBottomGlow != null) {
|
||||
mCurrViewBottomGlow.setAlpha(glow);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (DEBUG) Log.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
|
||||
@@ -154,7 +180,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mStretching = false;
|
||||
mCurrView = null;
|
||||
clearView();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
@@ -163,14 +189,20 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
if (v != null) {
|
||||
if (DEBUG) Log.d(TAG, "scale begins on view: " + v);
|
||||
mStretching = true;
|
||||
mCurrView = v;
|
||||
setView(v);
|
||||
setGlow(GLOW_BASE);
|
||||
mScaler.setView(v);
|
||||
mOldHeight = mScaler.getHeight();
|
||||
mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
|
||||
if (mCallback.canChildBeExpanded(v)) {
|
||||
if (DEBUG) Log.d(TAG, "working on an expandable child");
|
||||
mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
|
||||
} else {
|
||||
if (DEBUG) Log.d(TAG, "working on a non-expandable child");
|
||||
mNaturalHeight = mOldHeight;
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "got mOldHeight: " + mOldHeight +
|
||||
" mNaturalHeight: " + mNaturalHeight);
|
||||
v.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
if (DEBUG) v.setBackgroundColor(0xFFFFFF00);
|
||||
}
|
||||
return mStretching;
|
||||
}
|
||||
@@ -183,11 +215,33 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
} else {
|
||||
h = (force || h < mNaturalHeight) ? mSmallSize : mNaturalHeight;
|
||||
}
|
||||
if (DEBUG) mCurrView.setBackgroundColor(0);
|
||||
if (DEBUG && mCurrView != null) mCurrView.setBackgroundColor(0);
|
||||
mAnimation = ObjectAnimator.ofFloat(mScaler, "height", h).setDuration(EXPAND_DURATION);
|
||||
mAnimation.start();
|
||||
mStretching = false;
|
||||
setGlow(0f);
|
||||
clearView();
|
||||
}
|
||||
|
||||
private void clearView() {
|
||||
mCurrView = null;
|
||||
mCurrViewTopGlow = null;
|
||||
mCurrViewBottomGlow = null;
|
||||
}
|
||||
|
||||
private void setView(View v) {
|
||||
mCurrView = null;
|
||||
if (v instanceof ViewGroup) {
|
||||
ViewGroup g = (ViewGroup) v;
|
||||
mCurrViewTopGlow = g.findViewById(R.id.top_glow);
|
||||
mCurrViewBottomGlow = g.findViewById(R.id.bottom_glow);
|
||||
if (DEBUG) {
|
||||
String debugLog = "Looking for glows: " +
|
||||
(mCurrViewTopGlow != null ? "found top " : "didn't find top") +
|
||||
(mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom");
|
||||
Log.v(TAG, debugLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -397,12 +397,15 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
|
||||
// XXX: temporary: while testing big notifications, auto-expand all of them
|
||||
ViewGroup.LayoutParams lp = row.getLayoutParams();
|
||||
Boolean expandable = Boolean.FALSE;
|
||||
if (large != null) {
|
||||
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
expandable = Boolean.TRUE;
|
||||
} else {
|
||||
lp.height = minHeight;
|
||||
}
|
||||
row.setLayoutParams(lp);
|
||||
row.setTag(R.id.expandable_tag, expandable);
|
||||
workAroundBadLayerDrawableOpacity(row);
|
||||
View vetoButton = updateNotificationVetoButton(row, sbn);
|
||||
vetoButton.setContentDescription(mContext.getString(
|
||||
|
||||
@@ -165,6 +165,12 @@ public class NotificationRowLayout
|
||||
return (veto != null && veto.getVisibility() != View.GONE);
|
||||
}
|
||||
|
||||
public boolean canChildBeExpanded(View v) {
|
||||
Object isExpandable = v.getTag(R.id.expandable_tag);
|
||||
return isExpandable != null && isExpandable instanceof Boolean &&
|
||||
((Boolean)isExpandable).booleanValue();
|
||||
}
|
||||
|
||||
public void onChildDismissed(View v) {
|
||||
final View veto = v.findViewById(R.id.veto);
|
||||
if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
|
||||
|
||||
Reference in New Issue
Block a user