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