• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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