DynamicGrid.java revision 414300a79d140f8c2c8760d9adab750f69ffeafd
131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov/* 231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * Copyright (C) 2008 The Android Open Source Project 331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * 431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License"); 531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * you may not use this file except in compliance with the License. 631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * You may obtain a copy of the License at 731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * 831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * http://www.apache.org/licenses/LICENSE-2.0 931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * 1031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software 1131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS, 1231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * See the License for the specific language governing permissions and 1431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov * limitations under the License. 1531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov */ 1631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 1731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovpackage com.android.launcher3; 1831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 192b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoroimport android.content.res.Configuration; 2031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport android.content.res.Resources; 2179bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikovimport android.graphics.Paint; 2231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport android.graphics.PointF; 2331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport android.graphics.Paint.FontMetrics; 2431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport android.graphics.Rect; 2531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport android.util.DisplayMetrics; 2631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport android.util.TypedValue; 2779bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikovimport android.view.Gravity; 2831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport android.view.View; 2931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport android.view.ViewGroup.LayoutParams; 3031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport android.widget.FrameLayout; 3131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 32a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerdaimport java.util.ArrayList; 3331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport java.util.Collections; 3431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovimport java.util.Comparator; 3531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 3679bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikov 3779bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikovclass DeviceProfileQuery { 3831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float widthDps; 3931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float heightDps; 4027834b2ae8bb5a65dfc20c212844d98d1c252caeDmitri Plotnikov float value; 4179bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikov PointF dimens; 4227834b2ae8bb5a65dfc20c212844d98d1c252caeDmitri Plotnikov 4331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov DeviceProfileQuery(float w, float h, float v) { 4431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov widthDps = w; 4527834b2ae8bb5a65dfc20c212844d98d1c252caeDmitri Plotnikov heightDps = h; 4631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov value = v; 4731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov dimens = new PointF(w, h); 4831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 4965c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann} 5031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 5131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikovclass DeviceProfile { 5231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov String name; 5331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float minWidthDps; 5431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float minHeightDps; 5531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float numRows; 562013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann float numColumns; 572013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann float iconSize; 5831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float iconTextSize; 59a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda float numHotseatIcons; 6031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float hotseatIconSize; 6131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 62b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov boolean isLandscape; 635e684a424e7036ba3d379221d1889b4dd7265021Dave Santoro boolean isTablet; 6431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov boolean isLargeTablet; 65fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov boolean transposeLayoutWithOrientation; 66fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov 67fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int edgeMarginPx; 68fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov 69fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int widthPx; 70fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int heightPx; 71fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int availableWidthPx; 72ea14605e56c98fcaa93f2f1e4186ce9db5e2f159Makoto Onuki int availableHeightPx; 73f0c4681ee4191e47103f8699dd1bf9cf7fc8b669Daisuke Miyakawa int iconSizePx; 74fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int iconTextSizePx; 75fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int cellWidthPx; 76fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int cellHeightPx; 77fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int folderBackgroundOffset; 78fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int folderIconSizePx; 79fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int folderCellWidthPx; 80c86ace78ca5c2e10dcb001a916386c8a9865e230Daniel Lehmann int folderCellHeightPx; 81fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int hotseatCellWidthPx; 82fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int hotseatCellHeightPx; 83fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int hotseatIconSizePx; 84fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int hotseatBarHeightPx; 85fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int searchBarSpaceWidthPx; 86fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int searchBarSpaceMaxWidthPx; 87fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int searchBarSpaceHeightPx; 88fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int searchBarHeightPx; 89fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int pageIndicatorHeightPx; 90fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov 91fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov DeviceProfile(String n, float w, float h, float r, float c, 92fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov float is, float its, float hs, float his) { 93fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov name = n; 94fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov minWidthDps = w; 95fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov minHeightDps = h; 96fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov numRows = r; 97fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov numColumns = c; 98fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov iconSize = is; 99fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov iconTextSize = its; 100fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov numHotseatIcons = hs; 101fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov hotseatIconSize = his; 102fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov } 103fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov 104fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov DeviceProfile(ArrayList<DeviceProfile> profiles, 105fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov float minWidth, float minHeight, 106fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int wPx, int hPx, 107fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov int awPx, int ahPx, 108fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov Resources resources) { 109fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov DisplayMetrics dm = resources.getDisplayMetrics(); 110fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov ArrayList<DeviceProfileQuery> points = 111fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov new ArrayList<DeviceProfileQuery>(); 112fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov transposeLayoutWithOrientation = 113fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov resources.getBoolean(R.bool.hotseat_transpose_layout_with_orientation); 114fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov minWidthDps = minWidth; 115fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov minHeightDps = minHeight; 116fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov 117fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov edgeMarginPx = resources.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin); 118fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov pageIndicatorHeightPx = resources.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_height); 119fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov 120fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov // Interpolate the rows 121fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov for (DeviceProfile p : profiles) { 122fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numRows)); 123a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda } 124a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda numRows = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points)); 125a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda // Interpolate the columns 126a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda points.clear(); 127fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov for (DeviceProfile p : profiles) { 128fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numColumns)); 129fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov } 130fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov numColumns = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points)); 131fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov // Interpolate the icon size 132e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann points.clear(); 13331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov for (DeviceProfile p : profiles) { 13431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconSize)); 13531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 13631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov iconSize = invDistWeightedInterpolate(minWidth, minHeight, points); 13731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov iconSizePx = DynamicGrid.pxFromDp(iconSize, dm); 13831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 13931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Interpolate the icon text size 14031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov points.clear(); 14131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov for (DeviceProfile p : profiles) { 14231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconTextSize)); 14331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 144fa49a66979567894c85fe2489d1375216d67597eDmitri Plotnikov iconTextSize = invDistWeightedInterpolate(minWidth, minHeight, points); 14531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov iconTextSizePx = DynamicGrid.pxFromSp(iconTextSize, dm); 146b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov 147ea14605e56c98fcaa93f2f1e4186ce9db5e2f159Makoto Onuki // Interpolate the hotseat size 14831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov points.clear(); 14931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov for (DeviceProfile p : profiles) { 15031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numHotseatIcons)); 151b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov } 15231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov numHotseatIcons = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points)); 15331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Interpolate the hotseat icon size 15431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov points.clear(); 15531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov for (DeviceProfile p : profiles) { 156b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.hotseatIconSize)); 15731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 15831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Hotseat 15931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov hotseatIconSize = invDistWeightedInterpolate(minWidth, minHeight, points); 16031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov hotseatIconSizePx = DynamicGrid.pxFromDp(hotseatIconSize, dm); 161b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov 16231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Calculate other vars based on Configuration 16331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov updateFromConfiguration(resources, wPx, hPx, awPx, ahPx); 16431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 16531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Search Bar 166b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov searchBarSpaceMaxWidthPx = resources.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_max_width); 16731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov searchBarHeightPx = resources.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_height); 16831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov searchBarSpaceWidthPx = Math.min(searchBarSpaceMaxWidthPx, widthPx); 16931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov searchBarSpaceHeightPx = searchBarHeightPx + 2 * edgeMarginPx; 17031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 171b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov // Calculate the actual text height 17231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov Paint textPaint = new Paint(); 173ea14605e56c98fcaa93f2f1e4186ce9db5e2f159Makoto Onuki textPaint.setTextSize(iconTextSizePx); 174ea14605e56c98fcaa93f2f1e4186ce9db5e2f159Makoto Onuki FontMetrics fm = textPaint.getFontMetrics(); 175ea14605e56c98fcaa93f2f1e4186ce9db5e2f159Makoto Onuki cellWidthPx = iconSizePx; 176ea14605e56c98fcaa93f2f1e4186ce9db5e2f159Makoto Onuki cellHeightPx = iconSizePx + (int) Math.ceil(fm.bottom - fm.top); 177ea14605e56c98fcaa93f2f1e4186ce9db5e2f159Makoto Onuki 17831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // At this point, if the cells do not fit into the available height, then we need 17931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // to shrink the icon size 18031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov /* 181b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov Rect padding = getWorkspacePadding(isLandscape ? 18231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov CellLayout.LANDSCAPE : CellLayout.PORTRAIT); 18331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov int h = (int) (numRows * cellHeightPx) + padding.top + padding.bottom; 18431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov if (h > availableHeightPx) { 18531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float delta = h - availableHeightPx; 186b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov int deltaPx = (int) Math.ceil(delta / numRows); 18731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov iconSizePx -= deltaPx; 18831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov iconSize = DynamicGrid.dpiFromPx(iconSizePx, dm); 18931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov cellWidthPx = iconSizePx; 19031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov cellHeightPx = iconSizePx + (int) Math.ceil(fm.bottom - fm.top); 191b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov } 19231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov */ 19331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 19431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Hotseat 19531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov hotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx; 196b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov hotseatCellWidthPx = iconSizePx; 19731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov hotseatCellHeightPx = iconSizePx; 19831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 19931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Folder 20031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov folderCellWidthPx = cellWidthPx + 3 * edgeMarginPx; 201b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov folderCellHeightPx = cellHeightPx + edgeMarginPx; 20231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov folderBackgroundOffset = -edgeMarginPx; 20331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset; 20431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 20531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 20631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov void updateFromConfiguration(Resources resources, int wPx, int hPx, 20731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov int awPx, int ahPx) { 208b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov isLandscape = (resources.getConfiguration().orientation == 20931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov Configuration.ORIENTATION_LANDSCAPE); 21031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov isTablet = resources.getBoolean(R.bool.is_tablet); 211c86ace78ca5c2e10dcb001a916386c8a9865e230Daniel Lehmann isLargeTablet = resources.getBoolean(R.bool.is_large_tablet); 212c86ace78ca5c2e10dcb001a916386c8a9865e230Daniel Lehmann widthPx = wPx; 213c86ace78ca5c2e10dcb001a916386c8a9865e230Daniel Lehmann heightPx = hPx; 214c86ace78ca5c2e10dcb001a916386c8a9865e230Daniel Lehmann availableWidthPx = awPx; 215c86ace78ca5c2e10dcb001a916386c8a9865e230Daniel Lehmann availableHeightPx = ahPx; 21631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 21731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 218b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov private float dist(PointF p0, PointF p1) { 21931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) + 22031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov (p1.y-p0.y)*(p1.y-p0.y)); 22131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 22231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 223a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda private float weight(PointF a, PointF b, 22431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float pow) { 22531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float d = dist(a, b); 22631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov if (d == 0f) { 22731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov return Float.POSITIVE_INFINITY; 22831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 229a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda return (float) (1f / Math.pow(d, pow)); 23031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 23131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 23231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov private float invDistWeightedInterpolate(float width, float height, 23331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov ArrayList<DeviceProfileQuery> points) { 23431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float sum = 0; 23531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float weights = 0; 236b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov float pow = 5; 23731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float kNearestNeighbors = 3; 23831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov final PointF xy = new PointF(width, height); 23931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 24031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov ArrayList<DeviceProfileQuery> pointsByNearness = points; 24131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov Collections.sort(pointsByNearness, new Comparator<DeviceProfileQuery>() { 242b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov public int compare(DeviceProfileQuery a, DeviceProfileQuery b) { 24331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov return (int) (dist(xy, a.dimens) - dist(xy, b.dimens)); 24431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 24531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov }); 24631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 24731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov for (int i = 0; i < pointsByNearness.size(); ++i) { 248b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov DeviceProfileQuery p = pointsByNearness.get(i); 24931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov if (i < kNearestNeighbors) { 25031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float w = weight(xy, p.dimens, pow); 25131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov if (w == Float.POSITIVE_INFINITY) { 25231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov return p.value; 25331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 254b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov weights += w; 25531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 25631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 25731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 25831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov for (int i = 0; i < pointsByNearness.size(); ++i) { 25931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov DeviceProfileQuery p = pointsByNearness.get(i); 260b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov if (i < kNearestNeighbors) { 26131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov float w = weight(xy, p.dimens, pow); 26231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov sum += w * p.value / weights; 26331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 26431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 26531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 266b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov return sum; 26731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 26831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 26931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov Rect getWorkspacePadding(int orientation) { 27031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov Rect padding = new Rect(); 27186092529f272b7ed2cee24fae397291696b29b80Dmitri Plotnikov if (orientation == CellLayout.LANDSCAPE && 27286092529f272b7ed2cee24fae397291696b29b80Dmitri Plotnikov transposeLayoutWithOrientation) { 27386092529f272b7ed2cee24fae397291696b29b80Dmitri Plotnikov // Pad the left and right of the workspace with search/hotseat bar sizes 27431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov padding.set(searchBarSpaceHeightPx, edgeMarginPx, 27531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov hotseatBarHeightPx, edgeMarginPx); 27631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } else { 27731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov if (isTablet()) { 27831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Pad the left and right of the workspace to ensure consistent spacing 27931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // between all icons 28031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov int width = (orientation == CellLayout.LANDSCAPE) 28131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov ? Math.max(widthPx, heightPx) 28231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov : Math.min(widthPx, heightPx); 28331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // XXX: If the icon size changes across orientations, we will have to take 28431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // that into account here too. 28531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov int gap = (int) ((width - 2 * edgeMarginPx - 2867b8f74678640b571196557d64dd712dc4a109c49Dmitri Plotnikov (numColumns * cellWidthPx)) / (2 * (numColumns + 1))); 28731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov padding.set(edgeMarginPx + gap, 28831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov searchBarSpaceHeightPx, 28931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov edgeMarginPx + gap, 29031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov hotseatBarHeightPx + pageIndicatorHeightPx); 2917b8f74678640b571196557d64dd712dc4a109c49Dmitri Plotnikov } else { 29231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Pad the top and bottom of the workspace with search/hotseat bar sizes 29331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov padding.set(edgeMarginPx, 29431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov searchBarSpaceHeightPx, 2957b8f74678640b571196557d64dd712dc4a109c49Dmitri Plotnikov edgeMarginPx, 29631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov hotseatBarHeightPx + pageIndicatorHeightPx); 29731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 29831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 29931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov return padding; 30031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 30131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 30231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov int calculateCellWidth(int width, int countX) { 30331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov return width / countX; 30431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 305b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov int calculateCellHeight(int height, int countY) { 30631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov return height / countY; 30731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 30831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 30931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov boolean isTablet() { 31031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov return isTablet; 31131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } 31231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 31331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov boolean isLargeTablet() { 31431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov return isLargeTablet; 315b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov } 31631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 31731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov public void layout(Launcher launcher) { 31831ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov FrameLayout.LayoutParams lp; 31931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov Resources res = launcher.getResources(); 32031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov boolean hasVerticalBarLayout = isLandscape && 32131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation); 322b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov 32331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Layout the search bar space 32431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov View searchBarSpace = launcher.findViewById(R.id.qsb_bar); 32531ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov lp = (FrameLayout.LayoutParams) searchBarSpace.getLayoutParams(); 32631ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov if (hasVerticalBarLayout) { 32731ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov // Vertical search bar 328b979b4294c14f2bc562a5279910bafb7ac1a92b4Dmitri Plotnikov lp.gravity = Gravity.TOP | Gravity.LEFT; 32931ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov lp.width = searchBarSpaceHeightPx; 33031ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov lp.height = LayoutParams.MATCH_PARENT; 33131ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov searchBarSpace.setPadding( 33231ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 0, 2 * edgeMarginPx, 0, 33331ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov 2 * edgeMarginPx); 33431ec0b51ac4d508f8727608b98d0bf916f2b20b9Dmitri Plotnikov } else { 33565c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann // Horizontal search bar 33665c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; 33765c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.width = searchBarSpaceWidthPx; 33865c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.height = searchBarSpaceHeightPx; 33965c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann searchBarSpace.setPadding( 34065c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 2 * edgeMarginPx, 34165c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 2 * edgeMarginPx, 34265c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 2 * edgeMarginPx, 0); 34365c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann } 34465c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann searchBarSpace.setLayoutParams(lp); 34565c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 34665c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann // Layout the search bar 34765c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann View searchBar = launcher.getQsbBar(); 34865c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams(); 34965c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.width = LayoutParams.MATCH_PARENT; 35065c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.height = LayoutParams.MATCH_PARENT; 35165c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann searchBar.setLayoutParams(lp); 35265c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 35365c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann // Layout the voice proxy 35465c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann View voiceButtonProxy = launcher.findViewById(R.id.voice_button_proxy); 35565c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann if (voiceButtonProxy != null) { 35665c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann if (hasVerticalBarLayout) { 35765c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann // TODO: MOVE THIS INTO SEARCH BAR MEASURE 35865c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann } else { 35965c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp = (FrameLayout.LayoutParams) voiceButtonProxy.getLayoutParams(); 36065c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.gravity = Gravity.TOP | Gravity.END; 36165c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.width = (widthPx - searchBarSpaceWidthPx) / 2 + 36265c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 2 * iconSizePx; 36365c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.height = searchBarSpaceHeightPx; 36465c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann } 36565c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann } 36665c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 36765c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann // Layout the workspace 36865c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann View workspace = launcher.findViewById(R.id.workspace); 36965c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp = (FrameLayout.LayoutParams) workspace.getLayoutParams(); 37065c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.gravity = Gravity.CENTER; 37165c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann Rect padding = getWorkspacePadding(isLandscape 37265c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann ? CellLayout.LANDSCAPE 37365c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann : CellLayout.PORTRAIT); 37465c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann workspace.setPadding(padding.left, padding.top, 37565c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann padding.right, padding.bottom); 37665c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann workspace.setLayoutParams(lp); 37765c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 37865c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann // Layout the hotseat 37965c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann View hotseat = launcher.findViewById(R.id.hotseat); 38065c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams(); 38165c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann if (hasVerticalBarLayout) { 38279bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikov // Vertical hotseat 38379bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikov lp.gravity = Gravity.RIGHT; 38479bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikov lp.width = hotseatBarHeightPx; 38586092529f272b7ed2cee24fae397291696b29b80Dmitri Plotnikov lp.height = LayoutParams.MATCH_PARENT; 38679bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikov hotseat.setPadding(0, 2 * edgeMarginPx, 38779bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikov 2 * edgeMarginPx, 2 * edgeMarginPx); 38879bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikov } else if (isTablet()) { 38979bea93fe361aac5b4928ef090b5021bcba99428Dmitri Plotnikov // Pad the hotseat with the grid gap calculated above 3902013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann int gridGap = (int) ((widthPx - 2 * edgeMarginPx - 3912013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann (numColumns * cellWidthPx)) / (2 * (numColumns + 1))); 3922013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann int gridWidth = (int) ((numColumns * cellWidthPx) + 3932013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann ((numColumns - 1) * gridGap)); 3942013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann int hotseatGap = (int) Math.max(0, 3952013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann (gridWidth - (numHotseatIcons * hotseatCellWidthPx)) 3962013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann / (numHotseatIcons - 1)); 39765c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.gravity = Gravity.BOTTOM; 39865c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.width = LayoutParams.MATCH_PARENT; 39965c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann lp.height = hotseatBarHeightPx; 40065c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann hotseat.setPadding(2 * edgeMarginPx + gridGap + hotseatGap, 0, 40165c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 2 * edgeMarginPx + gridGap + hotseatGap, 40265c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann 2 * edgeMarginPx); 40365c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann } else { 40465c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann // For phones, layout the hotseat without any bottom margin 40565c90e23a0c141d390fc2177a1b461646f4f8a3aDaniel Lehmann // to ensure that we have space for the folders 4063b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann lp.gravity = Gravity.BOTTOM; 4073b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann lp.width = LayoutParams.MATCH_PARENT; 4083b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann lp.height = hotseatBarHeightPx; 4093b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann hotseat.setPadding(2 * edgeMarginPx, 0, 4103b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann 2 * edgeMarginPx, 0); 4113b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann } 4123b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann hotseat.setLayoutParams(lp); 413f0c4681ee4191e47103f8699dd1bf9cf7fc8b669Daisuke Miyakawa 414f0c4681ee4191e47103f8699dd1bf9cf7fc8b669Daisuke Miyakawa // Layout the page indicators 415f0c4681ee4191e47103f8699dd1bf9cf7fc8b669Daisuke Miyakawa View pageIndicator = launcher.findViewById(R.id.page_indicator); 416f0c4681ee4191e47103f8699dd1bf9cf7fc8b669Daisuke Miyakawa if (pageIndicator != null) { 4173b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann if (hasVerticalBarLayout) { 4183b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann // Hide the page indicators when we have vertical search/hotseat 4193b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann pageIndicator.setVisibility(View.GONE); 4203b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann } else { 4213b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann // Put the page indicators above the hotseat 4223b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams(); 4233b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 4243b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann lp.width = LayoutParams.WRAP_CONTENT; 4253b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann lp.height = pageIndicatorHeightPx; 4263b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann lp.bottomMargin = hotseatBarHeightPx; 4273b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann pageIndicator.setLayoutParams(lp); 4283b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann } 4293b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann } 4303b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann } 4313b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann} 4323b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann 4333b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmannpublic class DynamicGrid { 4343b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann @SuppressWarnings("unused") 4353b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann private static final String TAG = "DynamicGrid"; 4363b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann 4373b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann private DeviceProfile mProfile; 4383b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann private float mMinWidth; 4393b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann private float mMinHeight; 4403b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann 4413b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann public static float dpiFromPx(int size, DisplayMetrics metrics){ 4423b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT; 4433b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann return (size / densityRatio); 4443b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann } 4453b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann public static int pxFromDp(float size, DisplayMetrics metrics) { 4463b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4473b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann size, metrics)); 4483b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann } 4493b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann public static int pxFromSp(float size, DisplayMetrics metrics) { 4503b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 4513b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann size, metrics)); 4523b7d5949bfa524534e5d1aa29b8eaff8733ae00cDaniel Lehmann } 453e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 454e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann public DynamicGrid(Resources resources, int minWidthPx, int minHeightPx, 455e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann int widthPx, int heightPx, 456e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann int awPx, int ahPx) { 457e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann DisplayMetrics dm = resources.getDisplayMetrics(); 458e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann ArrayList<DeviceProfile> deviceProfiles = 459e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann new ArrayList<DeviceProfile>(); 460e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann // Our phone profiles include the bar sizes in each orientation 461e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Super Short Stubby", 462e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 255, 300, 2, 3, 48, 12, 4, 48)); 463e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Shorter Stubby", 464e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 255, 400, 3, 3, 48, 12, 4, 48)); 465e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Short Stubby", 466e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 275, 420, 3, 4, 48, 12, 4, 48)); 467e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Stubby", 468e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 255, 450, 3, 4, 48, 12, 4, 48)); 469e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Nexus S", 470e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 296, 491.33f, 4, 4, 48, 12, 4, 48)); 471e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Nexus 4", 472e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 359, 518, 4, 4, 60, 12, 5, 56)); 473e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann // The tablet profile is odd in that the landscape orientation 474e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann // also includes the nav bar on the side 475e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Nexus 7", 476e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 575, 904, 6, 6, 72, 14.4f, 7, 60)); 477e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann // Larger tablet profiles always have system bars on the top & bottom 478e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Nexus 10", 479e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 727, 1207, 5, 8, 80, 14.4f, 9, 64)); 480e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann /* 481e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Nexus 7", 482e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 600, 960, 5, 5, 72, 14.4f, 5, 60)); 483e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("Nexus 10", 484e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 800, 1280, 5, 5, 80, 14.4f, 6, 64)); 485e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann */ 486e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann deviceProfiles.add(new DeviceProfile("20-inch Tablet", 487e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann 1527, 2527, 7, 7, 100, 20, 7, 72)); 488e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann mMinWidth = dpiFromPx(minWidthPx, dm); 489e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann mMinHeight = dpiFromPx(minHeightPx, dm); 490e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann mProfile = new DeviceProfile(deviceProfiles, 491e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann mMinWidth, mMinHeight, 492e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann widthPx, heightPx, 493e9b196e446cc34f690a043c5f5d9e5a7b8b92b3fDaniel Lehmann awPx, ahPx, 494a126cddda7a8df442a1c4d63b4412d50c83725a6Daniel Lehmann resources); 495a126cddda7a8df442a1c4d63b4412d50c83725a6Daniel Lehmann } 496a126cddda7a8df442a1c4d63b4412d50c83725a6Daniel Lehmann 497a126cddda7a8df442a1c4d63b4412d50c83725a6Daniel Lehmann DeviceProfile getDeviceProfile() { 498a126cddda7a8df442a1c4d63b4412d50c83725a6Daniel Lehmann return mProfile; 499a126cddda7a8df442a1c4d63b4412d50c83725a6Daniel Lehmann } 500a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda 501a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda public String toString() { 502a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda return "-------- DYNAMIC GRID ------- \n" + 503a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda "Wd: " + mProfile.minWidthDps + ", Hd: " + mProfile.minHeightDps + 504a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda ", W: " + mProfile.widthPx + ", H: " + mProfile.heightPx + 505a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda " [r: " + mProfile.numRows + ", c: " + mProfile.numColumns + 506a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda ", is: " + mProfile.iconSizePx + ", its: " + mProfile.iconTextSize + 507a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda ", cw: " + mProfile.cellWidthPx + ", ch: " + mProfile.cellHeightPx + 508a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda ", hc: " + mProfile.numHotseatIcons + ", his: " + mProfile.hotseatIconSizePx + "]"; 509a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda } 510a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda} 511a4aa90ce861ea56f403aa244905c9a4e326f2a10Flavio Lerda