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