149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes/* 249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Copyright (C) 2014 The Android Open Source Project 349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * you may not use this file except in compliance with the License. 649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * You may obtain a copy of the License at 749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 1049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Unless required by applicable law or agreed to in writing, software 1149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 1249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * See the License for the specific language governing permissions and 1449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * limitations under the License. 1549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 1649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 1766698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banespackage android.support.v7.widget; 1849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 198e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 208e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas 2149c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.content.Context; 2249c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.graphics.Canvas; 2349c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.graphics.Rect; 2449c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.graphics.drawable.Drawable; 25c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo; 2649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.graphics.drawable.DrawableCompat; 279840efe3dbdc7026521da8576574c55120782f6cChris Banesimport android.support.v7.graphics.drawable.DrawableWrapper; 2849c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.util.AttributeSet; 2918864e53490e04739f1063a7ee113549874f87b0Chris Banesimport android.view.MotionEvent; 3049c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.View; 3149c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.ViewGroup; 3249c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.AbsListView; 3349c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.ListAdapter; 3449c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.ListView; 3549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 3649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport java.lang.reflect.Field; 3749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 3849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes/** 3949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * This class contains a number of useful things for ListView. Mainly used by 4049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * {@link android.support.v7.widget.ListPopupWindow}. 4149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 4249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @hide 4349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 448e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas@RestrictTo(LIBRARY_GROUP) 4549c78900da0d43140fb602431fb93212bd7f6c70Chris Banespublic class ListViewCompat extends ListView { 4649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 4749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public static final int INVALID_POSITION = -1; 4849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public static final int NO_POSITION = -1; 4949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 5049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private static final int[] STATE_SET_NOTHING = new int[] { 0 }; 5149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 5249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Rect mSelectorRect = new Rect(); 5349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int mSelectionLeftPadding = 0; 5449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int mSelectionTopPadding = 0; 5549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int mSelectionRightPadding = 0; 5649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int mSelectionBottomPadding = 0; 5749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 5818864e53490e04739f1063a7ee113549874f87b0Chris Banes protected int mMotionPosition; 5918864e53490e04739f1063a7ee113549874f87b0Chris Banes 6049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private Field mIsChildViewEnabled; 6149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 6280e66c1609421dacff3e49770411e201039aa1d8Chris Banes private GateKeeperDrawable mSelector; 6380e66c1609421dacff3e49770411e201039aa1d8Chris Banes 6449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ListViewCompat(Context context) { 6549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes this(context, null); 6649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 6749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 6849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ListViewCompat(Context context, AttributeSet attrs) { 6949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes this(context, attrs, 0); 7049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 7149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 7249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public ListViewCompat(Context context, AttributeSet attrs, int defStyleAttr) { 7349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super(context, attrs, defStyleAttr); 7449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 7549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes try { 7649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mIsChildViewEnabled = AbsListView.class.getDeclaredField("mIsChildViewEnabled"); 7749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mIsChildViewEnabled.setAccessible(true); 7849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } catch (NoSuchFieldException e) { 7949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes e.printStackTrace(); 8049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 8149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 8249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 8349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 8449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setSelector(Drawable sel) { 85065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes mSelector = sel != null ? new GateKeeperDrawable(sel) : null; 8680e66c1609421dacff3e49770411e201039aa1d8Chris Banes super.setSelector(mSelector); 8749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 88065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes final Rect padding = new Rect(); 89065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes if (sel != null) { 90065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes sel.getPadding(padding); 91065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes } 92065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes 9349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mSelectionLeftPadding = padding.left; 9449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mSelectionTopPadding = padding.top; 9549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mSelectionRightPadding = padding.right; 9649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mSelectionBottomPadding = padding.bottom; 9749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 9849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 9949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 10049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected void drawableStateChanged() { 10149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.drawableStateChanged(); 102065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes 103065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes setSelectorEnabled(true); 10449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes updateSelectorStateCompat(); 10549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 10649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 10749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 10849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected void dispatchDraw(Canvas canvas) { 10949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final boolean drawSelectorOnTop = false; 11049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!drawSelectorOnTop) { 11149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes drawSelectorCompat(canvas); 11249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 11349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 11449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.dispatchDraw(canvas); 11549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 11649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 11718864e53490e04739f1063a7ee113549874f87b0Chris Banes @Override 11818864e53490e04739f1063a7ee113549874f87b0Chris Banes public boolean onTouchEvent(MotionEvent ev) { 11918864e53490e04739f1063a7ee113549874f87b0Chris Banes switch (ev.getAction()) { 12018864e53490e04739f1063a7ee113549874f87b0Chris Banes case MotionEvent.ACTION_DOWN: 12118864e53490e04739f1063a7ee113549874f87b0Chris Banes mMotionPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); 12218864e53490e04739f1063a7ee113549874f87b0Chris Banes break; 12318864e53490e04739f1063a7ee113549874f87b0Chris Banes } 12418864e53490e04739f1063a7ee113549874f87b0Chris Banes return super.onTouchEvent(ev); 12518864e53490e04739f1063a7ee113549874f87b0Chris Banes } 12618864e53490e04739f1063a7ee113549874f87b0Chris Banes 12749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected void updateSelectorStateCompat() { 12849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes Drawable selector = getSelector(); 1293228edfc4f8385dad5ae502f4a1d1343b9ec728fChris Banes if (selector != null && shouldShowSelectorCompat()) { 1303228edfc4f8385dad5ae502f4a1d1343b9ec728fChris Banes selector.setState(getDrawableState()); 13149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 13249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 13349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 13449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected boolean shouldShowSelectorCompat() { 1353228edfc4f8385dad5ae502f4a1d1343b9ec728fChris Banes return touchModeDrawsInPressedStateCompat() && isPressed(); 13649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 13749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 13849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected boolean touchModeDrawsInPressedStateCompat() { 13949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return false; 14049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 14149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 14249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected void drawSelectorCompat(Canvas canvas) { 14349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!mSelectorRect.isEmpty()) { 14449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Drawable selector = getSelector(); 145065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes if (selector != null) { 146065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes selector.setBounds(mSelectorRect); 147065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes selector.draw(canvas); 148065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes } 14949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 15049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 15149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 15249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 15349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Find a position that can be selected (i.e., is not a separator). 15449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 15549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param position The starting position to look at. 15649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param lookDown Whether to look down for other positions. 15749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @return The next selectable position starting at position and then searching either up or 15849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * down. Returns {@link #INVALID_POSITION} if nothing can be found. 15949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 16049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public int lookForSelectablePosition(int position, boolean lookDown) { 16149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final ListAdapter adapter = getAdapter(); 16249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (adapter == null || isInTouchMode()) { 16349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return INVALID_POSITION; 16449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 16549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 16649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int count = adapter.getCount(); 16749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!getAdapter().areAllItemsEnabled()) { 16849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (lookDown) { 16949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes position = Math.max(0, position); 17049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes while (position < count && !adapter.isEnabled(position)) { 17149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes position++; 17249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 17349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 17449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes position = Math.min(position, count - 1); 17549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes while (position >= 0 && !adapter.isEnabled(position)) { 17649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes position--; 17749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 17849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 17949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 18049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (position < 0 || position >= count) { 18149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return INVALID_POSITION; 18249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 18349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return position; 18449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 18549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (position < 0 || position >= count) { 18649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return INVALID_POSITION; 18749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 18849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return position; 18949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 19049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 19149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 19249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected void positionSelectorLikeTouchCompat(int position, View sel, float x, float y) { 19349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes positionSelectorLikeFocusCompat(position, sel); 19449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 19549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes Drawable selector = getSelector(); 19649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (selector != null && position != INVALID_POSITION) { 19749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes DrawableCompat.setHotspot(selector, x, y); 19849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 19949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 20049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 20149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected void positionSelectorLikeFocusCompat(int position, View sel) { 20249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // If we're changing position, update the visibility since the selector 20349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // is technically being detached from the previous selection. 20449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Drawable selector = getSelector(); 20549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final boolean manageState = selector != null && position != INVALID_POSITION; 20649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (manageState) { 20749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes selector.setVisible(false, false); 20849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 20949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 21049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes positionSelectorCompat(position, sel); 21149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 21249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (manageState) { 21349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Rect bounds = mSelectorRect; 21449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final float x = bounds.exactCenterX(); 21549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final float y = bounds.exactCenterY(); 21649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes selector.setVisible(getVisibility() == VISIBLE, false); 21749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes DrawableCompat.setHotspot(selector, x, y); 21849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 21949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 22049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 22149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected void positionSelectorCompat(int position, View sel) { 22249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Rect selectorRect = mSelectorRect; 22349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes selectorRect.set(sel.getLeft(), sel.getTop(), sel.getRight(), sel.getBottom()); 22449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 22549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Adjust for selection padding. 22649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes selectorRect.left -= mSelectionLeftPadding; 22749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes selectorRect.top -= mSelectionTopPadding; 22849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes selectorRect.right += mSelectionRightPadding; 22949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes selectorRect.bottom += mSelectionBottomPadding; 23049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 23149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes try { 23249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // AbsListView.mIsChildViewEnabled controls the selector's state so we need to 23344ece5ceaaee232f9139ccbde40ac4a5e642bdeeChristophe Beyls // modify its value 23449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final boolean isChildViewEnabled = mIsChildViewEnabled.getBoolean(this); 23549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (sel.isEnabled() != isChildViewEnabled) { 23649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mIsChildViewEnabled.set(this, !isChildViewEnabled); 23749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (position != INVALID_POSITION) { 23849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes refreshDrawableState(); 23949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 24049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 24149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } catch (IllegalAccessException e) { 24249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes e.printStackTrace(); 24349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 24449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 24549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 24649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes /** 24749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Measures the height of the given range of children (inclusive) and returns the height 24849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * with this ListView's padding and divider heights included. If maxHeight is provided, the 24949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * measuring will stop when the current height reaches maxHeight. 25049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * 25149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param widthMeasureSpec The width measure spec to be given to a child's 25249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * {@link View#measure(int, int)}. 25349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param startPosition The position of the first child to be shown. 25449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param endPosition The (inclusive) position of the last child to be 25549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * shown. Specify {@link #NO_POSITION} if the last child 25649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * should be the last available child from the adapter. 25749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param maxHeight The maximum height that will be returned (if all the 25849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * children don't fit in this value, this value will be 25949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * returned). 26049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @param disallowPartialChildPosition In general, whether the returned height should only 26149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * contain entire children. This is more powerful--it is 26249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * the first inclusive position at which partial 26349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * children will not be allowed. Example: it looks nice 26449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * to have at least 3 completely visible children, and 26549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * in portrait this will most likely fit; but in 26649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * landscape there could be times when even 2 children 26749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * can not be completely shown, so a value of 2 26849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * (remember, inclusive) would be good (assuming 26949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * startPosition is 0). 27049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @return The height of this ListView with the given children. 27149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes */ 27249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public int measureHeightOfChildrenCompat(int widthMeasureSpec, int startPosition, 27349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int endPosition, final int maxHeight, 27449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int disallowPartialChildPosition) { 27549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 27649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int paddingTop = getListPaddingTop(); 27749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int paddingBottom = getListPaddingBottom(); 27849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int paddingLeft = getListPaddingLeft(); 27949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int paddingRight = getListPaddingRight(); 28049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int reportedDividerHeight = getDividerHeight(); 28149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Drawable divider = getDivider(); 28249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 28349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final ListAdapter adapter = getAdapter(); 28449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 28549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (adapter == null) { 28649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return paddingTop + paddingBottom; 28749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 28849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 28949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Include the padding of the list 29049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int returnedHeight = paddingTop + paddingBottom; 29149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int dividerHeight = ((reportedDividerHeight > 0) && divider != null) 29249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ? reportedDividerHeight : 0; 29349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 29449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // The previous height value that was less than maxHeight and contained 29549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // no partial children 29649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int prevHeightWithoutPartialChild = 0; 29749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 29849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes View child = null; 29949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int viewType = 0; 30049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int count = adapter.getCount(); 30149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes for (int i = 0; i < count; i++) { 30249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int newType = adapter.getItemViewType(i); 30349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (newType != viewType) { 30449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes child = null; 30549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes viewType = newType; 30649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 30749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes child = adapter.getView(i, child, this); 30849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 30949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Compute child height spec 31049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int heightMeasureSpec; 31133be76574d6b384d1e5be0946c8b19613cff0abbChris Banes ViewGroup.LayoutParams childLp = child.getLayoutParams(); 31233be76574d6b384d1e5be0946c8b19613cff0abbChris Banes 31333be76574d6b384d1e5be0946c8b19613cff0abbChris Banes if (childLp == null) { 31433be76574d6b384d1e5be0946c8b19613cff0abbChris Banes childLp = generateDefaultLayoutParams(); 31533be76574d6b384d1e5be0946c8b19613cff0abbChris Banes child.setLayoutParams(childLp); 31633be76574d6b384d1e5be0946c8b19613cff0abbChris Banes } 31733be76574d6b384d1e5be0946c8b19613cff0abbChris Banes 31833be76574d6b384d1e5be0946c8b19613cff0abbChris Banes if (childLp.height > 0) { 31949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes heightMeasureSpec = MeasureSpec.makeMeasureSpec(childLp.height, 32049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes MeasureSpec.EXACTLY); 32149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 32249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 32349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 32449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes child.measure(widthMeasureSpec, heightMeasureSpec); 32549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 326c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas // Since this view was measured directly against the parent measure 32733be76574d6b384d1e5be0946c8b19613cff0abbChris Banes // spec, we must measure it again before reuse. 32833be76574d6b384d1e5be0946c8b19613cff0abbChris Banes child.forceLayout(); 32933be76574d6b384d1e5be0946c8b19613cff0abbChris Banes 33049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (i > 0) { 33149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Count the divider for all but one child 33249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes returnedHeight += dividerHeight; 33349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 33449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 33549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes returnedHeight += child.getMeasuredHeight(); 33649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 33749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (returnedHeight >= maxHeight) { 33849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // We went over, figure out which height to return. If returnedHeight > 33949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // maxHeight, then the i'th position did not fit completely. 34049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1) 34149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes && (i > disallowPartialChildPosition) // We've past the min pos 34249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes && (prevHeightWithoutPartialChild > 0) // We have a prev height 34349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes && (returnedHeight != maxHeight) // i'th child did not fit completely 34449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ? prevHeightWithoutPartialChild 34549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes : maxHeight; 34649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 34749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 34849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) { 34949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes prevHeightWithoutPartialChild = returnedHeight; 35049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 35149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 35249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 35349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // At this point, we went through the range of children, and they each 35449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // completely fit, so return the returnedHeight 35549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return returnedHeight; 35649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 35749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 35880e66c1609421dacff3e49770411e201039aa1d8Chris Banes protected void setSelectorEnabled(boolean enabled) { 359065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes if (mSelector != null) { 360065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes mSelector.setEnabled(enabled); 361065fe5b9b48c7edee12fb5fcbf776b29a9ebd51eChris Banes } 36280e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 36380e66c1609421dacff3e49770411e201039aa1d8Chris Banes 36480e66c1609421dacff3e49770411e201039aa1d8Chris Banes private static class GateKeeperDrawable extends DrawableWrapper { 36580e66c1609421dacff3e49770411e201039aa1d8Chris Banes private boolean mEnabled; 36680e66c1609421dacff3e49770411e201039aa1d8Chris Banes 36780e66c1609421dacff3e49770411e201039aa1d8Chris Banes public GateKeeperDrawable(Drawable drawable) { 36880e66c1609421dacff3e49770411e201039aa1d8Chris Banes super(drawable); 36980e66c1609421dacff3e49770411e201039aa1d8Chris Banes mEnabled = true; 37080e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 37180e66c1609421dacff3e49770411e201039aa1d8Chris Banes 37280e66c1609421dacff3e49770411e201039aa1d8Chris Banes void setEnabled(boolean enabled) { 37380e66c1609421dacff3e49770411e201039aa1d8Chris Banes mEnabled = enabled; 37480e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 37580e66c1609421dacff3e49770411e201039aa1d8Chris Banes 37680e66c1609421dacff3e49770411e201039aa1d8Chris Banes @Override 37780e66c1609421dacff3e49770411e201039aa1d8Chris Banes public boolean setState(int[] stateSet) { 37880e66c1609421dacff3e49770411e201039aa1d8Chris Banes if (mEnabled) { 37980e66c1609421dacff3e49770411e201039aa1d8Chris Banes return super.setState(stateSet); 38080e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 38180e66c1609421dacff3e49770411e201039aa1d8Chris Banes return false; 38280e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 38380e66c1609421dacff3e49770411e201039aa1d8Chris Banes 38480e66c1609421dacff3e49770411e201039aa1d8Chris Banes @Override 38580e66c1609421dacff3e49770411e201039aa1d8Chris Banes public void draw(Canvas canvas) { 38680e66c1609421dacff3e49770411e201039aa1d8Chris Banes if (mEnabled) { 38780e66c1609421dacff3e49770411e201039aa1d8Chris Banes super.draw(canvas); 38880e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 38980e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 39080e66c1609421dacff3e49770411e201039aa1d8Chris Banes 39180e66c1609421dacff3e49770411e201039aa1d8Chris Banes @Override 39280e66c1609421dacff3e49770411e201039aa1d8Chris Banes public void setHotspot(float x, float y) { 39380e66c1609421dacff3e49770411e201039aa1d8Chris Banes if (mEnabled) { 39480e66c1609421dacff3e49770411e201039aa1d8Chris Banes super.setHotspot(x, y); 39580e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 39680e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 39780e66c1609421dacff3e49770411e201039aa1d8Chris Banes 39880e66c1609421dacff3e49770411e201039aa1d8Chris Banes @Override 39980e66c1609421dacff3e49770411e201039aa1d8Chris Banes public void setHotspotBounds(int left, int top, int right, int bottom) { 40080e66c1609421dacff3e49770411e201039aa1d8Chris Banes if (mEnabled) { 40180e66c1609421dacff3e49770411e201039aa1d8Chris Banes super.setHotspotBounds(left, top, right, bottom); 40280e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 40380e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 40480e66c1609421dacff3e49770411e201039aa1d8Chris Banes 40580e66c1609421dacff3e49770411e201039aa1d8Chris Banes @Override 40680e66c1609421dacff3e49770411e201039aa1d8Chris Banes public boolean setVisible(boolean visible, boolean restart) { 40780e66c1609421dacff3e49770411e201039aa1d8Chris Banes if (mEnabled) { 40880e66c1609421dacff3e49770411e201039aa1d8Chris Banes return super.setVisible(visible, restart); 40980e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 41080e66c1609421dacff3e49770411e201039aa1d8Chris Banes return false; 41180e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 41280e66c1609421dacff3e49770411e201039aa1d8Chris Banes } 41349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes} 414