DeviceProfile.java revision c32c63c46e933fb6c9038f6e18f24a2fef7eff9c
1/* 2 * Copyright (C) 2008 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 17package com.android.launcher3; 18 19import android.appwidget.AppWidgetHostView; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.res.Resources; 23import android.graphics.Paint; 24import android.graphics.Paint.FontMetrics; 25import android.graphics.Point; 26import android.graphics.Rect; 27import android.util.DisplayMetrics; 28import android.view.Gravity; 29import android.view.View; 30import android.view.ViewGroup; 31import android.view.ViewGroup.LayoutParams; 32import android.view.ViewGroup.MarginLayoutParams; 33import android.widget.FrameLayout; 34import android.widget.LinearLayout; 35 36public class DeviceProfile { 37 38 public final InvariantDeviceProfile inv; 39 40 // Device properties 41 public final boolean isTablet; 42 public final boolean isLargeTablet; 43 public final boolean isPhone; 44 public final boolean transposeLayoutWithOrientation; 45 46 // Device properties in current orientation 47 public final boolean isLandscape; 48 public final int widthPx; 49 public final int heightPx; 50 public final int availableWidthPx; 51 public final int availableHeightPx; 52 /** 53 * The maximum amount of left/right workspace padding as a percentage of the screen width. 54 * To be clear, this means that up to 7% of the screen width can be used as left padding, and 55 * 7% of the screen width can be used as right padding. 56 */ 57 private static final float MAX_HORIZONTAL_PADDING_PERCENT = 0.14f; 58 59 // Overview mode 60 private final int overviewModeMinIconZoneHeightPx; 61 private final int overviewModeMaxIconZoneHeightPx; 62 private final int overviewModeBarItemWidthPx; 63 private final int overviewModeBarSpacerWidthPx; 64 private final float overviewModeIconZoneRatio; 65 66 // Workspace 67 private int desiredWorkspaceLeftRightMarginPx; 68 public final int edgeMarginPx; 69 public final Rect defaultWidgetPadding; 70 private final int pageIndicatorHeightPx; 71 private final int defaultPageSpacingPx; 72 private float dragViewScale; 73 74 // Workspace icons 75 public int iconSizePx; 76 public int iconTextSizePx; 77 public int iconDrawablePaddingPx; 78 public int iconDrawablePaddingOriginalPx; 79 80 public int cellWidthPx; 81 public int cellHeightPx; 82 83 // Folder 84 public int folderBackgroundOffset; 85 public int folderIconSizePx; 86 public int folderCellWidthPx; 87 public int folderCellHeightPx; 88 89 // Hotseat 90 public int hotseatCellWidthPx; 91 public int hotseatCellHeightPx; 92 public int hotseatIconSizePx; 93 private int normalHotseatBarHeightPx, shortHotseatBarHeightPx; 94 private int hotseatBarHeightPx; // One of the above. 95 96 // All apps 97 public int allAppsNumCols; 98 public int allAppsNumPredictiveCols; 99 public int allAppsButtonVisualSize; 100 public final int allAppsIconSizePx; 101 public final float allAppsIconTextSizeSp; 102 103 // QSB 104 private int searchBarWidgetInternalPaddingTop, searchBarWidgetInternalPaddingBottom; 105 private int searchBarTopPaddingPx; 106 private int tallSearchBarNegativeTopPaddingPx, normalSearchBarTopExtraPaddingPx; 107 private int searchBarTopExtraPaddingPx; // One of the above. 108 private int normalSearchBarBottomPaddingPx, tallSearchBarBottomPaddingPx; 109 private int searchBarBottomPaddingPx; // One of the above. 110 private int normalSearchBarSpaceHeightPx, tallSearchBarSpaceHeightPx; 111 private int searchBarSpaceHeightPx; // One of the above. 112 113 public DeviceProfile(Context context, InvariantDeviceProfile inv, 114 Point minSize, Point maxSize, 115 int width, int height, boolean isLandscape) { 116 117 this.inv = inv; 118 this.isLandscape = isLandscape; 119 120 Resources res = context.getResources(); 121 DisplayMetrics dm = res.getDisplayMetrics(); 122 123 // Constants from resources 124 isTablet = res.getBoolean(R.bool.is_tablet); 125 isLargeTablet = res.getBoolean(R.bool.is_large_tablet); 126 isPhone = !isTablet && !isLargeTablet; 127 128 // Some more constants 129 transposeLayoutWithOrientation = 130 res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation); 131 132 ComponentName cn = new ComponentName(context.getPackageName(), 133 this.getClass().getName()); 134 defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null); 135 edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin); 136 desiredWorkspaceLeftRightMarginPx = 2 * edgeMarginPx; 137 pageIndicatorHeightPx = 138 res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_height); 139 defaultPageSpacingPx = 140 res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing); 141 overviewModeMinIconZoneHeightPx = 142 res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_min_icon_zone_height); 143 overviewModeMaxIconZoneHeightPx = 144 res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_max_icon_zone_height); 145 overviewModeBarItemWidthPx = 146 res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_item_width); 147 overviewModeBarSpacerWidthPx = 148 res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_spacer_width); 149 overviewModeIconZoneRatio = 150 res.getInteger(R.integer.config_dynamic_grid_overview_icon_zone_percentage) / 100f; 151 iconDrawablePaddingOriginalPx = 152 res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding); 153 154 // AllApps uses the original non-scaled icon text size 155 allAppsIconTextSizeSp = inv.iconTextSize; 156 157 // AllApps uses the original non-scaled icon size 158 allAppsIconSizePx = Utilities.pxFromDp(inv.iconSize, dm); 159 160 // Determine sizes. 161 widthPx = width; 162 heightPx = height; 163 if (isLandscape) { 164 availableWidthPx = maxSize.x; 165 availableHeightPx = minSize.y; 166 } else { 167 availableWidthPx = minSize.x; 168 availableHeightPx = maxSize.y; 169 } 170 171 // Calculate the remaining vars 172 updateAvailableDimensions(dm, res); 173 computeAllAppsButtonSize(context); 174 } 175 176 /** 177 * Determine the exact visual footprint of the all apps button, taking into account scaling 178 * and internal padding of the drawable. 179 */ 180 private void computeAllAppsButtonSize(Context context) { 181 Resources res = context.getResources(); 182 float padding = res.getInteger(R.integer.config_allAppsButtonPaddingPercent) / 100f; 183 allAppsButtonVisualSize = (int) (hotseatIconSizePx * (1 - padding)) - context.getResources() 184 .getDimensionPixelSize(R.dimen.all_apps_button_scale_down); 185 } 186 187 private void updateAvailableDimensions(DisplayMetrics dm, Resources res) { 188 // Check to see if the icons fit in the new available height. If not, then we need to 189 // shrink the icon size. 190 float scale = 1f; 191 int drawablePadding = iconDrawablePaddingOriginalPx; 192 updateIconSize(1f, drawablePadding, res, dm); 193 float usedHeight = (cellHeightPx * inv.numRows); 194 195 // We only care about the top and bottom workspace padding, which is not affected by RTL. 196 Rect workspacePadding = getWorkspacePadding(false /* isLayoutRtl */); 197 int maxHeight = (availableHeightPx - workspacePadding.top - workspacePadding.bottom); 198 if (usedHeight > maxHeight) { 199 scale = maxHeight / usedHeight; 200 drawablePadding = 0; 201 } 202 updateIconSize(scale, drawablePadding, res, dm); 203 } 204 205 private void updateIconSize(float scale, int drawablePadding, Resources res, 206 DisplayMetrics dm) { 207 iconSizePx = (int) (Utilities.pxFromDp(inv.iconSize, dm) * scale); 208 iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale); 209 iconDrawablePaddingPx = drawablePadding; 210 hotseatIconSizePx = (int) (Utilities.pxFromDp(inv.hotseatIconSize, dm) * scale); 211 212 // Search Bar 213 normalSearchBarSpaceHeightPx = res.getDimensionPixelSize( 214 R.dimen.dynamic_grid_search_bar_height); 215 tallSearchBarSpaceHeightPx = res.getDimensionPixelSize( 216 R.dimen.dynamic_grid_search_bar_height_tall); 217 searchBarWidgetInternalPaddingTop = res.getDimensionPixelSize( 218 R.dimen.qsb_internal_padding_top); 219 searchBarWidgetInternalPaddingBottom = res.getDimensionPixelSize( 220 R.dimen.qsb_internal_padding_bottom); 221 normalSearchBarTopExtraPaddingPx = res.getDimensionPixelSize( 222 R.dimen.dynamic_grid_search_bar_extra_top_padding); 223 tallSearchBarNegativeTopPaddingPx = res.getDimensionPixelSize( 224 R.dimen.dynamic_grid_search_bar_negative_top_padding_short); 225 if (isTablet && !isVerticalBarLayout()) { 226 searchBarTopPaddingPx = searchBarWidgetInternalPaddingTop; 227 normalSearchBarBottomPaddingPx = searchBarWidgetInternalPaddingBottom + 228 res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_bottom_padding_tablet); 229 tallSearchBarBottomPaddingPx = normalSearchBarBottomPaddingPx; 230 } else { 231 searchBarTopPaddingPx = searchBarWidgetInternalPaddingTop; 232 normalSearchBarBottomPaddingPx = searchBarWidgetInternalPaddingBottom + 233 res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_bottom_padding); 234 tallSearchBarBottomPaddingPx = searchBarWidgetInternalPaddingBottom 235 + res.getDimensionPixelSize( 236 R.dimen.dynamic_grid_search_bar_bottom_negative_padding_short); 237 } 238 239 // Calculate the actual text height 240 Paint textPaint = new Paint(); 241 textPaint.setTextSize(iconTextSizePx); 242 FontMetrics fm = textPaint.getFontMetrics(); 243 cellWidthPx = iconSizePx; 244 cellHeightPx = iconSizePx + iconDrawablePaddingPx + (int) Math.ceil(fm.bottom - fm.top); 245 final float scaleDps = res.getDimensionPixelSize(R.dimen.dragViewScale); 246 dragViewScale = (iconSizePx + scaleDps) / iconSizePx; 247 248 // Hotseat 249 normalHotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx; 250 shortHotseatBarHeightPx = iconSizePx + 2 * edgeMarginPx; 251 hotseatCellWidthPx = iconSizePx; 252 hotseatCellHeightPx = iconSizePx; 253 254 // Folder 255 int folderCellPadding = isTablet || isLandscape ? 6 * edgeMarginPx : 3 * edgeMarginPx; 256 // Don't let the folder get too close to the edges of the screen. 257 folderCellWidthPx = Math.min(cellWidthPx + folderCellPadding, 258 (availableWidthPx - 4 * edgeMarginPx) / inv.numFolderColumns); 259 folderCellHeightPx = cellHeightPx + edgeMarginPx; 260 folderBackgroundOffset = -edgeMarginPx; 261 folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset; 262 } 263 264 /** 265 * @param recyclerViewWidth the available width of the AllAppsRecyclerView 266 */ 267 public void updateAppsViewNumCols(Resources res, int recyclerViewWidth) { 268 int appsViewLeftMarginPx = 269 res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin); 270 int allAppsCellWidthGap = 271 res.getDimensionPixelSize(R.dimen.all_apps_icon_width_gap); 272 int availableAppsWidthPx = (recyclerViewWidth > 0) ? recyclerViewWidth : availableWidthPx; 273 int numAppsCols = (availableAppsWidthPx - appsViewLeftMarginPx) / 274 (allAppsIconSizePx + allAppsCellWidthGap); 275 int numPredictiveAppCols = Math.max(inv.minAllAppsPredictionColumns, numAppsCols); 276 allAppsNumCols = numAppsCols; 277 allAppsNumPredictiveCols = numPredictiveAppCols; 278 } 279 280 /** Returns the amount of extra space to allocate to the search bar for vertical padding. */ 281 private int getSearchBarTotalVerticalPadding() { 282 return searchBarTopPaddingPx + searchBarTopExtraPaddingPx + searchBarBottomPaddingPx; 283 } 284 285 /** Returns the width and height of the search bar, ignoring any padding. */ 286 public Point getSearchBarDimensForWidgetOpts(Resources res) { 287 Rect searchBarBounds = getSearchBarBounds(Utilities.isRtl(res)); 288 if (isVerticalBarLayout()) { 289 return new Point(searchBarBounds.width(), searchBarBounds.height()); 290 } 291 int widgetInternalPadding = searchBarWidgetInternalPaddingTop + 292 searchBarWidgetInternalPaddingBottom; 293 return new Point(searchBarBounds.width(), searchBarSpaceHeightPx + widgetInternalPadding); 294 } 295 296 /** Returns the search bar bounds in the current orientation */ 297 public Rect getSearchBarBounds(boolean isLayoutRtl) { 298 Rect bounds = new Rect(); 299 if (isVerticalBarLayout()) { 300 if (isLayoutRtl) { 301 bounds.set(availableWidthPx - normalSearchBarSpaceHeightPx, edgeMarginPx, 302 availableWidthPx, availableHeightPx - edgeMarginPx); 303 } else { 304 bounds.set(0, edgeMarginPx, normalSearchBarSpaceHeightPx, 305 availableHeightPx - edgeMarginPx); 306 } 307 } else { 308 int boundsBottom = searchBarSpaceHeightPx + getSearchBarTotalVerticalPadding(); 309 if (isTablet) { 310 // Pad the left and right of the workspace to ensure consistent spacing 311 // between all icons 312 int width = getCurrentWidth(); 313 // XXX: If the icon size changes across orientations, we will have to take 314 // that into account here too. 315 int gap = (int) ((width - 2 * edgeMarginPx - 316 (inv.numColumns * cellWidthPx)) / (2 * (inv.numColumns + 1))); 317 bounds.set(edgeMarginPx + gap, 0, 318 availableWidthPx - (edgeMarginPx + gap), boundsBottom); 319 } else { 320 bounds.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left, 321 0, 322 availableWidthPx - (desiredWorkspaceLeftRightMarginPx - 323 defaultWidgetPadding.right), boundsBottom); 324 } 325 } 326 return bounds; 327 } 328 329 public Point getCellSize() { 330 Point result = new Point(); 331 // Since we are only concerned with the overall padding, layout direction does 332 // not matter. 333 Rect padding = getWorkspacePadding(false /* isLayoutRtl */ ); 334 result.x = calculateCellWidth(availableWidthPx - padding.left - padding.right, 335 inv.numColumns); 336 result.y = calculateCellHeight(availableHeightPx - padding.top - padding.bottom, 337 inv.numRows); 338 return result; 339 } 340 341 /** Returns the workspace padding in the specified orientation */ 342 Rect getWorkspacePadding(boolean isLayoutRtl) { 343 Rect searchBarBounds = getSearchBarBounds(isLayoutRtl); 344 Rect padding = new Rect(); 345 if (isVerticalBarLayout()) { 346 // Pad the left and right of the workspace with search/hotseat bar sizes 347 if (isLayoutRtl) { 348 padding.set(normalHotseatBarHeightPx, edgeMarginPx, 349 searchBarBounds.width(), edgeMarginPx); 350 } else { 351 padding.set(searchBarBounds.width(), edgeMarginPx, 352 normalHotseatBarHeightPx, edgeMarginPx); 353 } 354 } else { 355 int paddingTop = searchBarBounds.bottom; 356 int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx; 357 if (isTablet) { 358 // Pad the left and right of the workspace to ensure consistent spacing 359 // between all icons 360 float gapScale = 1f + (dragViewScale - 1f) / 2f; 361 int width = getCurrentWidth(); 362 int height = getCurrentHeight(); 363 // The amount of screen space available for left/right padding. 364 int availablePaddingX = Math.max(0, width - (int) ((inv.numColumns * cellWidthPx) + 365 ((inv.numColumns - 1) * gapScale * cellWidthPx))); 366 availablePaddingX = (int) Math.min(availablePaddingX, 367 width * MAX_HORIZONTAL_PADDING_PERCENT); 368 int availablePaddingY = Math.max(0, height - paddingTop - paddingBottom 369 - (int) (2 * inv.numRows * cellHeightPx)); 370 padding.set(availablePaddingX / 2, paddingTop + availablePaddingY / 2, 371 availablePaddingX / 2, paddingBottom + availablePaddingY / 2); 372 } else { 373 // Pad the top and bottom of the workspace with search/hotseat bar sizes 374 padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left, 375 paddingTop, 376 desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right, 377 paddingBottom); 378 } 379 } 380 return padding; 381 } 382 383 private int getWorkspacePageSpacing(boolean isLayoutRtl) { 384 if (isVerticalBarLayout() || isLargeTablet) { 385 // In landscape mode the page spacing is set to the default. 386 return defaultPageSpacingPx; 387 } else { 388 // In portrait, we want the pages spaced such that there is no 389 // overhang of the previous / next page into the current page viewport. 390 // We assume symmetrical padding in portrait mode. 391 return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding(isLayoutRtl).left); 392 } 393 } 394 395 int getOverviewModeButtonBarHeight() { 396 int zoneHeight = (int) (overviewModeIconZoneRatio * availableHeightPx); 397 zoneHeight = Math.min(overviewModeMaxIconZoneHeightPx, 398 Math.max(overviewModeMinIconZoneHeightPx, zoneHeight)); 399 return zoneHeight; 400 } 401 402 // The rect returned will be extended to below the system ui that covers the workspace 403 public boolean isInHotseatRect(int x, int y) { 404 if (isVerticalBarLayout()) { 405 return (x >= (availableWidthPx - hotseatBarHeightPx)) 406 && (y >= 0) && (y <= availableHeightPx); 407 } else { 408 return (x >= 0) && (x <= availableWidthPx) 409 && (y >= (availableHeightPx - hotseatBarHeightPx)); 410 } 411 } 412 413 public static int calculateCellWidth(int width, int countX) { 414 return width / countX; 415 } 416 public static int calculateCellHeight(int height, int countY) { 417 return height / countY; 418 } 419 420 /** 421 * When {@code true}, the device is in landscape mode and the hotseat is on the right column. 422 * When {@code false}, either device is in portrait mode or the device is in landscape mode and 423 * the hotseat is on the bottom row. 424 */ 425 public boolean isVerticalBarLayout() { 426 return isLandscape && transposeLayoutWithOrientation; 427 } 428 429 boolean shouldFadeAdjacentWorkspaceScreens() { 430 return isVerticalBarLayout() || isLargeTablet; 431 } 432 433 private int getVisibleChildCount(ViewGroup parent) { 434 int visibleChildren = 0; 435 for (int i = 0; i < parent.getChildCount(); i++) { 436 if (parent.getChildAt(i).getVisibility() != View.GONE) { 437 visibleChildren++; 438 } 439 } 440 return visibleChildren; 441 } 442 443 // TODO(twickham): b/25154513 444 public void setSearchBarHeight(int searchBarHeight) { 445 if (searchBarHeight == LauncherCallbacks.SEARCH_BAR_HEIGHT_TALL) { 446 hotseatBarHeightPx = shortHotseatBarHeightPx; 447 searchBarSpaceHeightPx = tallSearchBarSpaceHeightPx; 448 searchBarBottomPaddingPx = tallSearchBarBottomPaddingPx; 449 searchBarTopExtraPaddingPx = isPhone ? tallSearchBarNegativeTopPaddingPx 450 : normalSearchBarTopExtraPaddingPx; 451 } else { 452 hotseatBarHeightPx = normalHotseatBarHeightPx; 453 searchBarSpaceHeightPx = normalSearchBarSpaceHeightPx; 454 searchBarBottomPaddingPx = normalSearchBarBottomPaddingPx; 455 searchBarTopExtraPaddingPx = normalSearchBarTopExtraPaddingPx; 456 } 457 } 458 459 public void layout(Launcher launcher) { 460 FrameLayout.LayoutParams lp; 461 boolean hasVerticalBarLayout = isVerticalBarLayout(); 462 final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources()); 463 464 // Layout the search bar space 465 Rect searchBarBounds = getSearchBarBounds(isLayoutRtl); 466 View searchBar = launcher.getSearchDropTargetBar(); 467 lp = getDropTargetBarLayoutParams(hasVerticalBarLayout, searchBar, Gravity.TOP); 468 lp.width = searchBarBounds.width(); 469 lp.height = searchBarBounds.height(); 470 lp.topMargin = searchBarTopExtraPaddingPx; 471 searchBar.setLayoutParams(lp); 472 473 // Layout the app info bar space 474 View appInfoBar = launcher.getAppInfoDropTargetBar(); 475 lp = getDropTargetBarLayoutParams(hasVerticalBarLayout, appInfoBar, Gravity.BOTTOM); 476 lp.bottomMargin = hotseatBarHeightPx; 477 appInfoBar.setLayoutParams(lp); 478 479 // Layout the workspace 480 PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace); 481 lp = (FrameLayout.LayoutParams) workspace.getLayoutParams(); 482 lp.gravity = Gravity.CENTER; 483 Rect padding = getWorkspacePadding(isLayoutRtl); 484 workspace.setLayoutParams(lp); 485 workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom); 486 workspace.setPageSpacing(getWorkspacePageSpacing(isLayoutRtl)); 487 488 // Layout the hotseat 489 View hotseat = launcher.findViewById(R.id.hotseat); 490 lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams(); 491 // We want the edges of the hotseat to line up with the edges of the workspace, but the 492 // icons in the hotseat are a different size, and so don't line up perfectly. To account for 493 // this, we pad the left and right of the hotseat with half of the difference of a workspace 494 // cell vs a hotseat cell. 495 float workspaceCellWidth = (float) getCurrentWidth() / inv.numColumns; 496 float hotseatCellWidth = (float) getCurrentWidth() / inv.numHotseatIcons; 497 int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2); 498 if (hasVerticalBarLayout) { 499 // Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the 500 // screen regardless of RTL 501 lp.gravity = Gravity.RIGHT; 502 lp.width = normalHotseatBarHeightPx; 503 lp.height = LayoutParams.MATCH_PARENT; 504 hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx); 505 } else if (isTablet) { 506 // Pad the hotseat with the workspace padding calculated above 507 lp.gravity = Gravity.BOTTOM; 508 lp.width = LayoutParams.MATCH_PARENT; 509 lp.height = hotseatBarHeightPx; 510 hotseat.findViewById(R.id.layout).setPadding( 511 hotseatAdjustment + padding.left, 0, 512 hotseatAdjustment + padding.right, 2 * edgeMarginPx); 513 } else { 514 // For phones, layout the hotseat without any bottom margin 515 // to ensure that we have space for the folders 516 lp.gravity = Gravity.BOTTOM; 517 lp.width = LayoutParams.MATCH_PARENT; 518 lp.height = hotseatBarHeightPx; 519 hotseat.findViewById(R.id.layout).setPadding( 520 hotseatAdjustment + padding.left, 0, 521 hotseatAdjustment + padding.right, 0); 522 } 523 hotseat.setLayoutParams(lp); 524 525 // Layout the page indicators 526 View pageIndicator = launcher.findViewById(R.id.page_indicator); 527 if (pageIndicator != null) { 528 if (hasVerticalBarLayout) { 529 // Hide the page indicators when we have vertical search/hotseat 530 pageIndicator.setVisibility(View.GONE); 531 } else { 532 // Put the page indicators above the hotseat 533 lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams(); 534 lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 535 lp.width = LayoutParams.WRAP_CONTENT; 536 lp.height = LayoutParams.WRAP_CONTENT; 537 lp.bottomMargin = hotseatBarHeightPx; 538 pageIndicator.setLayoutParams(lp); 539 } 540 } 541 542 // Layout the Overview Mode 543 ViewGroup overviewMode = launcher.getOverviewPanel(); 544 if (overviewMode != null) { 545 lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams(); 546 lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 547 548 int visibleChildCount = getVisibleChildCount(overviewMode); 549 int totalItemWidth = visibleChildCount * overviewModeBarItemWidthPx; 550 int maxWidth = totalItemWidth + (visibleChildCount-1) * overviewModeBarSpacerWidthPx; 551 552 lp.width = Math.min(availableWidthPx, maxWidth); 553 lp.height = getOverviewModeButtonBarHeight(); 554 overviewMode.setLayoutParams(lp); 555 556 if (lp.width > totalItemWidth && visibleChildCount > 1) { 557 // We have enough space. Lets add some margin too. 558 int margin = (lp.width - totalItemWidth) / (visibleChildCount-1); 559 View lastChild = null; 560 561 // Set margin of all visible children except the last visible child 562 for (int i = 0; i < visibleChildCount; i++) { 563 if (lastChild != null) { 564 MarginLayoutParams clp = (MarginLayoutParams) lastChild.getLayoutParams(); 565 if (isLayoutRtl) { 566 clp.leftMargin = margin; 567 } else { 568 clp.rightMargin = margin; 569 } 570 lastChild.setLayoutParams(clp); 571 lastChild = null; 572 } 573 View thisChild = overviewMode.getChildAt(i); 574 if (thisChild.getVisibility() != View.GONE) { 575 lastChild = thisChild; 576 } 577 } 578 } 579 } 580 } 581 582 private FrameLayout.LayoutParams getDropTargetBarLayoutParams(boolean hasVerticalBarLayout, 583 View dropTargetBar, int verticalGravity) { 584 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) dropTargetBar.getLayoutParams(); 585 if (hasVerticalBarLayout) { 586 // Vertical drop target bar space -- The drop target bar is fixed in the layout to be on 587 // the left of the screen regardless of RTL 588 lp.gravity = Gravity.LEFT; 589 lp.width = normalSearchBarSpaceHeightPx; 590 591 LinearLayout targets = (LinearLayout) dropTargetBar.findViewById(R.id.drag_target_bar); 592 targets.setOrientation(LinearLayout.VERTICAL); 593 FrameLayout.LayoutParams targetsLp = (FrameLayout.LayoutParams) targets.getLayoutParams(); 594 targetsLp.gravity = verticalGravity; 595 targetsLp.height = LayoutParams.WRAP_CONTENT; 596 } else { 597 // Horizontal drop target bar space 598 lp.gravity = verticalGravity | Gravity.CENTER_HORIZONTAL; 599 lp.height = searchBarSpaceHeightPx; 600 } 601 return lp; 602 } 603 604 private int getCurrentWidth() { 605 return isLandscape 606 ? Math.max(widthPx, heightPx) 607 : Math.min(widthPx, heightPx); 608 } 609 610 private int getCurrentHeight() { 611 return isLandscape 612 ? Math.min(widthPx, heightPx) 613 : Math.max(widthPx, heightPx); 614 } 615} 616