Merge "Keep RemoteInputView visible when focused" into nyc-dev

This commit is contained in:
TreeHugger Robot
2016-05-10 17:41:58 +00:00
committed by Android (Google) Code Review
11 changed files with 193 additions and 11 deletions

View File

@@ -21,7 +21,7 @@
<com.android.internal.widget.NotificationActionListLayout
android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_height="@dimen/notification_action_list_height"
android:paddingEnd="4dp"
android:orientation="horizontal"
android:gravity="center_vertical"

View File

@@ -152,6 +152,9 @@
<!-- The margin on the end of the content view with a picture.-->
<dimen name="notification_content_picture_margin">56dp</dimen>
<!-- The height of the notification action list -->
<dimen name="notification_action_list_height">56dp</dimen>
<!-- height of the content margin to accomodate for the header -->
<dimen name="notification_content_margin_top">37.5dp</dimen>

View File

@@ -2584,6 +2584,8 @@
<java-symbol type="dimen" name="input_extract_action_button_width" />
<java-symbol type="dimen" name="input_extract_action_button_height" />
<java-symbol type="dimen" name="notification_action_list_height" />
<!-- TV Remote Service package -->
<java-symbol type="string" name="config_tvRemoteServicePackage" />

View File

@@ -374,10 +374,42 @@ public class NotificationContentView extends FrameLayout {
mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());;
mUnrestrictedContentHeight = Math.max(contentHeight, getMinHeight());
selectLayout(mAnimate /* animate */, false /* force */);
int minHeightHint = getMinContentHeightHint();
NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
if (wrapper != null) {
wrapper.setContentHeight(mContentHeight, minHeightHint);
}
wrapper = getVisibleWrapper(mTransformationStartVisibleType);
if (wrapper != null) {
wrapper.setContentHeight(mContentHeight, minHeightHint);
}
updateClipping();
invalidateOutline();
}
/**
* @return the minimum apparent height that the wrapper should allow for the purpose
* of aligning elements at the bottom edge. If this is larger than the content
* height, the notification is clipped instead of being further shrunk.
*/
private int getMinContentHeightHint() {
if (mIsChildInGroup && (mVisibleType == VISIBLE_TYPE_SINGLELINE
|| mTransformationStartVisibleType == VISIBLE_TYPE_SINGLELINE)) {
return mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_action_list_height);
}
if (mHeadsUpChild != null) {
return mHeadsUpChild.getHeight();
} else {
return mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_action_list_height);
}
}
private void updateContentTransformation() {
int visibleType = calculateVisibleType();
if (visibleType != mVisibleType) {
@@ -493,11 +525,15 @@ public class NotificationContentView extends FrameLayout {
} else {
int visibleType = calculateVisibleType();
if (visibleType != mVisibleType || force) {
View visibleView = getViewForVisibleType(visibleType);
if (visibleView != null) {
visibleView.setVisibility(VISIBLE);
transferRemoteInputFocus(visibleType);
}
View visibleView = getViewForVisibleType(visibleType);
if (visibleView != null) {
visibleView.setVisibility(VISIBLE);
transferRemoteInputFocus(visibleType);
}
NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
if (visibleWrapper != null) {
visibleWrapper.setContentHeight(mContentHeight, getMinContentHeightHint());
}
if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
|| (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2016 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.notification;
import android.text.Layout;
import android.text.TextUtils;
import android.util.Pools;
import android.view.View;
import android.widget.TextView;
/**
* A transform state of the action list
*/
public class ActionListTransformState extends TransformState {
private static Pools.SimplePool<ActionListTransformState> sInstancePool
= new Pools.SimplePool<>(40);
@Override
protected boolean sameAs(TransformState otherState) {
return otherState instanceof ActionListTransformState;
}
public static ActionListTransformState obtain() {
ActionListTransformState instance = sInstancePool.acquire();
if (instance != null) {
return instance;
}
return new ActionListTransformState();
}
@Override
protected void resetTransformedView() {
// We need to keep the Y transformation, because this is used to keep the action list
// aligned at the bottom, unrelated to transforms.
float y = getTransformedView().getTranslationY();
super.resetTransformedView();
getTransformedView().setTranslationY(y);
}
@Override
public void recycle() {
super.recycle();
sInstancePool.release(this);
}
}

View File

@@ -41,6 +41,10 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
private ProgressBar mProgressBar;
private TextView mTitle;
private TextView mText;
private View mActionsContainer;
private int mContentHeight;
private int mMinHeightHint;
protected NotificationTemplateViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
super(ctx, view, row);
@@ -123,6 +127,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
// It's still a viewstub
mProgressBar = null;
}
mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
}
@Override
@@ -225,4 +230,21 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
(int) (gSource * (1f - t) + gTarget * t),
(int) (bSource * (1f - t) + bTarget * t));
}
@Override
public void setContentHeight(int contentHeight, int minHeightHint) {
super.setContentHeight(contentHeight, minHeightHint);
mContentHeight = contentHeight;
mMinHeightHint = minHeightHint;
updateActionOffset();
}
private void updateActionOffset() {
if (mActionsContainer != null) {
// We should never push the actions higher than they are in the headsup view.
int constrainedContentHeight = Math.max(mContentHeight, mMinHeightHint);
mActionsContainer.setTranslationY(constrainedContentHeight - mView.getHeight());
}
}
}

View File

@@ -158,4 +158,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
public void setShowingLegacyBackground(boolean showing) {
}
public void setContentHeight(int contentHeight, int minHeightHint) {
}
}

View File

@@ -374,6 +374,11 @@ public class TransformState {
result.initFrom(view);
return result;
}
if (view.getId() == com.android.internal.R.id.actions_container) {
ActionListTransformState result = ActionListTransformState.obtain();
result.initFrom(view);
return result;
}
if (view instanceof NotificationHeaderView) {
HeaderTransformState result = HeaderTransformState.obtain();
result.initFrom(view);
@@ -467,7 +472,7 @@ public class TransformState {
resetTransformedView();
}
private void resetTransformedView() {
protected void resetTransformedView() {
mTransformedView.setTranslationX(0);
mTransformedView.setTranslationY(0);
mTransformedView.setScaleX(1.0f);

View File

@@ -272,7 +272,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
public boolean requestScrollTo() {
findScrollContainer();
mScrollContainer.scrollTo(mScrollContainerChild);
mScrollContainer.lockScrollTo(mScrollContainerChild);
return true;
}

View File

@@ -243,6 +243,7 @@ public class NotificationStackScrollLayout extends ViewGroup
= new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
updateForcedScroll();
updateChildren();
mChildrenUpdateRequested = false;
getViewTreeObserver().removeOnPreDrawListener(this);
@@ -334,6 +335,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private boolean mDrawBackgroundAsSrc;
private boolean mFadedOut;
private boolean mGroupExpandedForMeasure;
private View mForcedScroll;
private float mBackgroundFadeAmount = 1.0f;
private static final Property<NotificationStackScrollLayout, Float> BACKGROUND_FADE =
new FloatProperty<NotificationStackScrollLayout>("backgroundFade") {
@@ -591,6 +593,23 @@ public class NotificationStackScrollLayout extends ViewGroup
clampScrollPosition();
}
private void updateForcedScroll() {
if (mForcedScroll != null && (!mForcedScroll.hasFocus()
|| !mForcedScroll.isAttachedToWindow())) {
mForcedScroll = null;
}
if (mForcedScroll != null) {
ExpandableView expandableView = (ExpandableView) mForcedScroll;
int positionInLinearLayout = getPositionInLinearLayout(expandableView);
int targetScroll = targetScrollForView(expandableView, positionInLinearLayout);
targetScroll = Math.max(0, Math.min(targetScroll, getScrollRange()));
if (mOwnScrollY < targetScroll || positionInLinearLayout < mOwnScrollY) {
mOwnScrollY = targetScroll;
}
}
}
private void requestChildrenUpdate() {
if (!mChildrenUpdateRequested) {
getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
@@ -978,11 +997,19 @@ public class NotificationStackScrollLayout extends ViewGroup
mScrollingEnabled = enable;
}
@Override
public void lockScrollTo(View v) {
if (mForcedScroll == v) {
return;
}
mForcedScroll = v;
scrollTo(v);
}
@Override
public boolean scrollTo(View v) {
ExpandableView expandableView = (ExpandableView) v;
int positionInLinearLayout = getPositionInLinearLayout(v);
int targetScroll = positionInLinearLayout + expandableView.getIntrinsicHeight() +
getImeInset() - getHeight() + getTopPadding();
int targetScroll = targetScrollForView(expandableView, getPositionInLinearLayout(v));
if (mOwnScrollY < targetScroll) {
mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScroll - mOwnScrollY);
@@ -993,6 +1020,15 @@ public class NotificationStackScrollLayout extends ViewGroup
return false;
}
/**
* @return the scroll necessary to make the bottom edge of {@param v} align with the top of
* the IME.
*/
private int targetScrollForView(ExpandableView v, int positionInLinearLayout) {
return positionInLinearLayout + v.getIntrinsicHeight() +
getImeInset() - getHeight() + getTopPadding();
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mBottomInset = insets.getSystemWindowInsetBottom();
@@ -1111,6 +1147,7 @@ public class NotificationStackScrollLayout extends ViewGroup
if (ev.getY() < mQsContainer.getBottom()) {
return false;
}
mForcedScroll = null;
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
@@ -2786,6 +2823,14 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
@Override
public void clearChildFocus(View child) {
super.clearChildFocus(child);
if (mForcedScroll == child) {
mForcedScroll = null;
}
}
@Override
public void requestDisallowLongPress() {
removeLongPressCallback();

View File

@@ -35,6 +35,12 @@ public interface ScrollContainer {
*/
boolean scrollTo(View v);
/**
* Like {@link #scrollTo(View)}, but keeps the scroll locked until the user
* scrolls, or {@param v} loses focus or is detached.
*/
void lockScrollTo(View v);
/**
* Request that the view does not dismiss for the current touch.
*/