1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3.widget; 18 19 import android.content.Context; 20 import android.graphics.Canvas; 21 import android.graphics.Color; 22 import android.support.v7.widget.LinearLayoutManager; 23 import android.util.AttributeSet; 24 import android.view.View; 25 import com.android.launcher3.BaseRecyclerView; 26 import com.android.launcher3.R; 27 import com.android.launcher3.model.PackageItemInfo; 28 import com.android.launcher3.model.WidgetsModel; 29 30 /** 31 * The widgets recycler view. 32 */ 33 public class WidgetsRecyclerView extends BaseRecyclerView { 34 35 private static final String TAG = "WidgetsRecyclerView"; 36 private WidgetsModel mWidgets; 37 private ScrollPositionState mScrollPosState = new ScrollPositionState(); 38 39 public WidgetsRecyclerView(Context context) { 40 this(context, null); 41 } 42 43 public WidgetsRecyclerView(Context context, AttributeSet attrs) { 44 this(context, attrs, 0); 45 } 46 47 public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) { 48 // API 21 and below only support 3 parameter ctor. 49 super(context, attrs, defStyleAttr); 50 } 51 52 public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr, 53 int defStyleRes) { 54 this(context, attrs, defStyleAttr); 55 } 56 57 @Override 58 protected void onFinishInflate() { 59 super.onFinishInflate(); 60 addOnItemTouchListener(this); 61 } 62 63 public int getFastScrollerTrackColor(int defaultTrackColor) { 64 return Color.WHITE; 65 } 66 67 public int getFastScrollerThumbInactiveColor(int defaultInactiveThumbColor) { 68 return getResources().getColor(R.color.widgets_view_fastscroll_thumb_inactive_color); 69 } 70 71 /** 72 * Sets the widget model in this view, used to determine the fast scroll position. 73 */ 74 public void setWidgets(WidgetsModel widgets) { 75 mWidgets = widgets; 76 } 77 78 /** 79 * We need to override the draw to ensure that we don't draw the overscroll effect beyond the 80 * background bounds. 81 */ 82 @Override 83 protected void dispatchDraw(Canvas canvas) { 84 canvas.clipRect(mBackgroundPadding.left, mBackgroundPadding.top, 85 getWidth() - mBackgroundPadding.right, 86 getHeight() - mBackgroundPadding.bottom); 87 super.dispatchDraw(canvas); 88 } 89 90 /** 91 * Maps the touch (from 0..1) to the adapter position that should be visible. 92 */ 93 @Override 94 public String scrollToPositionAtProgress(float touchFraction) { 95 int rowCount = mWidgets.getPackageSize(); 96 if (rowCount == 0) { 97 return ""; 98 } 99 100 // Stop the scroller if it is scrolling 101 stopScroll(); 102 103 getCurScrollState(mScrollPosState); 104 float pos = rowCount * touchFraction; 105 int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight, 0); 106 LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager()); 107 layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction)); 108 109 int posInt = (int) ((touchFraction == 1)? pos -1 : pos); 110 PackageItemInfo p = mWidgets.getPackageItemInfo(posInt); 111 return p.titleSectionName; 112 } 113 114 /** 115 * Updates the bounds for the scrollbar. 116 */ 117 @Override 118 public void onUpdateScrollbar() { 119 int rowCount = mWidgets.getPackageSize(); 120 121 // Skip early if, there are no items. 122 if (rowCount == 0) { 123 mScrollbar.setScrollbarThumbOffset(-1, -1); 124 return; 125 } 126 127 // Skip early if, there no child laid out in the container. 128 getCurScrollState(mScrollPosState); 129 if (mScrollPosState.rowIndex < 0) { 130 mScrollbar.setScrollbarThumbOffset(-1, -1); 131 return; 132 } 133 134 synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount, 0); 135 } 136 137 /** 138 * Returns the current scroll state. 139 */ 140 private void getCurScrollState(ScrollPositionState stateOut) { 141 stateOut.rowIndex = -1; 142 stateOut.rowTopOffset = -1; 143 stateOut.rowHeight = -1; 144 145 int rowCount = mWidgets.getPackageSize(); 146 147 // Return early if there are no items 148 if (rowCount == 0) { 149 return; 150 } 151 View child = getChildAt(0); 152 int position = getChildPosition(child); 153 154 stateOut.rowIndex = position; 155 stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child); 156 stateOut.rowHeight = child.getHeight(); 157 } 158 }