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