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