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