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 17 package com.android.launcher3; 18 19 import android.appwidget.AppWidgetHostView; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.res.Configuration; 23 import android.content.res.Resources; 24 import android.graphics.Point; 25 import android.graphics.PointF; 26 import android.graphics.Rect; 27 import android.util.DisplayMetrics; 28 import android.view.Surface; 29 import android.view.WindowManager; 30 31 import com.android.launcher3.CellLayout.ContainerType; 32 import com.android.launcher3.badge.BadgeRenderer; 33 import com.android.launcher3.graphics.IconNormalizer; 34 35 public class DeviceProfile { 36 37 public final InvariantDeviceProfile inv; 38 39 // Device properties 40 public final boolean isTablet; 41 public final boolean isLargeTablet; 42 public final boolean isPhone; 43 public final boolean transposeLayoutWithOrientation; 44 45 // Device properties in current orientation 46 public final boolean isLandscape; 47 public final boolean isMultiWindowMode; 48 49 public final int widthPx; 50 public final int heightPx; 51 public final int availableWidthPx; 52 public final int availableHeightPx; 53 /** 54 * The maximum amount of left/right workspace padding as a percentage of the screen width. 55 * To be clear, this means that up to 7% of the screen width can be used as left padding, and 56 * 7% of the screen width can be used as right padding. 57 */ 58 private static final float MAX_HORIZONTAL_PADDING_PERCENT = 0.14f; 59 60 private static final float TALL_DEVICE_ASPECT_RATIO_THRESHOLD = 2.0f; 61 62 // Workspace 63 public final int desiredWorkspaceLeftRightMarginPx; 64 public final int cellLayoutPaddingLeftRightPx; 65 public final int cellLayoutBottomPaddingPx; 66 public final int edgeMarginPx; 67 public final Rect defaultWidgetPadding; 68 public final int defaultPageSpacingPx; 69 private final int topWorkspacePadding; 70 public float workspaceSpringLoadShrinkFactor; 71 public final int workspaceSpringLoadedBottomSpace; 72 73 // Drag handle 74 public final int verticalDragHandleSizePx; 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 public int workspaceCellPaddingXPx; 85 86 // Folder 87 public int folderIconSizePx; 88 public int folderIconOffsetYPx; 89 90 // Folder cell 91 public int folderCellWidthPx; 92 public int folderCellHeightPx; 93 94 // Folder child 95 public int folderChildIconSizePx; 96 public int folderChildTextSizePx; 97 public int folderChildDrawablePaddingPx; 98 99 // Hotseat 100 public int hotseatCellHeightPx; 101 // In portrait: size = height, in landscape: size = width 102 public int hotseatBarSizePx; 103 public final int hotseatBarTopPaddingPx; 104 public final int hotseatBarBottomPaddingPx; 105 public final int hotseatBarSidePaddingPx; 106 107 // All apps 108 public int allAppsCellHeightPx; 109 public int allAppsIconSizePx; 110 public int allAppsIconDrawablePaddingPx; 111 public float allAppsIconTextSizePx; 112 113 // Widgets 114 public final PointF appWidgetScale = new PointF(1.0f, 1.0f); 115 116 // Drop Target 117 public int dropTargetBarSizePx; 118 119 // Insets 120 private final Rect mInsets = new Rect(); 121 public final Rect workspacePadding = new Rect(); 122 private final Rect mHotseatPadding = new Rect(); 123 private boolean mIsSeascape; 124 125 // Icon badges 126 public BadgeRenderer mBadgeRenderer; 127 DeviceProfile(Context context, InvariantDeviceProfile inv, Point minSize, Point maxSize, int width, int height, boolean isLandscape, boolean isMultiWindowMode)128 public DeviceProfile(Context context, InvariantDeviceProfile inv, 129 Point minSize, Point maxSize, 130 int width, int height, boolean isLandscape, boolean isMultiWindowMode) { 131 132 this.inv = inv; 133 this.isLandscape = isLandscape; 134 this.isMultiWindowMode = isMultiWindowMode; 135 136 Resources res = context.getResources(); 137 DisplayMetrics dm = res.getDisplayMetrics(); 138 139 // Constants from resources 140 isTablet = res.getBoolean(R.bool.is_tablet); 141 isLargeTablet = res.getBoolean(R.bool.is_large_tablet); 142 isPhone = !isTablet && !isLargeTablet; 143 144 // Some more constants 145 transposeLayoutWithOrientation = 146 res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation); 147 148 context = getContext(context, isVerticalBarLayout() 149 ? Configuration.ORIENTATION_LANDSCAPE 150 : Configuration.ORIENTATION_PORTRAIT); 151 res = context.getResources(); 152 153 154 ComponentName cn = new ComponentName(context.getPackageName(), 155 this.getClass().getName()); 156 defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null); 157 edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin); 158 desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx; 159 cellLayoutPaddingLeftRightPx = 160 res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding); 161 cellLayoutBottomPaddingPx = 162 res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_bottom_padding); 163 verticalDragHandleSizePx = res.getDimensionPixelSize( 164 R.dimen.vertical_drag_handle_size); 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 iconDrawablePaddingOriginalPx = 170 res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding); 171 dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size); 172 workspaceSpringLoadedBottomSpace = 173 res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space); 174 175 workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x); 176 177 hotseatBarTopPaddingPx = 178 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding); 179 hotseatBarBottomPaddingPx = 180 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding); 181 hotseatBarSidePaddingPx = 182 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding); 183 hotseatBarSizePx = isVerticalBarLayout() 184 ? Utilities.pxFromDp(inv.iconSize, dm) 185 : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_size) 186 + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx; 187 188 // Determine sizes. 189 widthPx = width; 190 heightPx = height; 191 if (isLandscape) { 192 availableWidthPx = maxSize.x; 193 availableHeightPx = minSize.y; 194 } else { 195 availableWidthPx = minSize.x; 196 availableHeightPx = maxSize.y; 197 } 198 199 // Calculate all of the remaining variables. 200 updateAvailableDimensions(dm, res); 201 202 // Now that we have all of the variables calculated, we can tune certain sizes. 203 float aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx); 204 boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0; 205 if (!isVerticalBarLayout() && isPhone && isTallDevice) { 206 // We increase the hotseat size when there is extra space. 207 // ie. For a display with a large aspect ratio, we can keep the icons on the workspace 208 // in portrait mode closer together by adding more height to the hotseat. 209 // Note: This calculation was created after noticing a pattern in the design spec. 210 int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx; 211 hotseatBarSizePx += extraSpace - verticalDragHandleSizePx; 212 213 // Recalculate the available dimensions using the new hotseat size. 214 updateAvailableDimensions(dm, res); 215 } 216 updateWorkspacePadding(); 217 218 // This is done last, after iconSizePx is calculated above. 219 mBadgeRenderer = new BadgeRenderer(iconSizePx); 220 } 221 copy(Context context)222 public DeviceProfile copy(Context context) { 223 Point size = new Point(availableWidthPx, availableHeightPx); 224 return new DeviceProfile(context, inv, size, size, widthPx, heightPx, isLandscape, 225 isMultiWindowMode); 226 } 227 getMultiWindowProfile(Context context, Point mwSize)228 public DeviceProfile getMultiWindowProfile(Context context, Point mwSize) { 229 // We take the minimum sizes of this profile and it's multi-window variant to ensure that 230 // the system decor is always excluded. 231 mwSize.set(Math.min(availableWidthPx, mwSize.x), Math.min(availableHeightPx, mwSize.y)); 232 233 // In multi-window mode, we can have widthPx = availableWidthPx 234 // and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles' 235 // widthPx and heightPx values where it's needed. 236 DeviceProfile profile = new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y, 237 isLandscape, true); 238 239 // If there isn't enough vertical cell padding with the labels displayed, hide the labels. 240 float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx 241 - iconDrawablePaddingPx - profile.iconTextSizePx; 242 if (workspaceCellPaddingY < profile.iconDrawablePaddingPx * 2) { 243 profile.adjustToHideWorkspaceLabels(); 244 } 245 246 // We use these scales to measure and layout the widgets using their full invariant profile 247 // sizes and then draw them scaled and centered to fit in their multi-window mode cellspans. 248 float appWidgetScaleX = (float) profile.getCellSize().x / getCellSize().x; 249 float appWidgetScaleY = (float) profile.getCellSize().y / getCellSize().y; 250 profile.appWidgetScale.set(appWidgetScaleX, appWidgetScaleY); 251 profile.updateWorkspacePadding(); 252 253 return profile; 254 } 255 256 /** 257 * Inverse of {@link #getMultiWindowProfile(Context, Point)} 258 * @return device profile corresponding to the current orientation in non multi-window mode. 259 */ getFullScreenProfile()260 public DeviceProfile getFullScreenProfile() { 261 return isLandscape ? inv.landscapeProfile : inv.portraitProfile; 262 } 263 264 /** 265 * Adjusts the profile so that the labels on the Workspace are hidden. 266 * It is important to call this method after the All Apps variables have been set. 267 */ adjustToHideWorkspaceLabels()268 private void adjustToHideWorkspaceLabels() { 269 iconTextSizePx = 0; 270 iconDrawablePaddingPx = 0; 271 cellHeightPx = iconSizePx; 272 273 // In normal cases, All Apps cell height should equal the Workspace cell height. 274 // Since we are removing labels from the Workspace, we need to manually compute the 275 // All Apps cell height. 276 int topBottomPadding = allAppsIconDrawablePaddingPx * (isVerticalBarLayout() ? 2 : 1); 277 allAppsCellHeightPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx 278 + Utilities.calculateTextHeight(allAppsIconTextSizePx) 279 + topBottomPadding * 2; 280 } 281 updateAvailableDimensions(DisplayMetrics dm, Resources res)282 private void updateAvailableDimensions(DisplayMetrics dm, Resources res) { 283 updateIconSize(1f, res, dm); 284 285 // Check to see if the icons fit within the available height. If not, then scale down. 286 float usedHeight = (cellHeightPx * inv.numRows); 287 int maxHeight = (availableHeightPx - getTotalWorkspacePadding().y); 288 if (usedHeight > maxHeight) { 289 float scale = maxHeight / usedHeight; 290 updateIconSize(scale, res, dm); 291 } 292 updateAvailableFolderCellDimensions(dm, res); 293 } 294 updateIconSize(float scale, Resources res, DisplayMetrics dm)295 private void updateIconSize(float scale, Resources res, DisplayMetrics dm) { 296 // Workspace 297 final boolean isVerticalLayout = isVerticalBarLayout(); 298 float invIconSizePx = isVerticalLayout ? inv.landscapeIconSize : inv.iconSize; 299 iconSizePx = (int) (Utilities.pxFromDp(invIconSizePx, dm) * scale); 300 iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale); 301 iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale); 302 303 cellHeightPx = iconSizePx + iconDrawablePaddingPx 304 + Utilities.calculateTextHeight(iconTextSizePx); 305 int cellYPadding = (getCellSize().y - cellHeightPx) / 2; 306 if (iconDrawablePaddingPx > cellYPadding && !isVerticalLayout 307 && !isMultiWindowMode) { 308 // Ensures that the label is closer to its corresponding icon. This is not an issue 309 // with vertical bar layout or multi-window mode since the issue is handled separately 310 // with their calls to {@link #adjustToHideWorkspaceLabels}. 311 cellHeightPx -= (iconDrawablePaddingPx - cellYPadding); 312 iconDrawablePaddingPx = cellYPadding; 313 } 314 cellWidthPx = iconSizePx + iconDrawablePaddingPx; 315 316 // All apps 317 allAppsIconTextSizePx = iconTextSizePx; 318 allAppsIconSizePx = iconSizePx; 319 allAppsIconDrawablePaddingPx = iconDrawablePaddingPx; 320 allAppsCellHeightPx = getCellSize().y; 321 322 if (isVerticalLayout) { 323 // Always hide the Workspace text with vertical bar layout. 324 adjustToHideWorkspaceLabels(); 325 } 326 327 // Hotseat 328 if (isVerticalLayout) { 329 hotseatBarSizePx = iconSizePx; 330 } 331 hotseatCellHeightPx = iconSizePx; 332 333 if (!isVerticalLayout) { 334 int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx 335 - verticalDragHandleSizePx - topWorkspacePadding; 336 float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace; 337 workspaceSpringLoadShrinkFactor = Math.min( 338 res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f, 339 1 - (minRequiredHeight / expectedWorkspaceHeight)); 340 } else { 341 workspaceSpringLoadShrinkFactor = 342 res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f; 343 } 344 345 // Folder icon 346 folderIconSizePx = IconNormalizer.getNormalizedCircleSize(iconSizePx); 347 folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2; 348 } 349 updateAvailableFolderCellDimensions(DisplayMetrics dm, Resources res)350 private void updateAvailableFolderCellDimensions(DisplayMetrics dm, Resources res) { 351 int folderBottomPanelSize = res.getDimensionPixelSize(R.dimen.folder_label_padding_top) 352 + res.getDimensionPixelSize(R.dimen.folder_label_padding_bottom) 353 + Utilities.calculateTextHeight(res.getDimension(R.dimen.folder_label_text_size)); 354 355 updateFolderCellSize(1f, dm, res); 356 357 // Don't let the folder get too close to the edges of the screen. 358 int folderMargin = edgeMarginPx; 359 Point totalWorkspacePadding = getTotalWorkspacePadding(); 360 361 // Check if the icons fit within the available height. 362 float usedHeight = folderCellHeightPx * inv.numFolderRows + folderBottomPanelSize; 363 int maxHeight = availableHeightPx - totalWorkspacePadding.y - folderMargin; 364 float scaleY = maxHeight / usedHeight; 365 366 // Check if the icons fit within the available width. 367 float usedWidth = folderCellWidthPx * inv.numFolderColumns; 368 int maxWidth = availableWidthPx - totalWorkspacePadding.x - folderMargin; 369 float scaleX = maxWidth / usedWidth; 370 371 float scale = Math.min(scaleX, scaleY); 372 if (scale < 1f) { 373 updateFolderCellSize(scale, dm, res); 374 } 375 } 376 updateFolderCellSize(float scale, DisplayMetrics dm, Resources res)377 private void updateFolderCellSize(float scale, DisplayMetrics dm, Resources res) { 378 folderChildIconSizePx = (int) (Utilities.pxFromDp(inv.iconSize, dm) * scale); 379 folderChildTextSizePx = 380 (int) (res.getDimensionPixelSize(R.dimen.folder_child_text_size) * scale); 381 382 int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx); 383 int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding) * scale); 384 int cellPaddingY = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_y_padding) * scale); 385 386 folderCellWidthPx = folderChildIconSizePx + 2 * cellPaddingX; 387 folderCellHeightPx = folderChildIconSizePx + 2 * cellPaddingY + textHeight; 388 folderChildDrawablePaddingPx = Math.max(0, 389 (folderCellHeightPx - folderChildIconSizePx - textHeight) / 3); 390 } 391 updateInsets(Rect insets)392 public void updateInsets(Rect insets) { 393 mInsets.set(insets); 394 updateWorkspacePadding(); 395 } 396 getInsets()397 public Rect getInsets() { 398 return mInsets; 399 } 400 getCellSize()401 public Point getCellSize() { 402 Point result = new Point(); 403 // Since we are only concerned with the overall padding, layout direction does 404 // not matter. 405 Point padding = getTotalWorkspacePadding(); 406 result.x = calculateCellWidth(availableWidthPx - padding.x 407 - cellLayoutPaddingLeftRightPx * 2, inv.numColumns); 408 result.y = calculateCellHeight(availableHeightPx - padding.y 409 - cellLayoutBottomPaddingPx, inv.numRows); 410 return result; 411 } 412 getTotalWorkspacePadding()413 public Point getTotalWorkspacePadding() { 414 updateWorkspacePadding(); 415 return new Point(workspacePadding.left + workspacePadding.right, 416 workspacePadding.top + workspacePadding.bottom); 417 } 418 419 /** 420 * Updates {@link #workspacePadding} as a result of any internal value change to reflect the 421 * new workspace padding 422 */ updateWorkspacePadding()423 private void updateWorkspacePadding() { 424 Rect padding = workspacePadding; 425 if (isVerticalBarLayout()) { 426 padding.top = 0; 427 padding.bottom = edgeMarginPx; 428 padding.left = hotseatBarSidePaddingPx; 429 padding.right = hotseatBarSidePaddingPx; 430 if (isSeascape()) { 431 padding.left += hotseatBarSizePx; 432 padding.right += verticalDragHandleSizePx; 433 } else { 434 padding.left += verticalDragHandleSizePx; 435 padding.right += hotseatBarSizePx; 436 } 437 } else { 438 int paddingBottom = hotseatBarSizePx + verticalDragHandleSizePx; 439 if (isTablet) { 440 // Pad the left and right of the workspace to ensure consistent spacing 441 // between all icons 442 // The amount of screen space available for left/right padding. 443 int availablePaddingX = Math.max(0, widthPx - ((inv.numColumns * cellWidthPx) + 444 ((inv.numColumns - 1) * cellWidthPx))); 445 availablePaddingX = (int) Math.min(availablePaddingX, 446 widthPx * MAX_HORIZONTAL_PADDING_PERCENT); 447 int availablePaddingY = Math.max(0, heightPx - topWorkspacePadding - paddingBottom 448 - (2 * inv.numRows * cellHeightPx) - hotseatBarTopPaddingPx 449 - hotseatBarBottomPaddingPx); 450 padding.set(availablePaddingX / 2, topWorkspacePadding + availablePaddingY / 2, 451 availablePaddingX / 2, paddingBottom + availablePaddingY / 2); 452 } else { 453 // Pad the top and bottom of the workspace with search/hotseat bar sizes 454 padding.set(desiredWorkspaceLeftRightMarginPx, 455 topWorkspacePadding, 456 desiredWorkspaceLeftRightMarginPx, 457 paddingBottom); 458 } 459 } 460 } 461 getHotseatLayoutPadding()462 public Rect getHotseatLayoutPadding() { 463 if (isVerticalBarLayout()) { 464 if (isSeascape()) { 465 mHotseatPadding.set( 466 mInsets.left, mInsets.top, hotseatBarSidePaddingPx, mInsets.bottom); 467 } else { 468 mHotseatPadding.set( 469 hotseatBarSidePaddingPx, mInsets.top, mInsets.right, mInsets.bottom); 470 } 471 } else { 472 473 // We want the edges of the hotseat to line up with the edges of the workspace, but the 474 // icons in the hotseat are a different size, and so don't line up perfectly. To account 475 // for this, we pad the left and right of the hotseat with half of the difference of a 476 // workspace cell vs a hotseat cell. 477 float workspaceCellWidth = (float) widthPx / inv.numColumns; 478 float hotseatCellWidth = (float) widthPx / inv.numHotseatIcons; 479 int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2); 480 mHotseatPadding.set( 481 hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx, 482 hotseatBarTopPaddingPx, 483 hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx, 484 hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx); 485 } 486 return mHotseatPadding; 487 } 488 489 /** 490 * @return the bounds for which the open folders should be contained within 491 */ getAbsoluteOpenFolderBounds()492 public Rect getAbsoluteOpenFolderBounds() { 493 if (isVerticalBarLayout()) { 494 // Folders should only appear right of the drop target bar and left of the hotseat 495 return new Rect(mInsets.left + dropTargetBarSizePx + edgeMarginPx, 496 mInsets.top, 497 mInsets.left + availableWidthPx - hotseatBarSizePx - edgeMarginPx, 498 mInsets.top + availableHeightPx); 499 } else { 500 // Folders should only appear below the drop target bar and above the hotseat 501 return new Rect(mInsets.left + edgeMarginPx, 502 mInsets.top + dropTargetBarSizePx + edgeMarginPx, 503 mInsets.left + availableWidthPx - edgeMarginPx, 504 mInsets.top + availableHeightPx - hotseatBarSizePx 505 - verticalDragHandleSizePx - edgeMarginPx); 506 } 507 } 508 calculateCellWidth(int width, int countX)509 public static int calculateCellWidth(int width, int countX) { 510 return width / countX; 511 } calculateCellHeight(int height, int countY)512 public static int calculateCellHeight(int height, int countY) { 513 return height / countY; 514 } 515 516 /** 517 * When {@code true}, the device is in landscape mode and the hotseat is on the right column. 518 * When {@code false}, either device is in portrait mode or the device is in landscape mode and 519 * the hotseat is on the bottom row. 520 */ isVerticalBarLayout()521 public boolean isVerticalBarLayout() { 522 return isLandscape && transposeLayoutWithOrientation; 523 } 524 525 /** 526 * Updates orientation information and returns true if it has changed from the previous value. 527 */ updateIsSeascape(WindowManager wm)528 public boolean updateIsSeascape(WindowManager wm) { 529 if (isVerticalBarLayout()) { 530 boolean isSeascape = wm.getDefaultDisplay().getRotation() == Surface.ROTATION_270; 531 if (mIsSeascape != isSeascape) { 532 mIsSeascape = isSeascape; 533 return true; 534 } 535 } 536 return false; 537 } 538 isSeascape()539 public boolean isSeascape() { 540 return isVerticalBarLayout() && mIsSeascape; 541 } 542 shouldFadeAdjacentWorkspaceScreens()543 public boolean shouldFadeAdjacentWorkspaceScreens() { 544 return isVerticalBarLayout() || isLargeTablet; 545 } 546 getCellHeight(@ontainerType int containerType)547 public int getCellHeight(@ContainerType int containerType) { 548 switch (containerType) { 549 case CellLayout.WORKSPACE: 550 return cellHeightPx; 551 case CellLayout.FOLDER: 552 return folderCellHeightPx; 553 case CellLayout.HOTSEAT: 554 return hotseatCellHeightPx; 555 default: 556 // ?? 557 return 0; 558 } 559 } 560 getContext(Context c, int orientation)561 private static Context getContext(Context c, int orientation) { 562 Configuration context = new Configuration(c.getResources().getConfiguration()); 563 context.orientation = orientation; 564 return c.createConfigurationContext(context); 565 } 566 567 /** 568 * Callback when a component changes the DeviceProfile associated with it, as a result of 569 * configuration change 570 */ 571 public interface OnDeviceProfileChangeListener { 572 573 /** 574 * Called when the device profile is reassigned. Note that for layout and measurements, it 575 * is sufficient to listen for inset changes. Use this callback when you need to perform 576 * a one time operation. 577 */ onDeviceProfileChanged(DeviceProfile dp)578 void onDeviceProfileChanged(DeviceProfile dp); 579 } 580 } 581