Loading core/java/com/android/internal/app/AlertController.java +6 −38 Original line number Diff line number Diff line Loading @@ -178,11 +178,6 @@ public class AlertController { return outValue.data != 0; } private static boolean isWatch(Context context) { return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_WATCH) == Configuration.UI_MODE_TYPE_WATCH; } public static final AlertController create(Context context, DialogInterface di, Window window) { final TypedArray a = context.obtainStyledAttributes( null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0); Loading Loading @@ -892,17 +887,11 @@ public class AlertController { listView.setAdapter(mAdapter); final int checkedItem = mCheckedItem; if (checkedItem > -1) { // TODO: Remove temp watch specific code if (isWatch(mContext)) { listView.setItemChecked(checkedItem + listView.getHeaderViewsCount(), true); listView.setSelection(checkedItem + listView.getHeaderViewsCount()); } else { listView.setItemChecked(checkedItem, true); listView.setSelection(checkedItem); } } } } public static class RecycleListView extends ListView { private final int mPaddingTopNoTitle; Loading Loading @@ -1078,15 +1067,9 @@ public class AlertController { if (mCheckedItems != null) { boolean isItemChecked = mCheckedItems[position]; if (isItemChecked) { // TODO: Remove temp watch specific code if (isWatch(mContext)) { listView.setItemChecked( position + listView.getHeaderViewsCount(), true); } else { listView.setItemChecked(position, true); } } } return view; } }; Loading @@ -1105,17 +1088,10 @@ public class AlertController { public void bindView(View view, Context context, Cursor cursor) { CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1); text.setText(cursor.getString(mLabelIndex)); // TODO: Remove temp watch specific code if (isWatch(mContext)) { listView.setItemChecked( cursor.getPosition() + listView.getHeaderViewsCount(), cursor.getInt(mIsCheckedIndex) == 1); } else { listView.setItemChecked( cursor.getPosition(), cursor.getInt(mIsCheckedIndex) == 1); } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { Loading Loading @@ -1157,10 +1133,6 @@ public class AlertController { listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { // TODO: Remove temp watch specific code if (isWatch(mContext)) { position -= listView.getHeaderViewsCount(); } mOnClickListener.onClick(dialog.mDialogInterface, position); if (!mIsSingleChoice) { dialog.mDialogInterface.dismiss(); Loading @@ -1171,10 +1143,6 @@ public class AlertController { listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { // TODO: Remove temp watch specific code if (isWatch(mContext)) { position -= listView.getHeaderViewsCount(); } if (mCheckedItems != null) { mCheckedItems[position] = listView.isItemChecked(position); } Loading core/java/com/android/internal/app/MicroAlertController.java +23 −12 Original line number Diff line number Diff line Loading @@ -18,12 +18,15 @@ package com.android.internal.app; import android.content.Context; import android.content.DialogInterface; import android.text.TextUtils; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ScrollView; import android.widget.TextView; import android.widget.AbsListView; import com.android.internal.app.AlertController; import com.android.internal.R; Loading Loading @@ -52,30 +55,38 @@ public class MicroAlertController extends AlertController { contentPanel.removeView(mMessageView); if (mListView != null) { // has ListView, swap ScrollView with ListView // has ListView, swap scrollView with ListView // move topPanel into header of ListView // move topPanel into top of scrollParent View topPanel = mScrollView.findViewById(R.id.topPanel); ((ViewGroup) topPanel.getParent()).removeView(topPanel); topPanel.setLayoutParams( new AbsListView.LayoutParams(topPanel.getLayoutParams())); mListView.addHeaderView(topPanel, null, false); FrameLayout.LayoutParams topParams = new FrameLayout.LayoutParams(topPanel.getLayoutParams()); topParams.gravity = Gravity.TOP; topPanel.setLayoutParams(topParams); // move buttonPanel into footer of ListView // move buttonPanel into bottom of scrollParent View buttonPanel = mScrollView.findViewById(R.id.buttonPanel); ((ViewGroup) buttonPanel.getParent()).removeView(buttonPanel); buttonPanel.setLayoutParams( new AbsListView.LayoutParams(buttonPanel.getLayoutParams())); mListView.addFooterView(buttonPanel, null, false); FrameLayout.LayoutParams buttonParams = new FrameLayout.LayoutParams(buttonPanel.getLayoutParams()); buttonParams.gravity = Gravity.BOTTOM; buttonPanel.setLayoutParams(buttonParams); // swap ScrollView w/ ListView // remove scrollview final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent(); final int childIndex = scrollParent.indexOfChild(mScrollView); scrollParent.removeViewAt(childIndex); scrollParent.addView(mListView, childIndex, // add list view scrollParent.addView(mListView, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); // add top and button panel scrollParent.addView(topPanel); scrollParent.addView(buttonPanel); } else { // no content, just hide everything contentPanel.setVisibility(View.GONE); Loading core/java/com/android/internal/widget/WatchListDecorLayout.java 0 → 100644 +327 −0 Original line number Diff line number Diff line /* * 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.internal.widget; import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.Rect; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewTreeObserver; import android.widget.ListView; import android.widget.FrameLayout; import java.util.ArrayList; /** * Layout for the decor for ListViews on watch-type devices with small screens. * <p> * Supports one panel with the gravity set to top, and one panel with gravity set to bottom. * <p> * Use with one ListView child. The top and bottom panels will track the ListView's scrolling. * If there is no ListView child, it will act like a normal FrameLayout. */ public class WatchListDecorLayout extends FrameLayout implements ViewTreeObserver.OnScrollChangedListener { private int mForegroundPaddingLeft = 0; private int mForegroundPaddingTop = 0; private int mForegroundPaddingRight = 0; private int mForegroundPaddingBottom = 0; private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1); /** Track the amount the ListView has to scroll up to account for padding change difference. */ private int mPendingScroll; private View mBottomPanel; private View mTopPanel; private ListView mListView; private ViewTreeObserver mObserver; public WatchListDecorLayout(Context context, AttributeSet attrs) { super(context, attrs); } public WatchListDecorLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public WatchListDecorLayout( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mPendingScroll = 0; for (int i = 0; i < getChildCount(); ++i) { View child = getChildAt(i); if (child instanceof ListView) { if (mListView != null) { throw new IllegalArgumentException("only one ListView child allowed"); } mListView = (ListView) child; mListView.setNestedScrollingEnabled(true); mObserver = mListView.getViewTreeObserver(); mObserver.addOnScrollChangedListener(this); } else { int gravity = (((LayoutParams) child.getLayoutParams()).gravity & Gravity.VERTICAL_GRAVITY_MASK); if (gravity == Gravity.TOP && mTopPanel == null) { mTopPanel = child; } else if (gravity == Gravity.BOTTOM && mBottomPanel == null) { mBottomPanel = child; } } } } @Override public void onDetachedFromWindow() { mListView = null; mBottomPanel = null; mTopPanel = null; if (mObserver != null) { if (mObserver.isAlive()) { mObserver.removeOnScrollChangedListener(this); } mObserver = null; } } private void applyMeasureToChild(View child, int widthMeasureSpec, int heightMeasureSpec) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec; if (lp.width == LayoutParams.MATCH_PARENT) { final int width = Math.max(0, getMeasuredWidth() - getPaddingLeftWithForeground() - getPaddingRightWithForeground() - lp.leftMargin - lp.rightMargin); childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( width, MeasureSpec.EXACTLY); } else { childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, getPaddingLeftWithForeground() + getPaddingRightWithForeground() + lp.leftMargin + lp.rightMargin, lp.width); } final int childHeightMeasureSpec; if (lp.height == LayoutParams.MATCH_PARENT) { final int height = Math.max(0, getMeasuredHeight() - getPaddingTopWithForeground() - getPaddingBottomWithForeground() - lp.topMargin - lp.bottomMargin); childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( height, MeasureSpec.EXACTLY); } else { childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTopWithForeground() + getPaddingBottomWithForeground() + lp.topMargin + lp.bottomMargin, lp.height); } child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } private int measureAndGetHeight(View child, int widthMeasureSpec, int heightMeasureSpec) { if (child != null) { if (child.getVisibility() != GONE) { applyMeasureToChild(mBottomPanel, widthMeasureSpec, heightMeasureSpec); return child.getMeasuredHeight(); } else if (getMeasureAllChildren()) { applyMeasureToChild(mBottomPanel, widthMeasureSpec, heightMeasureSpec); } } return 0; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); final boolean measureMatchParentChildren = MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY || MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY; mMatchParentChildren.clear(); int maxHeight = 0; int maxWidth = 0; int childState = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (getMeasureAllChildren() || child.getVisibility() != GONE) { measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); maxWidth = Math.max(maxWidth, child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); childState = combineMeasuredStates(childState, child.getMeasuredState()); if (measureMatchParentChildren) { if (lp.width == LayoutParams.MATCH_PARENT || lp.height == LayoutParams.MATCH_PARENT) { mMatchParentChildren.add(child); } } } } // Account for padding too maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground(); maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground(); // Check against our minimum height and width maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); // Check against our foreground's minimum height and width final Drawable drawable = getForeground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT)); if (mListView != null) { if (mPendingScroll != 0) { mListView.scrollListBy(mPendingScroll); mPendingScroll = 0; } int paddingTop = Math.max(mListView.getPaddingTop(), measureAndGetHeight(mTopPanel, widthMeasureSpec, heightMeasureSpec)); int paddingBottom = Math.max(mListView.getPaddingBottom(), measureAndGetHeight(mBottomPanel, widthMeasureSpec, heightMeasureSpec)); if (paddingTop != mListView.getPaddingTop() || paddingBottom != mListView.getPaddingBottom()) { mPendingScroll += mListView.getPaddingTop() - paddingTop; mListView.setPadding( mListView.getPaddingLeft(), paddingTop, mListView.getPaddingRight(), paddingBottom); } } count = mMatchParentChildren.size(); if (count > 1) { for (int i = 0; i < count; i++) { final View child = mMatchParentChildren.get(i); if (mListView == null || (child != mTopPanel && child != mBottomPanel)) { applyMeasureToChild(child, widthMeasureSpec, heightMeasureSpec); } } } } @Override public void setForegroundGravity(int foregroundGravity) { if (getForegroundGravity() != foregroundGravity) { super.setForegroundGravity(foregroundGravity); // calling get* again here because the set above may apply default constraints final Drawable foreground = getForeground(); if (getForegroundGravity() == Gravity.FILL && foreground != null) { Rect padding = new Rect(); if (foreground.getPadding(padding)) { mForegroundPaddingLeft = padding.left; mForegroundPaddingTop = padding.top; mForegroundPaddingRight = padding.right; mForegroundPaddingBottom = padding.bottom; } } else { mForegroundPaddingLeft = 0; mForegroundPaddingTop = 0; mForegroundPaddingRight = 0; mForegroundPaddingBottom = 0; } } } private int getPaddingLeftWithForeground() { return isForegroundInsidePadding() ? Math.max(mPaddingLeft, mForegroundPaddingLeft) : mPaddingLeft + mForegroundPaddingLeft; } private int getPaddingRightWithForeground() { return isForegroundInsidePadding() ? Math.max(mPaddingRight, mForegroundPaddingRight) : mPaddingRight + mForegroundPaddingRight; } private int getPaddingTopWithForeground() { return isForegroundInsidePadding() ? Math.max(mPaddingTop, mForegroundPaddingTop) : mPaddingTop + mForegroundPaddingTop; } private int getPaddingBottomWithForeground() { return isForegroundInsidePadding() ? Math.max(mPaddingBottom, mForegroundPaddingBottom) : mPaddingBottom + mForegroundPaddingBottom; } @Override public void onScrollChanged() { if (mListView == null) { return; } if (mTopPanel != null) { if (mListView.getChildCount() > 0) { if (mListView.getFirstVisiblePosition() == 0) { View firstChild = mListView.getChildAt(0); setScrolling(mTopPanel, firstChild.getY() - mTopPanel.getHeight() - mTopPanel.getTop()); } else { // shift to hide the frame, last child is not the last position setScrolling(mTopPanel, -mTopPanel.getHeight()); } } else { setScrolling(mTopPanel, 0); // no visible child, fallback to default behaviour } } if (mBottomPanel != null) { if (mListView.getChildCount() > 0) { if (mListView.getLastVisiblePosition() >= mListView.getCount() - 1) { View lastChild = mListView.getChildAt(mListView.getChildCount() - 1); setScrolling(mBottomPanel, lastChild.getY() + lastChild.getHeight() - mBottomPanel.getTop()); } else { // shift to hide the frame, last child is not the last position setScrolling(mBottomPanel, mBottomPanel.getHeight()); } } else { setScrolling(mBottomPanel, 0); // no visible child, fallback to default behaviour } } } /** Only set scrolling for the panel if there is a change in its translationY. */ private void setScrolling(View panel, float translationY) { if (panel.getTranslationY() != translationY) { panel.setTranslationY(translationY); } } } core/res/res/layout-watch/alert_dialog_material.xml +2 −2 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> <FrameLayout <com.android.internal.widget.WatchListDecorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parentPanel" android:layout_width="match_parent" Loading Loading @@ -104,4 +104,4 @@ </FrameLayout> </LinearLayout> </ScrollView> </FrameLayout> </com.android.internal.widget.WatchListDecorLayout> Loading
core/java/com/android/internal/app/AlertController.java +6 −38 Original line number Diff line number Diff line Loading @@ -178,11 +178,6 @@ public class AlertController { return outValue.data != 0; } private static boolean isWatch(Context context) { return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_WATCH) == Configuration.UI_MODE_TYPE_WATCH; } public static final AlertController create(Context context, DialogInterface di, Window window) { final TypedArray a = context.obtainStyledAttributes( null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0); Loading Loading @@ -892,17 +887,11 @@ public class AlertController { listView.setAdapter(mAdapter); final int checkedItem = mCheckedItem; if (checkedItem > -1) { // TODO: Remove temp watch specific code if (isWatch(mContext)) { listView.setItemChecked(checkedItem + listView.getHeaderViewsCount(), true); listView.setSelection(checkedItem + listView.getHeaderViewsCount()); } else { listView.setItemChecked(checkedItem, true); listView.setSelection(checkedItem); } } } } public static class RecycleListView extends ListView { private final int mPaddingTopNoTitle; Loading Loading @@ -1078,15 +1067,9 @@ public class AlertController { if (mCheckedItems != null) { boolean isItemChecked = mCheckedItems[position]; if (isItemChecked) { // TODO: Remove temp watch specific code if (isWatch(mContext)) { listView.setItemChecked( position + listView.getHeaderViewsCount(), true); } else { listView.setItemChecked(position, true); } } } return view; } }; Loading @@ -1105,17 +1088,10 @@ public class AlertController { public void bindView(View view, Context context, Cursor cursor) { CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1); text.setText(cursor.getString(mLabelIndex)); // TODO: Remove temp watch specific code if (isWatch(mContext)) { listView.setItemChecked( cursor.getPosition() + listView.getHeaderViewsCount(), cursor.getInt(mIsCheckedIndex) == 1); } else { listView.setItemChecked( cursor.getPosition(), cursor.getInt(mIsCheckedIndex) == 1); } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { Loading Loading @@ -1157,10 +1133,6 @@ public class AlertController { listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { // TODO: Remove temp watch specific code if (isWatch(mContext)) { position -= listView.getHeaderViewsCount(); } mOnClickListener.onClick(dialog.mDialogInterface, position); if (!mIsSingleChoice) { dialog.mDialogInterface.dismiss(); Loading @@ -1171,10 +1143,6 @@ public class AlertController { listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { // TODO: Remove temp watch specific code if (isWatch(mContext)) { position -= listView.getHeaderViewsCount(); } if (mCheckedItems != null) { mCheckedItems[position] = listView.isItemChecked(position); } Loading
core/java/com/android/internal/app/MicroAlertController.java +23 −12 Original line number Diff line number Diff line Loading @@ -18,12 +18,15 @@ package com.android.internal.app; import android.content.Context; import android.content.DialogInterface; import android.text.TextUtils; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ScrollView; import android.widget.TextView; import android.widget.AbsListView; import com.android.internal.app.AlertController; import com.android.internal.R; Loading Loading @@ -52,30 +55,38 @@ public class MicroAlertController extends AlertController { contentPanel.removeView(mMessageView); if (mListView != null) { // has ListView, swap ScrollView with ListView // has ListView, swap scrollView with ListView // move topPanel into header of ListView // move topPanel into top of scrollParent View topPanel = mScrollView.findViewById(R.id.topPanel); ((ViewGroup) topPanel.getParent()).removeView(topPanel); topPanel.setLayoutParams( new AbsListView.LayoutParams(topPanel.getLayoutParams())); mListView.addHeaderView(topPanel, null, false); FrameLayout.LayoutParams topParams = new FrameLayout.LayoutParams(topPanel.getLayoutParams()); topParams.gravity = Gravity.TOP; topPanel.setLayoutParams(topParams); // move buttonPanel into footer of ListView // move buttonPanel into bottom of scrollParent View buttonPanel = mScrollView.findViewById(R.id.buttonPanel); ((ViewGroup) buttonPanel.getParent()).removeView(buttonPanel); buttonPanel.setLayoutParams( new AbsListView.LayoutParams(buttonPanel.getLayoutParams())); mListView.addFooterView(buttonPanel, null, false); FrameLayout.LayoutParams buttonParams = new FrameLayout.LayoutParams(buttonPanel.getLayoutParams()); buttonParams.gravity = Gravity.BOTTOM; buttonPanel.setLayoutParams(buttonParams); // swap ScrollView w/ ListView // remove scrollview final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent(); final int childIndex = scrollParent.indexOfChild(mScrollView); scrollParent.removeViewAt(childIndex); scrollParent.addView(mListView, childIndex, // add list view scrollParent.addView(mListView, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); // add top and button panel scrollParent.addView(topPanel); scrollParent.addView(buttonPanel); } else { // no content, just hide everything contentPanel.setVisibility(View.GONE); Loading
core/java/com/android/internal/widget/WatchListDecorLayout.java 0 → 100644 +327 −0 Original line number Diff line number Diff line /* * 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.internal.widget; import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.Rect; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewTreeObserver; import android.widget.ListView; import android.widget.FrameLayout; import java.util.ArrayList; /** * Layout for the decor for ListViews on watch-type devices with small screens. * <p> * Supports one panel with the gravity set to top, and one panel with gravity set to bottom. * <p> * Use with one ListView child. The top and bottom panels will track the ListView's scrolling. * If there is no ListView child, it will act like a normal FrameLayout. */ public class WatchListDecorLayout extends FrameLayout implements ViewTreeObserver.OnScrollChangedListener { private int mForegroundPaddingLeft = 0; private int mForegroundPaddingTop = 0; private int mForegroundPaddingRight = 0; private int mForegroundPaddingBottom = 0; private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1); /** Track the amount the ListView has to scroll up to account for padding change difference. */ private int mPendingScroll; private View mBottomPanel; private View mTopPanel; private ListView mListView; private ViewTreeObserver mObserver; public WatchListDecorLayout(Context context, AttributeSet attrs) { super(context, attrs); } public WatchListDecorLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public WatchListDecorLayout( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mPendingScroll = 0; for (int i = 0; i < getChildCount(); ++i) { View child = getChildAt(i); if (child instanceof ListView) { if (mListView != null) { throw new IllegalArgumentException("only one ListView child allowed"); } mListView = (ListView) child; mListView.setNestedScrollingEnabled(true); mObserver = mListView.getViewTreeObserver(); mObserver.addOnScrollChangedListener(this); } else { int gravity = (((LayoutParams) child.getLayoutParams()).gravity & Gravity.VERTICAL_GRAVITY_MASK); if (gravity == Gravity.TOP && mTopPanel == null) { mTopPanel = child; } else if (gravity == Gravity.BOTTOM && mBottomPanel == null) { mBottomPanel = child; } } } } @Override public void onDetachedFromWindow() { mListView = null; mBottomPanel = null; mTopPanel = null; if (mObserver != null) { if (mObserver.isAlive()) { mObserver.removeOnScrollChangedListener(this); } mObserver = null; } } private void applyMeasureToChild(View child, int widthMeasureSpec, int heightMeasureSpec) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec; if (lp.width == LayoutParams.MATCH_PARENT) { final int width = Math.max(0, getMeasuredWidth() - getPaddingLeftWithForeground() - getPaddingRightWithForeground() - lp.leftMargin - lp.rightMargin); childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( width, MeasureSpec.EXACTLY); } else { childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, getPaddingLeftWithForeground() + getPaddingRightWithForeground() + lp.leftMargin + lp.rightMargin, lp.width); } final int childHeightMeasureSpec; if (lp.height == LayoutParams.MATCH_PARENT) { final int height = Math.max(0, getMeasuredHeight() - getPaddingTopWithForeground() - getPaddingBottomWithForeground() - lp.topMargin - lp.bottomMargin); childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( height, MeasureSpec.EXACTLY); } else { childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTopWithForeground() + getPaddingBottomWithForeground() + lp.topMargin + lp.bottomMargin, lp.height); } child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } private int measureAndGetHeight(View child, int widthMeasureSpec, int heightMeasureSpec) { if (child != null) { if (child.getVisibility() != GONE) { applyMeasureToChild(mBottomPanel, widthMeasureSpec, heightMeasureSpec); return child.getMeasuredHeight(); } else if (getMeasureAllChildren()) { applyMeasureToChild(mBottomPanel, widthMeasureSpec, heightMeasureSpec); } } return 0; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); final boolean measureMatchParentChildren = MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY || MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY; mMatchParentChildren.clear(); int maxHeight = 0; int maxWidth = 0; int childState = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (getMeasureAllChildren() || child.getVisibility() != GONE) { measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); maxWidth = Math.max(maxWidth, child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); childState = combineMeasuredStates(childState, child.getMeasuredState()); if (measureMatchParentChildren) { if (lp.width == LayoutParams.MATCH_PARENT || lp.height == LayoutParams.MATCH_PARENT) { mMatchParentChildren.add(child); } } } } // Account for padding too maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground(); maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground(); // Check against our minimum height and width maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); // Check against our foreground's minimum height and width final Drawable drawable = getForeground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT)); if (mListView != null) { if (mPendingScroll != 0) { mListView.scrollListBy(mPendingScroll); mPendingScroll = 0; } int paddingTop = Math.max(mListView.getPaddingTop(), measureAndGetHeight(mTopPanel, widthMeasureSpec, heightMeasureSpec)); int paddingBottom = Math.max(mListView.getPaddingBottom(), measureAndGetHeight(mBottomPanel, widthMeasureSpec, heightMeasureSpec)); if (paddingTop != mListView.getPaddingTop() || paddingBottom != mListView.getPaddingBottom()) { mPendingScroll += mListView.getPaddingTop() - paddingTop; mListView.setPadding( mListView.getPaddingLeft(), paddingTop, mListView.getPaddingRight(), paddingBottom); } } count = mMatchParentChildren.size(); if (count > 1) { for (int i = 0; i < count; i++) { final View child = mMatchParentChildren.get(i); if (mListView == null || (child != mTopPanel && child != mBottomPanel)) { applyMeasureToChild(child, widthMeasureSpec, heightMeasureSpec); } } } } @Override public void setForegroundGravity(int foregroundGravity) { if (getForegroundGravity() != foregroundGravity) { super.setForegroundGravity(foregroundGravity); // calling get* again here because the set above may apply default constraints final Drawable foreground = getForeground(); if (getForegroundGravity() == Gravity.FILL && foreground != null) { Rect padding = new Rect(); if (foreground.getPadding(padding)) { mForegroundPaddingLeft = padding.left; mForegroundPaddingTop = padding.top; mForegroundPaddingRight = padding.right; mForegroundPaddingBottom = padding.bottom; } } else { mForegroundPaddingLeft = 0; mForegroundPaddingTop = 0; mForegroundPaddingRight = 0; mForegroundPaddingBottom = 0; } } } private int getPaddingLeftWithForeground() { return isForegroundInsidePadding() ? Math.max(mPaddingLeft, mForegroundPaddingLeft) : mPaddingLeft + mForegroundPaddingLeft; } private int getPaddingRightWithForeground() { return isForegroundInsidePadding() ? Math.max(mPaddingRight, mForegroundPaddingRight) : mPaddingRight + mForegroundPaddingRight; } private int getPaddingTopWithForeground() { return isForegroundInsidePadding() ? Math.max(mPaddingTop, mForegroundPaddingTop) : mPaddingTop + mForegroundPaddingTop; } private int getPaddingBottomWithForeground() { return isForegroundInsidePadding() ? Math.max(mPaddingBottom, mForegroundPaddingBottom) : mPaddingBottom + mForegroundPaddingBottom; } @Override public void onScrollChanged() { if (mListView == null) { return; } if (mTopPanel != null) { if (mListView.getChildCount() > 0) { if (mListView.getFirstVisiblePosition() == 0) { View firstChild = mListView.getChildAt(0); setScrolling(mTopPanel, firstChild.getY() - mTopPanel.getHeight() - mTopPanel.getTop()); } else { // shift to hide the frame, last child is not the last position setScrolling(mTopPanel, -mTopPanel.getHeight()); } } else { setScrolling(mTopPanel, 0); // no visible child, fallback to default behaviour } } if (mBottomPanel != null) { if (mListView.getChildCount() > 0) { if (mListView.getLastVisiblePosition() >= mListView.getCount() - 1) { View lastChild = mListView.getChildAt(mListView.getChildCount() - 1); setScrolling(mBottomPanel, lastChild.getY() + lastChild.getHeight() - mBottomPanel.getTop()); } else { // shift to hide the frame, last child is not the last position setScrolling(mBottomPanel, mBottomPanel.getHeight()); } } else { setScrolling(mBottomPanel, 0); // no visible child, fallback to default behaviour } } } /** Only set scrolling for the panel if there is a change in its translationY. */ private void setScrolling(View panel, float translationY) { if (panel.getTranslationY() != translationY) { panel.setTranslationY(translationY); } } }
core/res/res/layout-watch/alert_dialog_material.xml +2 −2 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> <FrameLayout <com.android.internal.widget.WatchListDecorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parentPanel" android:layout_width="match_parent" Loading Loading @@ -104,4 +104,4 @@ </FrameLayout> </LinearLayout> </ScrollView> </FrameLayout> </com.android.internal.widget.WatchListDecorLayout>