AllAppsRecyclerView.java revision ac5f6af1488ec1cf0b73aa0848a675764c2f652b
193f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung/* 293f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * Copyright (C) 2015 The Android Open Source Project 393f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * 493f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * Licensed under the Apache License, Version 2.0 (the "License"); 593f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * you may not use this file except in compliance with the License. 693f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * You may obtain a copy of the License at 793f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * 893f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * http://www.apache.org/licenses/LICENSE-2.0 993f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * 1093f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * Unless required by applicable law or agreed to in writing, software 1193f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * distributed under the License is distributed on an "AS IS" BASIS, 1293f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1393f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * See the License for the specific language governing permissions and 1493f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * limitations under the License. 1593f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung */ 165f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chungpackage com.android.launcher3.allapps; 1793f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 1893f98eaf1800024cb2f28379bdd997f3debae63aWinson Chungimport android.content.Context; 1993f98eaf1800024cb2f28379bdd997f3debae63aWinson Chungimport android.graphics.Rect; 2093f98eaf1800024cb2f28379bdd997f3debae63aWinson Chungimport android.graphics.drawable.Drawable; 2124cf70092b8b0281df071891573642f56e34f9e5Winson Chungimport android.support.v7.widget.LinearLayoutManager; 2293f98eaf1800024cb2f28379bdd997f3debae63aWinson Chungimport android.support.v7.widget.RecyclerView; 2393f98eaf1800024cb2f28379bdd997f3debae63aWinson Chungimport android.util.AttributeSet; 24f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chungimport android.view.View; 25ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song 265f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chungimport com.android.launcher3.BaseRecyclerView; 275f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chungimport com.android.launcher3.DeviceProfile; 285f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chungimport com.android.launcher3.Launcher; 295f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chungimport com.android.launcher3.Utilities; 3093f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 3193f98eaf1800024cb2f28379bdd997f3debae63aWinson Chungimport java.util.List; 3293f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 3393f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung/** 34ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song * A RecyclerView with custom fast scroll support for the all apps view. 3593f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung */ 365f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chungpublic class AllAppsRecyclerView extends BaseRecyclerView { 3793f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 3893f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung private AlphabeticalAppsList mApps; 3993f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung private int mNumAppsPerRow; 40208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung private int mNumPredictedAppsPerRow; 4193f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 42208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung private int mPredictionBarHeight; 43f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung private int mScrollbarMinHeight; 44ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song 45ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung private Rect mBackgroundPadding = new Rect(); 4693f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 472e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen private Launcher mLauncher; 482e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen 495f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chung public AllAppsRecyclerView(Context context) { 5093f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung this(context, null); 5193f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 5293f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 535f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chung public AllAppsRecyclerView(Context context, AttributeSet attrs) { 5493f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung this(context, attrs, 0); 5593f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 5693f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 575f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chung public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) { 5893f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung this(context, attrs, defStyleAttr, 0); 5993f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 6093f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 615f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chung public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr, 6293f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung int defStyleRes) { 6393f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung super(context, attrs, defStyleAttr); 642e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen mLauncher = (Launcher) context; 6593f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 6693f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 6793f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung /** 6893f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * Sets the list of apps in this view, used to determine the fastscroll position. 6993f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung */ 7093f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung public void setApps(AlphabeticalAppsList apps) { 7193f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung mApps = apps; 7293f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 7393f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 7493f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung /** 7593f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung * Sets the number of apps per row in this recycler view. 7693f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung */ 77208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung public void setNumAppsPerRow(int numAppsPerRow, int numPredictedAppsPerRow) { 78208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung mNumAppsPerRow = numAppsPerRow; 79208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung mNumPredictedAppsPerRow = numPredictedAppsPerRow; 80da25da3d557177febb9c7afb78e04b1ef4a45f17Winson Chung 812e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen DeviceProfile grid = mLauncher.getDeviceProfile(); 82da25da3d557177febb9c7afb78e04b1ef4a45f17Winson Chung RecyclerView.RecycledViewPool pool = getRecycledViewPool(); 83da25da3d557177febb9c7afb78e04b1ef4a45f17Winson Chung int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx); 845f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chung pool.setMaxRecycledViews(AllAppsGridAdapter.PREDICTION_BAR_SPACER_TYPE, 1); 855f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chung pool.setMaxRecycledViews(AllAppsGridAdapter.EMPTY_SEARCH_VIEW_TYPE, 1); 865f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chung pool.setMaxRecycledViews(AllAppsGridAdapter.ICON_VIEW_TYPE, approxRows * mNumAppsPerRow); 875f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chung pool.setMaxRecycledViews(AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE, approxRows); 8893f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 8993f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 9012fb2cc8ec0dd915259beadacf91a131c6a090b9Sunny Goyal public void updateBackgroundPadding(Drawable background) { 91ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung background.getPadding(mBackgroundPadding); 92ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung } 93ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung 9493f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung /** 95208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung * Sets the prediction bar height. 96208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung */ 97208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung public void setPredictionBarHeight(int height) { 98208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung mPredictionBarHeight = height; 99208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung } 100208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung 101208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung /** 102ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung * Scrolls this recycler view to the top. 103ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung */ 104ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung public void scrollToTop() { 105ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung scrollToPosition(0); 10632f14071cc5808737c88da7b5f3047a8222f8843Winson Chung } 10732f14071cc5808737c88da7b5f3047a8222f8843Winson Chung 10832f14071cc5808737c88da7b5f3047a8222f8843Winson Chung /** 10932f14071cc5808737c88da7b5f3047a8222f8843Winson Chung * Returns the current scroll position. 11032f14071cc5808737c88da7b5f3047a8222f8843Winson Chung */ 11132f14071cc5808737c88da7b5f3047a8222f8843Winson Chung public int getScrollPosition() { 11232f14071cc5808737c88da7b5f3047a8222f8843Winson Chung List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems(); 113ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song getCurScrollState(scrollPosState, items); 114ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song if (scrollPosState.rowIndex != -1) { 11532f14071cc5808737c88da7b5f3047a8222f8843Winson Chung int predictionBarHeight = mApps.getPredictedApps().isEmpty() ? 0 : mPredictionBarHeight; 116ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song return getPaddingTop() + (scrollPosState.rowIndex * scrollPosState.rowHeight) + 117ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song predictionBarHeight - scrollPosState.rowTopOffset; 11832f14071cc5808737c88da7b5f3047a8222f8843Winson Chung } 11932f14071cc5808737c88da7b5f3047a8222f8843Winson Chung return 0; 120ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung } 121ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung 12293f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung @Override 12393f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung protected void onFinishInflate() { 124ebe1734a67dff9ab46f3c6cce328a86b714ce620Hyunyoung Song super.onFinishInflate(); 12593f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung addOnItemTouchListener(this); 12693f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 12793f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 12893f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung /** 12999d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung * Maps the touch (from 0..1) to the adapter position that should be visible. 13093f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung */ 131ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song @Override 132ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song public String scrollToPositionAtProgress(float touchFraction) { 13399d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung // Ensure that we have any sections 13499d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung List<AlphabeticalAppsList.FastScrollSectionInfo> fastScrollSections = 13599d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung mApps.getFastScrollerSections(); 13699d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung if (fastScrollSections.isEmpty()) { 1379121fbffafe0b90a23768e5ebc5fffab2a2175c2Winson Chung return ""; 1389121fbffafe0b90a23768e5ebc5fffab2a2175c2Winson Chung } 13993f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 140208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung // Stop the scroller if it is scrolling 141208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager(); 142208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung stopScroll(); 143208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung 144208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung // If there is a prediction bar, then capture the appropriate area for the prediction bar 145208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung float predictionBarFraction = 0f; 1468c01f810ebcddeb2e9f3a6599c62f701e9c3cac9Winson Chung if (!mApps.getPredictedApps().isEmpty()) { 147208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung predictionBarFraction = (float) mNumPredictedAppsPerRow / mApps.getSize(); 148208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung if (touchFraction <= predictionBarFraction) { 149208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung // Scroll to the top of the view, where the prediction bar is 150208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung layoutManager.scrollToPositionWithOffset(0, 0); 151208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung return ""; 152208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung } 153208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung } 154208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung 155208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung // Since the app ranges are from 0..1, we need to map the touch fraction back to 0..1 from 156208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung // predictionBarFraction..1 157208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung touchFraction = (touchFraction - predictionBarFraction) * 158208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung (1f / (1f - predictionBarFraction)); 15999d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung AlphabeticalAppsList.FastScrollSectionInfo lastScrollSection = fastScrollSections.get(0); 16099d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung for (int i = 1; i < fastScrollSections.size(); i++) { 16199d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung AlphabeticalAppsList.FastScrollSectionInfo scrollSection = fastScrollSections.get(i); 16299d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung if (lastScrollSection.appRangeFraction <= touchFraction && 16399d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung touchFraction < scrollSection.appRangeFraction) { 16493f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung break; 16593f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 16699d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung lastScrollSection = scrollSection; 16793f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 16893f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung 169208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung // Scroll to the view at the position, anchored at the top of the screen. We call the scroll 170208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung // method on the LayoutManager directly since it is not exposed by RecyclerView. 171208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung layoutManager.scrollToPositionWithOffset(lastScrollSection.appItem.position, 0); 172208ed75cfdb02e571273d73d056d8ed7f6f756ebWinson Chung 17399d96ba6c8e3258f7d99a33d49da2aeb0da5d862Winson Chung return lastScrollSection.sectionName; 17493f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung } 175f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung 176ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song 177ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song /** 178ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song * Returns the row index for a app index in the list. 179ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song */ 180ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song private int findRowForAppIndex(int index) { 181ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections(); 182ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song int appIndex = 0; 183ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song int rowCount = 0; 184ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song for (AlphabeticalAppsList.SectionInfo info : sections) { 185ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song int numRowsInSection = (int) Math.ceil((float) info.numApps / mNumAppsPerRow); 186ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song if (appIndex + info.numApps > index) { 187ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song return rowCount + ((index - appIndex) / mNumAppsPerRow); 188ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song } 189ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song appIndex += info.numApps; 190ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song rowCount += numRowsInSection; 191ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song } 192ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song return appIndex; 193ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song } 194ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song 195ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song /** 196ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song * Returns the total number of rows in the list. 197ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song */ 198ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song private int getNumRows() { 199ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections(); 200ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song int rowCount = 0; 201ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song for (AlphabeticalAppsList.SectionInfo info : sections) { 202ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song int numRowsInSection = (int) Math.ceil((float) info.numApps / mNumAppsPerRow); 203ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song rowCount += numRowsInSection; 204ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song } 205ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song return rowCount; 206ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song } 207ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song 208ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song 209f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung /** 210515f2897e876ba52ed6371d22e6d0f7d1016aaf3Winson Chung * Updates the bounds for the scrollbar. 211f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung */ 212ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song @Override 213ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song public void updateVerticalScrollbarBounds() { 21483f59abc9c566da5deb98afe7ea35cfb061f2920Winson Chung List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems(); 21583f59abc9c566da5deb98afe7ea35cfb061f2920Winson Chung 216ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song // Skip early if there are no items. 21783f59abc9c566da5deb98afe7ea35cfb061f2920Winson Chung if (items.isEmpty()) { 218ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song verticalScrollbarBounds.setEmpty(); 219f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung return; 220f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung } 221f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung 222f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung // Find the index and height of the first visible row (all rows have the same height) 223ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song int x, y; 2248c01f810ebcddeb2e9f3a6599c62f701e9c3cac9Winson Chung int predictionBarHeight = mApps.getPredictedApps().isEmpty() ? 0 : mPredictionBarHeight; 225f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung int rowCount = getNumRows(); 226ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song getCurScrollState(scrollPosState, items); 227ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song if (scrollPosState.rowIndex != -1) { 228f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung int height = getHeight() - getPaddingTop() - getPaddingBottom(); 229ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song int totalScrollHeight = rowCount * scrollPosState.rowHeight + predictionBarHeight; 230f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung if (totalScrollHeight > height) { 231f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung int scrollbarHeight = Math.max(mScrollbarMinHeight, 232f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung (int) (height / ((float) totalScrollHeight / height))); 233f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung 234f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung // Calculate the position and size of the scroll bar 23566a90e701ff6f7002fd3ed290ffc25d9c5ff3a9aWinson Chung if (Utilities.isRtl(getResources())) { 236ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung x = mBackgroundPadding.left; 237f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung } else { 238ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song x = getWidth() - mBackgroundPadding.right - getScrollbarWidth(); 239f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung } 240f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung 241f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung // To calculate the offset, we compute the percentage of the total scrollable height 242f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung // that the user has already scrolled and then map that to the scroll bar bounds 243f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung int availableY = totalScrollHeight - height; 244f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung int availableScrollY = height - scrollbarHeight; 245ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song y = (scrollPosState.rowIndex * scrollPosState.rowHeight) + predictionBarHeight 246ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song - scrollPosState.rowTopOffset; 247f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung y = getPaddingTop() + 248f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung (int) (((float) (getPaddingTop() + y) / availableY) * availableScrollY); 249f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung 250ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song verticalScrollbarBounds.set(x, y, x + getScrollbarWidth(), y + scrollbarHeight); 251f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung return; 252f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung } 253f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung } 254ac5f6af1488ec1cf0b73aa0848a675764c2f652bHyunyoung Song verticalScrollbarBounds.setEmpty(); 255f819dc2bc782e93ac9ecc163a99af0da62821d31Winson Chung } 256ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung 257ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung /** 258ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung * Returns the current scroll state. 259ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung */ 260ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung private void getCurScrollState(ScrollPositionState stateOut, 261ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung List<AlphabeticalAppsList.AdapterItem> items) { 262ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung stateOut.rowIndex = -1; 263ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung stateOut.rowTopOffset = -1; 264ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung stateOut.rowHeight = -1; 265532e6ea2e6e4b5f968038b52db9bb998cb9fe84aWinson Chung 266532e6ea2e6e4b5f968038b52db9bb998cb9fe84aWinson Chung // Return early if there are no items 267532e6ea2e6e4b5f968038b52db9bb998cb9fe84aWinson Chung if (items.isEmpty()) { 268532e6ea2e6e4b5f968038b52db9bb998cb9fe84aWinson Chung return; 269532e6ea2e6e4b5f968038b52db9bb998cb9fe84aWinson Chung } 270532e6ea2e6e4b5f968038b52db9bb998cb9fe84aWinson Chung 271ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung int childCount = getChildCount(); 272ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung for (int i = 0; i < childCount; i++) { 273ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung View child = getChildAt(i); 274ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung int position = getChildPosition(child); 275ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung if (position != NO_POSITION) { 276ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung AlphabeticalAppsList.AdapterItem item = items.get(position); 2775f4e0fdd2e4edeb9211e2dcd1c99497f175731f8Winson Chung if (item.viewType == AllAppsGridAdapter.ICON_VIEW_TYPE) { 278ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung stateOut.rowIndex = findRowForAppIndex(item.appIndex); 279ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child); 280ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung stateOut.rowHeight = child.getHeight(); 281ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung break; 282ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung } 283ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung } 284ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung } 285ed0c1cc739d3b3d82c301299db8abc3146de49bbWinson Chung } 28693f98eaf1800024cb2f28379bdd997f3debae63aWinson Chung} 287