Merge "Adding logs to track down missing workspace screen. (Bug 11683562)" into jb-ub-now-jolly-elf
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index d9ca157..688ff82 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -916,6 +916,13 @@
}
@Override
+ public float getIntrinsicIconScaleFactor() {
+ LauncherAppState app = LauncherAppState.getInstance();
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+ return (float) grid.allAppsIconSizePx / grid.iconSizePx;
+ }
+
+ @Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
cancelAllTasks();
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
new file mode 100644
index 0000000..626ec42
--- /dev/null
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -0,0 +1,717 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.appwidget.AppWidgetHostView;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetrics;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+
+class DeviceProfileQuery {
+ float widthDps;
+ float heightDps;
+ float value;
+ PointF dimens;
+
+ DeviceProfileQuery(float w, float h, float v) {
+ widthDps = w;
+ heightDps = h;
+ value = v;
+ dimens = new PointF(w, h);
+ }
+}
+
+public class DeviceProfile {
+ public static interface DeviceProfileCallbacks {
+ public void onAvailableSizeChanged(DeviceProfile grid);
+ }
+
+ String name;
+ float minWidthDps;
+ float minHeightDps;
+ float numRows;
+ float numColumns;
+ float numHotseatIcons;
+ private float iconSize;
+ private float iconTextSize;
+ private int iconDrawablePaddingOriginalPx;
+ private float hotseatIconSize;
+
+ boolean isLandscape;
+ boolean isTablet;
+ boolean isLargeTablet;
+ boolean transposeLayoutWithOrientation;
+
+ int desiredWorkspaceLeftRightMarginPx;
+ int edgeMarginPx;
+ Rect defaultWidgetPadding;
+
+ int widthPx;
+ int heightPx;
+ int availableWidthPx;
+ int availableHeightPx;
+ int defaultPageSpacingPx;
+
+ int overviewModeMinIconZoneHeightPx;
+ int overviewModeMaxIconZoneHeightPx;
+ int overviewModeMaxBarWidthPx;
+ float overviewModeIconZoneRatio;
+ float overviewModeScaleFactor;
+
+ int iconSizePx;
+ int iconTextSizePx;
+ int iconDrawablePaddingPx;
+ int cellWidthPx;
+ int cellHeightPx;
+ int allAppsIconSizePx;
+ int allAppsIconTextSizePx;
+ int allAppsCellWidthPx;
+ int allAppsCellHeightPx;
+ int allAppsCellPaddingPx;
+ int folderBackgroundOffset;
+ int folderIconSizePx;
+ int folderCellWidthPx;
+ int folderCellHeightPx;
+ int hotseatCellWidthPx;
+ int hotseatCellHeightPx;
+ int hotseatIconSizePx;
+ int hotseatBarHeightPx;
+ int hotseatAllAppsRank;
+ int allAppsNumRows;
+ int allAppsNumCols;
+ int searchBarSpaceWidthPx;
+ int searchBarSpaceMaxWidthPx;
+ int searchBarSpaceHeightPx;
+ int searchBarHeightPx;
+ int pageIndicatorHeightPx;
+
+ private ArrayList<DeviceProfileCallbacks> mCallbacks = new ArrayList<DeviceProfileCallbacks>();
+
+ DeviceProfile(String n, float w, float h, float r, float c,
+ float is, float its, float hs, float his) {
+ // Ensure that we have an odd number of hotseat items (since we need to place all apps)
+ if (!AppsCustomizePagedView.DISABLE_ALL_APPS && hs % 2 == 0) {
+ throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
+ }
+
+ name = n;
+ minWidthDps = w;
+ minHeightDps = h;
+ numRows = r;
+ numColumns = c;
+ iconSize = is;
+ iconTextSize = its;
+ numHotseatIcons = hs;
+ hotseatIconSize = his;
+ }
+
+ DeviceProfile(Context context,
+ ArrayList<DeviceProfile> profiles,
+ float minWidth, float minHeight,
+ int wPx, int hPx,
+ int awPx, int ahPx,
+ Resources res) {
+ DisplayMetrics dm = res.getDisplayMetrics();
+ ArrayList<DeviceProfileQuery> points =
+ new ArrayList<DeviceProfileQuery>();
+ transposeLayoutWithOrientation =
+ res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
+ minWidthDps = minWidth;
+ minHeightDps = minHeight;
+
+ ComponentName cn = new ComponentName(context.getPackageName(),
+ this.getClass().getName());
+ defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
+ edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
+ desiredWorkspaceLeftRightMarginPx = 2 * edgeMarginPx;
+ pageIndicatorHeightPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_height);
+ defaultPageSpacingPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
+ allAppsCellPaddingPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_all_apps_cell_padding);
+ overviewModeMinIconZoneHeightPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_min_icon_zone_height);
+ overviewModeMaxIconZoneHeightPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_max_icon_zone_height);
+ overviewModeMaxBarWidthPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_max_width);
+ overviewModeIconZoneRatio =
+ res.getInteger(R.integer.config_dynamic_grid_overview_icon_zone_percentage) / 100f;
+ overviewModeScaleFactor =
+ res.getInteger(R.integer.config_dynamic_grid_overview_scale_percentage) / 100f;
+
+ // Interpolate the rows
+ for (DeviceProfile p : profiles) {
+ points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numRows));
+ }
+ numRows = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points));
+ // Interpolate the columns
+ points.clear();
+ for (DeviceProfile p : profiles) {
+ points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numColumns));
+ }
+ numColumns = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points));
+ // Interpolate the hotseat length
+ points.clear();
+ for (DeviceProfile p : profiles) {
+ points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numHotseatIcons));
+ }
+ numHotseatIcons = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points));
+ hotseatAllAppsRank = (int) (numHotseatIcons / 2);
+
+ // Interpolate the icon size
+ points.clear();
+ for (DeviceProfile p : profiles) {
+ points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconSize));
+ }
+ iconSize = invDistWeightedInterpolate(minWidth, minHeight, points);
+ // AllApps uses the original non-scaled icon size
+ allAppsIconSizePx = DynamicGrid.pxFromDp(iconSize, dm);
+
+ // Interpolate the icon text size
+ points.clear();
+ for (DeviceProfile p : profiles) {
+ points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconTextSize));
+ }
+ iconTextSize = invDistWeightedInterpolate(minWidth, minHeight, points);
+ iconDrawablePaddingOriginalPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding);
+ // AllApps uses the original non-scaled icon text size
+ allAppsIconTextSizePx = DynamicGrid.pxFromDp(iconTextSize, dm);
+
+ // Interpolate the hotseat icon size
+ points.clear();
+ for (DeviceProfile p : profiles) {
+ points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.hotseatIconSize));
+ }
+ // Hotseat
+ hotseatIconSize = invDistWeightedInterpolate(minWidth, minHeight, points);
+
+ // Calculate the remaining vars
+ updateFromConfiguration(context, res, wPx, hPx, awPx, ahPx);
+ updateAvailableDimensions(context);
+ }
+
+ void addCallback(DeviceProfileCallbacks cb) {
+ mCallbacks.add(cb);
+ cb.onAvailableSizeChanged(this);
+ }
+ void removeCallback(DeviceProfileCallbacks cb) {
+ mCallbacks.remove(cb);
+ }
+
+ private int getDeviceOrientation(Context context) {
+ WindowManager windowManager = (WindowManager)
+ context.getSystemService(Context.WINDOW_SERVICE);
+ Resources resources = context.getResources();
+ DisplayMetrics dm = resources.getDisplayMetrics();
+ Configuration config = resources.getConfiguration();
+ int rotation = windowManager.getDefaultDisplay().getRotation();
+
+ boolean isLandscape = (config.orientation == Configuration.ORIENTATION_LANDSCAPE) &&
+ (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180);
+ boolean isRotatedPortrait = (config.orientation == Configuration.ORIENTATION_PORTRAIT) &&
+ (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
+ if (isLandscape || isRotatedPortrait) {
+ return CellLayout.LANDSCAPE;
+ } else {
+ return CellLayout.PORTRAIT;
+ }
+ }
+
+ private void updateAvailableDimensions(Context context) {
+ WindowManager windowManager = (WindowManager)
+ context.getSystemService(Context.WINDOW_SERVICE);
+ Display display = windowManager.getDefaultDisplay();
+ Resources resources = context.getResources();
+ DisplayMetrics dm = resources.getDisplayMetrics();
+ Configuration config = resources.getConfiguration();
+
+ // There are three possible configurations that the dynamic grid accounts for, portrait,
+ // landscape with the nav bar at the bottom, and landscape with the nav bar at the side.
+ // To prevent waiting for fitSystemWindows(), we make the observation that in landscape,
+ // the height is the smallest height (either with the nav bar at the bottom or to the
+ // side) and otherwise, the height is simply the largest possible height for a portrait
+ // device.
+ Point size = new Point();
+ Point smallestSize = new Point();
+ Point largestSize = new Point();
+ display.getSize(size);
+ display.getCurrentSizeRange(smallestSize, largestSize);
+ availableWidthPx = size.x;
+ if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ availableHeightPx = smallestSize.y;
+ } else {
+ availableHeightPx = largestSize.y;
+ }
+
+ // Check to see if the icons fit in the new available height. If not, then we need to
+ // shrink the icon size.
+ Rect workspacePadding = getWorkspacePadding();
+ float scale = 1f;
+ int drawablePadding = iconDrawablePaddingOriginalPx;
+ updateIconSize(1f, drawablePadding, resources, dm);
+ float usedHeight = (cellHeightPx * numRows);
+ int maxHeight = (availableHeightPx - workspacePadding.top - workspacePadding.bottom);
+ if (usedHeight > maxHeight) {
+ scale = maxHeight / usedHeight;
+ drawablePadding = 0;
+ }
+ updateIconSize(scale, drawablePadding, resources, dm);
+
+ // Make the callbacks
+ for (DeviceProfileCallbacks cb : mCallbacks) {
+ cb.onAvailableSizeChanged(this);
+ }
+ }
+
+ private void updateIconSize(float scale, int drawablePadding, Resources resources,
+ DisplayMetrics dm) {
+ iconSizePx = (int) (DynamicGrid.pxFromDp(iconSize, dm) * scale);
+ iconTextSizePx = (int) (DynamicGrid.pxFromSp(iconTextSize, dm) * scale);
+ iconDrawablePaddingPx = drawablePadding;
+ hotseatIconSizePx = (int) (DynamicGrid.pxFromDp(hotseatIconSize, dm) * scale);
+
+ // Search Bar
+ searchBarSpaceMaxWidthPx = resources.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_max_width);
+ searchBarHeightPx = resources.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_height);
+ searchBarSpaceWidthPx = Math.min(searchBarSpaceMaxWidthPx, widthPx);
+ searchBarSpaceHeightPx = searchBarHeightPx + 2 * edgeMarginPx;
+
+ // Calculate the actual text height
+ Paint textPaint = new Paint();
+ textPaint.setTextSize(iconTextSizePx);
+ FontMetrics fm = textPaint.getFontMetrics();
+ cellWidthPx = iconSizePx;
+ cellHeightPx = iconSizePx + iconDrawablePaddingPx + (int) Math.ceil(fm.bottom - fm.top);
+
+ // Hotseat
+ hotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx;
+ hotseatCellWidthPx = iconSizePx;
+ hotseatCellHeightPx = iconSizePx;
+
+ // Folder
+ folderCellWidthPx = cellWidthPx + 3 * edgeMarginPx;
+ folderCellHeightPx = cellHeightPx + edgeMarginPx;
+ folderBackgroundOffset = -edgeMarginPx;
+ folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset;
+
+ // All Apps
+ Rect padding = getWorkspacePadding(isLandscape ?
+ CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
+ int pageIndicatorOffset =
+ resources.getDimensionPixelSize(R.dimen.apps_customize_page_indicator_offset);
+ allAppsCellWidthPx = allAppsIconSizePx;
+ allAppsCellHeightPx = allAppsIconSizePx + drawablePadding + iconTextSizePx;
+ int maxLongEdgeCellCount =
+ resources.getInteger(R.integer.config_dynamic_grid_max_long_edge_cell_count);
+ int maxShortEdgeCellCount =
+ resources.getInteger(R.integer.config_dynamic_grid_max_short_edge_cell_count);
+ int minEdgeCellCount =
+ resources.getInteger(R.integer.config_dynamic_grid_min_edge_cell_count);
+ int maxRows = (isLandscape ? maxShortEdgeCellCount : maxLongEdgeCellCount);
+ int maxCols = (isLandscape ? maxLongEdgeCellCount : maxShortEdgeCellCount);
+
+ allAppsNumRows = (availableHeightPx - pageIndicatorHeightPx) /
+ (allAppsCellHeightPx + allAppsCellPaddingPx);
+ allAppsNumRows = Math.max(minEdgeCellCount, Math.min(maxRows, allAppsNumRows));
+ allAppsNumCols = (availableWidthPx) /
+ (allAppsCellWidthPx + allAppsCellPaddingPx);
+ allAppsNumCols = Math.max(minEdgeCellCount, Math.min(maxCols, allAppsNumCols));
+ }
+
+ void updateFromConfiguration(Context context, Resources resources, int wPx, int hPx,
+ int awPx, int ahPx) {
+ isLandscape = (resources.getConfiguration().orientation ==
+ Configuration.ORIENTATION_LANDSCAPE);
+ isTablet = resources.getBoolean(R.bool.is_tablet);
+ isLargeTablet = resources.getBoolean(R.bool.is_large_tablet);
+ widthPx = wPx;
+ heightPx = hPx;
+ availableWidthPx = awPx;
+ availableHeightPx = ahPx;
+
+ updateAvailableDimensions(context);
+ }
+
+ private float dist(PointF p0, PointF p1) {
+ return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) +
+ (p1.y-p0.y)*(p1.y-p0.y));
+ }
+
+ private float weight(PointF a, PointF b,
+ float pow) {
+ float d = dist(a, b);
+ if (d == 0f) {
+ return Float.POSITIVE_INFINITY;
+ }
+ return (float) (1f / Math.pow(d, pow));
+ }
+
+ private float invDistWeightedInterpolate(float width, float height,
+ ArrayList<DeviceProfileQuery> points) {
+ float sum = 0;
+ float weights = 0;
+ float pow = 5;
+ float kNearestNeighbors = 3;
+ final PointF xy = new PointF(width, height);
+
+ ArrayList<DeviceProfileQuery> pointsByNearness = points;
+ Collections.sort(pointsByNearness, new Comparator<DeviceProfileQuery>() {
+ public int compare(DeviceProfileQuery a, DeviceProfileQuery b) {
+ return (int) (dist(xy, a.dimens) - dist(xy, b.dimens));
+ }
+ });
+
+ for (int i = 0; i < pointsByNearness.size(); ++i) {
+ DeviceProfileQuery p = pointsByNearness.get(i);
+ if (i < kNearestNeighbors) {
+ float w = weight(xy, p.dimens, pow);
+ if (w == Float.POSITIVE_INFINITY) {
+ return p.value;
+ }
+ weights += w;
+ }
+ }
+
+ for (int i = 0; i < pointsByNearness.size(); ++i) {
+ DeviceProfileQuery p = pointsByNearness.get(i);
+ if (i < kNearestNeighbors) {
+ float w = weight(xy, p.dimens, pow);
+ sum += w * p.value / weights;
+ }
+ }
+
+ return sum;
+ }
+
+ /** Returns the search bar bounds in the current orientation */
+ Rect getSearchBarBounds() {
+ return getSearchBarBounds(isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
+ }
+ /** Returns the search bar bounds in the specified orientation */
+ Rect getSearchBarBounds(int orientation) {
+ Rect bounds = new Rect();
+ if (orientation == CellLayout.LANDSCAPE &&
+ transposeLayoutWithOrientation) {
+ bounds.set(0, edgeMarginPx, searchBarSpaceHeightPx, availableHeightPx - edgeMarginPx);
+ } else {
+ if (isTablet()) {
+ // Pad the left and right of the workspace to ensure consistent spacing
+ // between all icons
+ int width = (orientation == CellLayout.LANDSCAPE)
+ ? Math.max(widthPx, heightPx)
+ : Math.min(widthPx, heightPx);
+ // XXX: If the icon size changes across orientations, we will have to take
+ // that into account here too.
+ int gap = (int) ((width - 2 * edgeMarginPx -
+ (numColumns * cellWidthPx)) / (2 * (numColumns + 1)));
+ bounds.set(edgeMarginPx + gap, 0, availableWidthPx - (edgeMarginPx + gap),
+ searchBarSpaceHeightPx);
+ } else {
+ bounds.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left, 0,
+ availableWidthPx - (desiredWorkspaceLeftRightMarginPx -
+ defaultWidgetPadding.right), searchBarSpaceHeightPx);
+ }
+ }
+ return bounds;
+ }
+
+ /** Returns the workspace padding in the specified orientation */
+ Rect getWorkspacePadding() {
+ return getWorkspacePadding(isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
+ }
+ Rect getWorkspacePadding(int orientation) {
+ Rect searchBarBounds = getSearchBarBounds(orientation);
+ Rect padding = new Rect();
+ if (orientation == CellLayout.LANDSCAPE &&
+ transposeLayoutWithOrientation) {
+ // Pad the left and right of the workspace with search/hotseat bar sizes
+ padding.set(searchBarBounds.right, edgeMarginPx,
+ hotseatBarHeightPx, edgeMarginPx);
+ } else {
+ if (isTablet()) {
+ // Pad the left and right of the workspace to ensure consistent spacing
+ // between all icons
+ int width = (orientation == CellLayout.LANDSCAPE)
+ ? Math.max(widthPx, heightPx)
+ : Math.min(widthPx, heightPx);
+ // XXX: If the icon size changes across orientations, we will have to take
+ // that into account here too.
+ int gap = (int) ((width - 2 * edgeMarginPx -
+ (numColumns * cellWidthPx)) / (2 * (numColumns + 1)));
+ padding.set(edgeMarginPx + gap,
+ searchBarBounds.bottom,
+ edgeMarginPx + gap,
+ hotseatBarHeightPx + pageIndicatorHeightPx);
+ } else {
+ // Pad the top and bottom of the workspace with search/hotseat bar sizes
+ padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
+ searchBarBounds.bottom,
+ desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
+ hotseatBarHeightPx + pageIndicatorHeightPx);
+ }
+ }
+ return padding;
+ }
+
+ int getWorkspacePageSpacing(int orientation) {
+ if (orientation == CellLayout.LANDSCAPE &&
+ transposeLayoutWithOrientation) {
+ // In landscape mode the page spacing is set to the default.
+ return defaultPageSpacingPx;
+ } else {
+ // In portrait, we want the pages spaced such that there is no
+ // overhang of the previous / next page into the current page viewport.
+ // We assume symmetrical padding in portrait mode.
+ return 2 * getWorkspacePadding().left;
+ }
+ }
+
+ Rect getOverviewModeButtonBarRect() {
+ int zoneHeight = (int) (overviewModeIconZoneRatio * availableHeightPx);
+ zoneHeight = Math.min(overviewModeMaxIconZoneHeightPx,
+ Math.max(overviewModeMinIconZoneHeightPx, zoneHeight));
+ return new Rect(0, availableHeightPx - zoneHeight, 0, availableHeightPx);
+ }
+
+ float getOverviewModeScale() {
+ Rect workspacePadding = getWorkspacePadding();
+ Rect overviewBar = getOverviewModeButtonBarRect();
+ int pageSpace = availableHeightPx - workspacePadding.top - workspacePadding.bottom;
+ return (overviewModeScaleFactor * (pageSpace - overviewBar.height())) / pageSpace;
+ }
+
+ // The rect returned will be extended to below the system ui that covers the workspace
+ Rect getHotseatRect() {
+ if (isVerticalBarLayout()) {
+ return new Rect(availableWidthPx - hotseatBarHeightPx, 0,
+ Integer.MAX_VALUE, availableHeightPx);
+ } else {
+ return new Rect(0, availableHeightPx - hotseatBarHeightPx,
+ availableWidthPx, Integer.MAX_VALUE);
+ }
+ }
+
+ int calculateCellWidth(int width, int countX) {
+ return width / countX;
+ }
+ int calculateCellHeight(int height, int countY) {
+ return height / countY;
+ }
+
+ boolean isPhone() {
+ return !isTablet && !isLargeTablet;
+ }
+ boolean isTablet() {
+ return isTablet;
+ }
+ boolean isLargeTablet() {
+ return isLargeTablet;
+ }
+
+ boolean isVerticalBarLayout() {
+ return isLandscape && transposeLayoutWithOrientation;
+ }
+
+ boolean shouldFadeAdjacentWorkspaceScreens() {
+ return isVerticalBarLayout() || isLargeTablet();
+ }
+
+ public void layout(Launcher launcher) {
+ FrameLayout.LayoutParams lp;
+ Resources res = launcher.getResources();
+ boolean hasVerticalBarLayout = isVerticalBarLayout();
+
+ // Layout the search bar space
+ View searchBar = launcher.getSearchBar();
+ lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
+ if (hasVerticalBarLayout) {
+ // Vertical search bar
+ lp.gravity = Gravity.TOP | Gravity.LEFT;
+ lp.width = searchBarSpaceHeightPx;
+ lp.height = LayoutParams.MATCH_PARENT;
+ searchBar.setPadding(
+ 0, 2 * edgeMarginPx, 0,
+ 2 * edgeMarginPx);
+ } else {
+ // Horizontal search bar
+ lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
+ lp.width = searchBarSpaceWidthPx;
+ lp.height = searchBarSpaceHeightPx;
+ searchBar.setPadding(
+ 2 * edgeMarginPx,
+ 2 * edgeMarginPx,
+ 2 * edgeMarginPx, 0);
+ }
+ searchBar.setLayoutParams(lp);
+
+ // Layout the search bar
+ View qsbBar = launcher.getQsbBar();
+ LayoutParams vglp = qsbBar.getLayoutParams();
+ vglp.width = LayoutParams.MATCH_PARENT;
+ vglp.height = LayoutParams.MATCH_PARENT;
+ qsbBar.setLayoutParams(vglp);
+
+ // Layout the voice proxy
+ View voiceButtonProxy = launcher.findViewById(R.id.voice_button_proxy);
+ if (voiceButtonProxy != null) {
+ if (hasVerticalBarLayout) {
+ // TODO: MOVE THIS INTO SEARCH BAR MEASURE
+ } else {
+ lp = (FrameLayout.LayoutParams) voiceButtonProxy.getLayoutParams();
+ lp.gravity = Gravity.TOP | Gravity.END;
+ lp.width = (widthPx - searchBarSpaceWidthPx) / 2 +
+ 2 * iconSizePx;
+ lp.height = searchBarSpaceHeightPx;
+ }
+ }
+
+ // Layout the workspace
+ PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
+ lp = (FrameLayout.LayoutParams) workspace.getLayoutParams();
+ lp.gravity = Gravity.CENTER;
+ int orientation = isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT;
+ Rect padding = getWorkspacePadding(orientation);
+ workspace.setLayoutParams(lp);
+ workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
+ workspace.setPageSpacing(getWorkspacePageSpacing(orientation));
+
+ // Layout the hotseat
+ View hotseat = launcher.findViewById(R.id.hotseat);
+ lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
+ if (hasVerticalBarLayout) {
+ // Vertical hotseat
+ lp.gravity = Gravity.RIGHT;
+ lp.width = hotseatBarHeightPx;
+ lp.height = LayoutParams.MATCH_PARENT;
+ hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
+ } else if (isTablet()) {
+ // Pad the hotseat with the grid gap calculated above
+ int gridGap = (int) ((widthPx - 2 * edgeMarginPx -
+ (numColumns * cellWidthPx)) / (2 * (numColumns + 1)));
+ int gridWidth = (int) ((numColumns * cellWidthPx) +
+ ((numColumns - 1) * gridGap));
+ int hotseatGap = (int) Math.max(0,
+ (gridWidth - (numHotseatIcons * hotseatCellWidthPx))
+ / (numHotseatIcons - 1));
+ lp.gravity = Gravity.BOTTOM;
+ lp.width = LayoutParams.MATCH_PARENT;
+ lp.height = hotseatBarHeightPx;
+ hotseat.setPadding(2 * edgeMarginPx + gridGap + hotseatGap, 0,
+ 2 * edgeMarginPx + gridGap + hotseatGap,
+ 2 * edgeMarginPx);
+ } else {
+ // For phones, layout the hotseat without any bottom margin
+ // to ensure that we have space for the folders
+ lp.gravity = Gravity.BOTTOM;
+ lp.width = LayoutParams.MATCH_PARENT;
+ lp.height = hotseatBarHeightPx;
+ hotseat.findViewById(R.id.layout).setPadding(2 * edgeMarginPx, 0,
+ 2 * edgeMarginPx, 0);
+ }
+ hotseat.setLayoutParams(lp);
+
+ // Layout the page indicators
+ View pageIndicator = launcher.findViewById(R.id.page_indicator);
+ if (pageIndicator != null) {
+ if (hasVerticalBarLayout) {
+ // Hide the page indicators when we have vertical search/hotseat
+ pageIndicator.setVisibility(View.GONE);
+ } else {
+ // Put the page indicators above the hotseat
+ lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams();
+ lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ lp.width = LayoutParams.WRAP_CONTENT;
+ lp.height = LayoutParams.WRAP_CONTENT;
+ lp.bottomMargin = hotseatBarHeightPx;
+ pageIndicator.setLayoutParams(lp);
+ }
+ }
+
+ // Layout AllApps
+ AppsCustomizeTabHost host = (AppsCustomizeTabHost)
+ launcher.findViewById(R.id.apps_customize_pane);
+ if (host != null) {
+ // Center the all apps page indicator
+ int pageIndicatorHeight = (int) (pageIndicatorHeightPx * Math.min(1f,
+ (allAppsIconSizePx / DynamicGrid.DEFAULT_ICON_SIZE_PX)));
+ pageIndicator = host.findViewById(R.id.apps_customize_page_indicator);
+ if (pageIndicator != null) {
+ lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams();
+ lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ lp.width = LayoutParams.WRAP_CONTENT;
+ lp.height = pageIndicatorHeight;
+ pageIndicator.setLayoutParams(lp);
+ }
+
+ AppsCustomizePagedView pagedView = (AppsCustomizePagedView)
+ host.findViewById(R.id.apps_customize_pane_content);
+ padding = new Rect();
+ if (pagedView != null) {
+ // Constrain the dimensions of all apps so that it does not span the full width
+ int paddingLR = (availableWidthPx - (allAppsCellWidthPx * allAppsNumCols)) /
+ (2 * (allAppsNumCols + 1));
+ int paddingTB = (availableHeightPx - (allAppsCellHeightPx * allAppsNumRows)) /
+ (2 * (allAppsNumRows + 1));
+ paddingLR = Math.min(paddingLR, (int)((paddingLR + paddingTB) * 0.75f));
+ paddingTB = Math.min(paddingTB, (int)((paddingLR + paddingTB) * 0.75f));
+ int maxAllAppsWidth = (allAppsNumCols * (allAppsCellWidthPx + 2 * paddingLR));
+ int gridPaddingLR = (availableWidthPx - maxAllAppsWidth) / 2;
+ if (gridPaddingLR > (allAppsCellWidthPx / 4)) {
+ padding.left = padding.right = gridPaddingLR;
+ }
+ // The icons are centered, so we can't just offset by the page indicator height
+ // because the empty space will actually be pageIndicatorHeight + paddingTB
+ padding.bottom = Math.max(0, pageIndicatorHeight - paddingTB);
+ pagedView.setAllAppsPadding(padding);
+ pagedView.setWidgetsPageIndicatorPadding(pageIndicatorHeight);
+ }
+ }
+
+ // Layout the Overview Mode
+ View overviewMode = launcher.getOverviewPanel();
+ if (overviewMode != null) {
+ Rect r = getOverviewModeButtonBarRect();
+ lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams();
+ lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ lp.width = Math.min(availableWidthPx, overviewModeMaxBarWidthPx);
+ lp.height = r.height();
+ overviewMode.setLayoutParams(lp);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index ab48233..1bfaa23 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -198,7 +198,7 @@
* @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
* Makes dragging feel more precise, e.g. you can clip out a transparent border
*/
- public void startDrag(Bitmap b, int dragLayerX, int dragLayerY,
+ public DragView startDrag(Bitmap b, int dragLayerX, int dragLayerY,
DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion,
float initialDragViewScale) {
if (PROFILE_DRAWING_DURING_DRAG) {
@@ -245,6 +245,7 @@
mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
dragView.show(mMotionDownX, mMotionDownY);
handleMoveEvent(mMotionDownX, mMotionDownY);
+ return dragView;
}
/**
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index 159d7d9..dc0ba90 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -522,14 +522,18 @@
scale *= childScale;
int toX = coord[0];
int toY = coord[1];
+ float toScale = scale;
if (child instanceof TextView) {
TextView tv = (TextView) child;
+ // Account for the source scale of the icon (ie. from AllApps to Workspace, in which
+ // the workspace may have smaller icon bounds).
+ toScale = scale / dragView.getIntrinsicIconScaleFactor();
// The child may be scaled (always about the center of the view) so to account for it,
// we have to offset the position by the scaled size. Once we do that, we can center
// the drag view about the scaled child view.
- toY += Math.round(scale * tv.getPaddingTop());
- toY -= dragView.getMeasuredHeight() * (1 - scale) / 2;
+ toY += Math.round(toScale * tv.getPaddingTop());
+ toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
} else if (child instanceof FolderIcon) {
// Account for holographic blur padding on the drag view
@@ -555,7 +559,7 @@
}
}
};
- animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, scale, scale,
+ animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
}
diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java
index 2ef99ae..cca9ab1 100644
--- a/src/com/android/launcher3/DragSource.java
+++ b/src/com/android/launcher3/DragSource.java
@@ -30,6 +30,11 @@
*/
boolean supportsFlingToDelete();
+ /*
+ * @return the scale of the icons over the workspace icon size
+ */
+ float getIntrinsicIconScaleFactor();
+
/**
* A callback specifically made back to the source after an item from this source has been flung
* to be deleted on a DropTarget. In such a situation, this method will be called after
diff --git a/src/com/android/launcher3/DragView.java b/src/com/android/launcher3/DragView.java
index 686cf62..b66b55c 100644
--- a/src/com/android/launcher3/DragView.java
+++ b/src/com/android/launcher3/DragView.java
@@ -51,6 +51,9 @@
private float mOffsetX = 0.0f;
private float mOffsetY = 0.0f;
private float mInitialScale = 1f;
+ // The intrinsic icon scale factor is the scale factor for a drag icon over the workspace
+ // size. This is ignored for non-icons.
+ private float mIntrinsicIconScale = 1f;
/**
* Construct the drag view.
@@ -120,6 +123,15 @@
mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
}
+ /** Sets the scale of the view over the normal workspace icon size. */
+ public void setIntrinsicIconScaleFactor(float scale) {
+ mIntrinsicIconScale = scale;
+ }
+
+ public float getIntrinsicIconScaleFactor() {
+ return mIntrinsicIconScale;
+ }
+
public float getOffsetY() {
return mOffsetY;
}
diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java
index 5f8c011..42aa20d 100644
--- a/src/com/android/launcher3/DynamicGrid.java
+++ b/src/com/android/launcher3/DynamicGrid.java
@@ -16,674 +16,14 @@
package com.android.launcher3;
-import android.appwidget.AppWidgetHostView;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Paint;
-import android.graphics.Paint.FontMetrics;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.TypedValue;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-class DeviceProfileQuery {
- float widthDps;
- float heightDps;
- float value;
- PointF dimens;
-
- DeviceProfileQuery(float w, float h, float v) {
- widthDps = w;
- heightDps = h;
- value = v;
- dimens = new PointF(w, h);
- }
-}
-
-class DeviceProfile {
- public static interface DeviceProfileCallbacks {
- public void onAvailableSizeChanged(DeviceProfile grid);
- }
-
- String name;
- float minWidthDps;
- float minHeightDps;
- float numRows;
- float numColumns;
- float numHotseatIcons;
- private float iconSize;
- private float iconTextSize;
- private int iconDrawablePaddingOriginalPx;
- private float hotseatIconSize;
-
- boolean isLandscape;
- boolean isTablet;
- boolean isLargeTablet;
- boolean transposeLayoutWithOrientation;
-
- int desiredWorkspaceLeftRightMarginPx;
- int edgeMarginPx;
- Rect defaultWidgetPadding;
-
- int widthPx;
- int heightPx;
- int availableWidthPx;
- int availableHeightPx;
- int defaultPageSpacingPx;
-
- int overviewModeMinIconZoneHeightPx;
- int overviewModeMaxIconZoneHeightPx;
- int overviewModeMaxBarWidthPx;
- float overviewModeIconZoneRatio;
- float overviewModeScaleFactor;
-
- int iconSizePx;
- int iconTextSizePx;
- int iconDrawablePaddingPx;
- int cellWidthPx;
- int cellHeightPx;
- int allAppsIconSizePx;
- int allAppsIconTextSizePx;
- int allAppsCellWidthPx;
- int allAppsCellHeightPx;
- int allAppsCellPaddingPx;
- int folderBackgroundOffset;
- int folderIconSizePx;
- int folderCellWidthPx;
- int folderCellHeightPx;
- int hotseatCellWidthPx;
- int hotseatCellHeightPx;
- int hotseatIconSizePx;
- int hotseatBarHeightPx;
- int hotseatAllAppsRank;
- int allAppsNumRows;
- int allAppsNumCols;
- int searchBarSpaceWidthPx;
- int searchBarSpaceMaxWidthPx;
- int searchBarSpaceHeightPx;
- int searchBarHeightPx;
- int pageIndicatorHeightPx;
-
- private ArrayList<DeviceProfileCallbacks> mCallbacks = new ArrayList<DeviceProfileCallbacks>();
-
- DeviceProfile(String n, float w, float h, float r, float c,
- float is, float its, float hs, float his) {
- // Ensure that we have an odd number of hotseat items (since we need to place all apps)
- if (!AppsCustomizePagedView.DISABLE_ALL_APPS && hs % 2 == 0) {
- throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
- }
-
- name = n;
- minWidthDps = w;
- minHeightDps = h;
- numRows = r;
- numColumns = c;
- iconSize = is;
- iconTextSize = its;
- numHotseatIcons = hs;
- hotseatIconSize = his;
- }
-
- DeviceProfile(Context context,
- ArrayList<DeviceProfile> profiles,
- float minWidth, float minHeight,
- int wPx, int hPx,
- int awPx, int ahPx,
- Resources res) {
- DisplayMetrics dm = res.getDisplayMetrics();
- ArrayList<DeviceProfileQuery> points =
- new ArrayList<DeviceProfileQuery>();
- transposeLayoutWithOrientation =
- res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
- minWidthDps = minWidth;
- minHeightDps = minHeight;
-
- ComponentName cn = new ComponentName(context.getPackageName(),
- this.getClass().getName());
- defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
- edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
- desiredWorkspaceLeftRightMarginPx = 2 * edgeMarginPx;
- pageIndicatorHeightPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_height);
- defaultPageSpacingPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
- allAppsCellPaddingPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_all_apps_cell_padding);
- overviewModeMinIconZoneHeightPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_min_icon_zone_height);
- overviewModeMaxIconZoneHeightPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_max_icon_zone_height);
- overviewModeMaxBarWidthPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_max_width);
- overviewModeIconZoneRatio =
- res.getInteger(R.integer.config_dynamic_grid_overview_icon_zone_percentage) / 100f;
- overviewModeScaleFactor =
- res.getInteger(R.integer.config_dynamic_grid_overview_scale_percentage) / 100f;
-
- // Interpolate the rows
- for (DeviceProfile p : profiles) {
- points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numRows));
- }
- numRows = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points));
- // Interpolate the columns
- points.clear();
- for (DeviceProfile p : profiles) {
- points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numColumns));
- }
- numColumns = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points));
- // Interpolate the hotseat length
- points.clear();
- for (DeviceProfile p : profiles) {
- points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numHotseatIcons));
- }
- numHotseatIcons = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points));
- hotseatAllAppsRank = (int) (numHotseatIcons / 2);
-
- // Interpolate the icon size
- points.clear();
- for (DeviceProfile p : profiles) {
- points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconSize));
- }
- iconSize = invDistWeightedInterpolate(minWidth, minHeight, points);
- // AllApps uses the original non-scaled icon size
- allAppsIconSizePx = DynamicGrid.pxFromDp(iconSize, dm);
-
- // Interpolate the icon text size
- points.clear();
- for (DeviceProfile p : profiles) {
- points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconTextSize));
- }
- iconTextSize = invDistWeightedInterpolate(minWidth, minHeight, points);
- iconDrawablePaddingOriginalPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding);
- // AllApps uses the original non-scaled icon text size
- allAppsIconTextSizePx = DynamicGrid.pxFromDp(iconTextSize, dm);
-
- // Interpolate the hotseat icon size
- points.clear();
- for (DeviceProfile p : profiles) {
- points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.hotseatIconSize));
- }
- // Hotseat
- hotseatIconSize = invDistWeightedInterpolate(minWidth, minHeight, points);
-
- // Calculate the remaining vars
- updateFromConfiguration(context, res, wPx, hPx, awPx, ahPx);
- updateAvailableDimensions(context);
- }
-
- void addCallback(DeviceProfileCallbacks cb) {
- mCallbacks.add(cb);
- cb.onAvailableSizeChanged(this);
- }
- void removeCallback(DeviceProfileCallbacks cb) {
- mCallbacks.remove(cb);
- }
-
- private int getDeviceOrientation(Context context) {
- WindowManager windowManager = (WindowManager)
- context.getSystemService(Context.WINDOW_SERVICE);
- Resources resources = context.getResources();
- DisplayMetrics dm = resources.getDisplayMetrics();
- Configuration config = resources.getConfiguration();
- int rotation = windowManager.getDefaultDisplay().getRotation();
-
- boolean isLandscape = (config.orientation == Configuration.ORIENTATION_LANDSCAPE) &&
- (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180);
- boolean isRotatedPortrait = (config.orientation == Configuration.ORIENTATION_PORTRAIT) &&
- (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
- if (isLandscape || isRotatedPortrait) {
- return CellLayout.LANDSCAPE;
- } else {
- return CellLayout.PORTRAIT;
- }
- }
-
- private void updateAvailableDimensions(Context context) {
- WindowManager windowManager = (WindowManager)
- context.getSystemService(Context.WINDOW_SERVICE);
- Display display = windowManager.getDefaultDisplay();
- Resources resources = context.getResources();
- DisplayMetrics dm = resources.getDisplayMetrics();
- Configuration config = resources.getConfiguration();
-
- // There are three possible configurations that the dynamic grid accounts for, portrait,
- // landscape with the nav bar at the bottom, and landscape with the nav bar at the side.
- // To prevent waiting for fitSystemWindows(), we make the observation that in landscape,
- // the height is the smallest height (either with the nav bar at the bottom or to the
- // side) and otherwise, the height is simply the largest possible height for a portrait
- // device.
- Point size = new Point();
- Point smallestSize = new Point();
- Point largestSize = new Point();
- display.getSize(size);
- display.getCurrentSizeRange(smallestSize, largestSize);
- availableWidthPx = size.x;
- if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
- availableHeightPx = smallestSize.y;
- } else {
- availableHeightPx = largestSize.y;
- }
-
- // Check to see if the icons fit in the new available height. If not, then we need to
- // shrink the icon size.
- Rect workspacePadding = getWorkspacePadding();
- float scale = 1f;
- int drawablePadding = iconDrawablePaddingOriginalPx;
- updateIconSize(1f, drawablePadding, resources, dm);
- float usedHeight = (cellHeightPx * numRows);
- int maxHeight = (availableHeightPx - workspacePadding.top - workspacePadding.bottom);
- if (usedHeight > maxHeight) {
- scale = maxHeight / usedHeight;
- drawablePadding = 0;
- }
- updateIconSize(scale, drawablePadding, resources, dm);
-
- // Make the callbacks
- for (DeviceProfileCallbacks cb : mCallbacks) {
- cb.onAvailableSizeChanged(this);
- }
- }
-
- private void updateIconSize(float scale, int drawablePadding, Resources resources,
- DisplayMetrics dm) {
- iconSizePx = (int) (DynamicGrid.pxFromDp(iconSize, dm) * scale);
- iconTextSizePx = (int) (DynamicGrid.pxFromSp(iconTextSize, dm) * scale);
- iconDrawablePaddingPx = drawablePadding;
- hotseatIconSizePx = (int) (DynamicGrid.pxFromDp(hotseatIconSize, dm) * scale);
-
- // Search Bar
- searchBarSpaceMaxWidthPx = resources.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_max_width);
- searchBarHeightPx = resources.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_height);
- searchBarSpaceWidthPx = Math.min(searchBarSpaceMaxWidthPx, widthPx);
- searchBarSpaceHeightPx = searchBarHeightPx + 2 * edgeMarginPx;
-
- // Calculate the actual text height
- Paint textPaint = new Paint();
- textPaint.setTextSize(iconTextSizePx);
- FontMetrics fm = textPaint.getFontMetrics();
- cellWidthPx = iconSizePx;
- cellHeightPx = iconSizePx + iconDrawablePaddingPx + (int) Math.ceil(fm.bottom - fm.top);
-
- // Hotseat
- hotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx;
- hotseatCellWidthPx = iconSizePx;
- hotseatCellHeightPx = iconSizePx;
-
- // Folder
- folderCellWidthPx = cellWidthPx + 3 * edgeMarginPx;
- folderCellHeightPx = cellHeightPx + edgeMarginPx;
- folderBackgroundOffset = -edgeMarginPx;
- folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset;
-
- // All Apps
- Rect padding = getWorkspacePadding(isLandscape ?
- CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
- int pageIndicatorOffset =
- resources.getDimensionPixelSize(R.dimen.apps_customize_page_indicator_offset);
- allAppsCellWidthPx = allAppsIconSizePx;
- allAppsCellHeightPx = allAppsIconSizePx + drawablePadding + iconTextSizePx;
- int maxLongEdgeCellCount =
- resources.getInteger(R.integer.config_dynamic_grid_max_long_edge_cell_count);
- int maxShortEdgeCellCount =
- resources.getInteger(R.integer.config_dynamic_grid_max_short_edge_cell_count);
- int minEdgeCellCount =
- resources.getInteger(R.integer.config_dynamic_grid_min_edge_cell_count);
- int maxRows = (isLandscape ? maxShortEdgeCellCount : maxLongEdgeCellCount);
- int maxCols = (isLandscape ? maxLongEdgeCellCount : maxShortEdgeCellCount);
-
- allAppsNumRows = (availableHeightPx - pageIndicatorHeightPx) /
- (allAppsCellHeightPx + allAppsCellPaddingPx);
- allAppsNumRows = Math.max(minEdgeCellCount, Math.min(maxRows, allAppsNumRows));
- allAppsNumCols = (availableWidthPx) /
- (allAppsCellWidthPx + allAppsCellPaddingPx);
- allAppsNumCols = Math.max(minEdgeCellCount, Math.min(maxCols, allAppsNumCols));
- }
-
- void updateFromConfiguration(Context context, Resources resources, int wPx, int hPx,
- int awPx, int ahPx) {
- isLandscape = (resources.getConfiguration().orientation ==
- Configuration.ORIENTATION_LANDSCAPE);
- isTablet = resources.getBoolean(R.bool.is_tablet);
- isLargeTablet = resources.getBoolean(R.bool.is_large_tablet);
- widthPx = wPx;
- heightPx = hPx;
- availableWidthPx = awPx;
- availableHeightPx = ahPx;
-
- updateAvailableDimensions(context);
- }
-
- private float dist(PointF p0, PointF p1) {
- return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) +
- (p1.y-p0.y)*(p1.y-p0.y));
- }
-
- private float weight(PointF a, PointF b,
- float pow) {
- float d = dist(a, b);
- if (d == 0f) {
- return Float.POSITIVE_INFINITY;
- }
- return (float) (1f / Math.pow(d, pow));
- }
-
- private float invDistWeightedInterpolate(float width, float height,
- ArrayList<DeviceProfileQuery> points) {
- float sum = 0;
- float weights = 0;
- float pow = 5;
- float kNearestNeighbors = 3;
- final PointF xy = new PointF(width, height);
-
- ArrayList<DeviceProfileQuery> pointsByNearness = points;
- Collections.sort(pointsByNearness, new Comparator<DeviceProfileQuery>() {
- public int compare(DeviceProfileQuery a, DeviceProfileQuery b) {
- return (int) (dist(xy, a.dimens) - dist(xy, b.dimens));
- }
- });
-
- for (int i = 0; i < pointsByNearness.size(); ++i) {
- DeviceProfileQuery p = pointsByNearness.get(i);
- if (i < kNearestNeighbors) {
- float w = weight(xy, p.dimens, pow);
- if (w == Float.POSITIVE_INFINITY) {
- return p.value;
- }
- weights += w;
- }
- }
-
- for (int i = 0; i < pointsByNearness.size(); ++i) {
- DeviceProfileQuery p = pointsByNearness.get(i);
- if (i < kNearestNeighbors) {
- float w = weight(xy, p.dimens, pow);
- sum += w * p.value / weights;
- }
- }
-
- return sum;
- }
-
- Rect getWorkspacePadding() {
- return getWorkspacePadding(isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
- }
-
- Rect getWorkspacePadding(int orientation) {
- Rect padding = new Rect();
- if (orientation == CellLayout.LANDSCAPE &&
- transposeLayoutWithOrientation) {
- // Pad the left and right of the workspace with search/hotseat bar sizes
- padding.set(searchBarSpaceHeightPx, edgeMarginPx,
- hotseatBarHeightPx, edgeMarginPx);
- } else {
- if (isTablet()) {
- // Pad the left and right of the workspace to ensure consistent spacing
- // between all icons
- int width = (orientation == CellLayout.LANDSCAPE)
- ? Math.max(widthPx, heightPx)
- : Math.min(widthPx, heightPx);
- // XXX: If the icon size changes across orientations, we will have to take
- // that into account here too.
- int gap = (int) ((width - 2 * edgeMarginPx -
- (numColumns * cellWidthPx)) / (2 * (numColumns + 1)));
- padding.set(edgeMarginPx + gap,
- searchBarSpaceHeightPx,
- edgeMarginPx + gap,
- hotseatBarHeightPx + pageIndicatorHeightPx);
- } else {
- // Pad the top and bottom of the workspace with search/hotseat bar sizes
- padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
- searchBarSpaceHeightPx,
- desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
- hotseatBarHeightPx + pageIndicatorHeightPx);
- }
- }
- return padding;
- }
-
- int getWorkspacePageSpacing(int orientation) {
- if (orientation == CellLayout.LANDSCAPE &&
- transposeLayoutWithOrientation) {
- // In landscape mode the page spacing is set to the default.
- return defaultPageSpacingPx;
- } else {
- // In portrait, we want the pages spaced such that there is no
- // overhang of the previous / next page into the current page viewport.
- // We assume symmetrical padding in portrait mode.
- return 2 * getWorkspacePadding().left;
- }
- }
-
- Rect getOverviewModeButtonBarRect() {
- int zoneHeight = (int) (overviewModeIconZoneRatio * availableHeightPx);
- zoneHeight = Math.min(overviewModeMaxIconZoneHeightPx,
- Math.max(overviewModeMinIconZoneHeightPx, zoneHeight));
- return new Rect(0, availableHeightPx - zoneHeight, 0, availableHeightPx);
- }
-
- float getOverviewModeScale() {
- Rect workspacePadding = getWorkspacePadding();
- Rect overviewBar = getOverviewModeButtonBarRect();
- int pageSpace = availableHeightPx - workspacePadding.top - workspacePadding.bottom;
- return (overviewModeScaleFactor * (pageSpace - overviewBar.height())) / pageSpace;
- }
-
- // The rect returned will be extended to below the system ui that covers the workspace
- Rect getHotseatRect() {
- if (isVerticalBarLayout()) {
- return new Rect(availableWidthPx - hotseatBarHeightPx, 0,
- Integer.MAX_VALUE, availableHeightPx);
- } else {
- return new Rect(0, availableHeightPx - hotseatBarHeightPx,
- availableWidthPx, Integer.MAX_VALUE);
- }
- }
-
- int calculateCellWidth(int width, int countX) {
- return width / countX;
- }
- int calculateCellHeight(int height, int countY) {
- return height / countY;
- }
-
- boolean isPhone() {
- return !isTablet && !isLargeTablet;
- }
- boolean isTablet() {
- return isTablet;
- }
- boolean isLargeTablet() {
- return isLargeTablet;
- }
-
- boolean isVerticalBarLayout() {
- return isLandscape && transposeLayoutWithOrientation;
- }
-
- boolean shouldFadeAdjacentWorkspaceScreens() {
- return isVerticalBarLayout() || isLargeTablet();
- }
-
- public void layout(Launcher launcher) {
- FrameLayout.LayoutParams lp;
- Resources res = launcher.getResources();
- boolean hasVerticalBarLayout = isVerticalBarLayout();
-
- // Layout the search bar space
- View searchBar = launcher.getSearchBar();
- lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
- if (hasVerticalBarLayout) {
- // Vertical search bar
- lp.gravity = Gravity.TOP | Gravity.LEFT;
- lp.width = searchBarSpaceHeightPx;
- lp.height = LayoutParams.MATCH_PARENT;
- searchBar.setPadding(
- 0, 2 * edgeMarginPx, 0,
- 2 * edgeMarginPx);
- } else {
- // Horizontal search bar
- lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- lp.width = searchBarSpaceWidthPx;
- lp.height = searchBarSpaceHeightPx;
- searchBar.setPadding(
- 2 * edgeMarginPx,
- 2 * edgeMarginPx,
- 2 * edgeMarginPx, 0);
- }
- searchBar.setLayoutParams(lp);
-
- // Layout the search bar
- View qsbBar = launcher.getQsbBar();
- LayoutParams vglp = qsbBar.getLayoutParams();
- vglp.width = LayoutParams.MATCH_PARENT;
- vglp.height = LayoutParams.MATCH_PARENT;
- qsbBar.setLayoutParams(vglp);
-
- // Layout the voice proxy
- View voiceButtonProxy = launcher.findViewById(R.id.voice_button_proxy);
- if (voiceButtonProxy != null) {
- if (hasVerticalBarLayout) {
- // TODO: MOVE THIS INTO SEARCH BAR MEASURE
- } else {
- lp = (FrameLayout.LayoutParams) voiceButtonProxy.getLayoutParams();
- lp.gravity = Gravity.TOP | Gravity.END;
- lp.width = (widthPx - searchBarSpaceWidthPx) / 2 +
- 2 * iconSizePx;
- lp.height = searchBarSpaceHeightPx;
- }
- }
-
- // Layout the workspace
- PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
- lp = (FrameLayout.LayoutParams) workspace.getLayoutParams();
- lp.gravity = Gravity.CENTER;
- int orientation = isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT;
- Rect padding = getWorkspacePadding(orientation);
- workspace.setLayoutParams(lp);
- workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
- workspace.setPageSpacing(getWorkspacePageSpacing(orientation));
-
- // Layout the hotseat
- View hotseat = launcher.findViewById(R.id.hotseat);
- lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
- if (hasVerticalBarLayout) {
- // Vertical hotseat
- lp.gravity = Gravity.RIGHT;
- lp.width = hotseatBarHeightPx;
- lp.height = LayoutParams.MATCH_PARENT;
- hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
- } else if (isTablet()) {
- // Pad the hotseat with the grid gap calculated above
- int gridGap = (int) ((widthPx - 2 * edgeMarginPx -
- (numColumns * cellWidthPx)) / (2 * (numColumns + 1)));
- int gridWidth = (int) ((numColumns * cellWidthPx) +
- ((numColumns - 1) * gridGap));
- int hotseatGap = (int) Math.max(0,
- (gridWidth - (numHotseatIcons * hotseatCellWidthPx))
- / (numHotseatIcons - 1));
- lp.gravity = Gravity.BOTTOM;
- lp.width = LayoutParams.MATCH_PARENT;
- lp.height = hotseatBarHeightPx;
- hotseat.setPadding(2 * edgeMarginPx + gridGap + hotseatGap, 0,
- 2 * edgeMarginPx + gridGap + hotseatGap,
- 2 * edgeMarginPx);
- } else {
- // For phones, layout the hotseat without any bottom margin
- // to ensure that we have space for the folders
- lp.gravity = Gravity.BOTTOM;
- lp.width = LayoutParams.MATCH_PARENT;
- lp.height = hotseatBarHeightPx;
- hotseat.findViewById(R.id.layout).setPadding(2 * edgeMarginPx, 0,
- 2 * edgeMarginPx, 0);
- }
- hotseat.setLayoutParams(lp);
-
- // Layout the page indicators
- View pageIndicator = launcher.findViewById(R.id.page_indicator);
- if (pageIndicator != null) {
- if (hasVerticalBarLayout) {
- // Hide the page indicators when we have vertical search/hotseat
- pageIndicator.setVisibility(View.GONE);
- } else {
- // Put the page indicators above the hotseat
- lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams();
- lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- lp.width = LayoutParams.WRAP_CONTENT;
- lp.height = LayoutParams.WRAP_CONTENT;
- lp.bottomMargin = hotseatBarHeightPx;
- pageIndicator.setLayoutParams(lp);
- }
- }
-
- // Layout AllApps
- AppsCustomizeTabHost host = (AppsCustomizeTabHost)
- launcher.findViewById(R.id.apps_customize_pane);
- if (host != null) {
- // Center the all apps page indicator
- int pageIndicatorHeight = (int) (pageIndicatorHeightPx * Math.min(1f,
- (allAppsIconSizePx / DynamicGrid.DEFAULT_ICON_SIZE_PX)));
- pageIndicator = host.findViewById(R.id.apps_customize_page_indicator);
- if (pageIndicator != null) {
- lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams();
- lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- lp.width = LayoutParams.WRAP_CONTENT;
- lp.height = pageIndicatorHeight;
- pageIndicator.setLayoutParams(lp);
- }
-
- AppsCustomizePagedView pagedView = (AppsCustomizePagedView)
- host.findViewById(R.id.apps_customize_pane_content);
- padding = new Rect();
- if (pagedView != null) {
- // Constrain the dimensions of all apps so that it does not span the full width
- int paddingLR = (availableWidthPx - (allAppsCellWidthPx * allAppsNumCols)) /
- (2 * (allAppsNumCols + 1));
- int paddingTB = (availableHeightPx - (allAppsCellHeightPx * allAppsNumRows)) /
- (2 * (allAppsNumRows + 1));
- paddingLR = Math.min(paddingLR, (int)((paddingLR + paddingTB) * 0.75f));
- paddingTB = Math.min(paddingTB, (int)((paddingLR + paddingTB) * 0.75f));
- int maxAllAppsWidth = (allAppsNumCols * (allAppsCellWidthPx + 2 * paddingLR));
- int gridPaddingLR = (availableWidthPx - maxAllAppsWidth) / 2;
- if (gridPaddingLR > (allAppsCellWidthPx / 4)) {
- padding.left = padding.right = gridPaddingLR;
- }
- // The icons are centered, so we can't just offset by the page indicator height
- // because the empty space will actually be pageIndicatorHeight + paddingTB
- padding.bottom = Math.max(0, pageIndicatorHeight - paddingTB);
- pagedView.setAllAppsPadding(padding);
- pagedView.setWidgetsPageIndicatorPadding(pageIndicatorHeight);
- }
- }
-
- // Layout the Overview Mode
- View overviewMode = launcher.getOverviewPanel();
- if (overviewMode != null) {
- Rect r = getOverviewModeButtonBarRect();
- lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams();
- lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- lp.width = Math.min(availableWidthPx, overviewModeMaxBarWidthPx);
- lp.height = r.height();
- overviewMode.setLayoutParams(lp);
- }
- }
-}
-
public class DynamicGrid {
@SuppressWarnings("unused")
private static final String TAG = "DynamicGrid";
@@ -755,7 +95,7 @@
resources);
}
- DeviceProfile getDeviceProfile() {
+ public DeviceProfile getDeviceProfile() {
return mProfile;
}
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index bce6707..83be143 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -27,19 +27,11 @@
class FastBitmapDrawable extends Drawable {
private Bitmap mBitmap;
private int mAlpha;
- private int mWidth;
- private int mHeight;
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
FastBitmapDrawable(Bitmap b) {
- mAlpha = 255;
+ mAlpha = 255;
mBitmap = b;
- if (b != null) {
- mWidth = mBitmap.getWidth();
- mHeight = mBitmap.getHeight();
- } else {
- mWidth = mHeight = 0;
- }
}
@Override
@@ -76,32 +68,22 @@
@Override
public int getIntrinsicWidth() {
- return mWidth;
+ return getBounds().width();
}
@Override
public int getIntrinsicHeight() {
- return mHeight;
+ return getBounds().height();
}
@Override
public int getMinimumWidth() {
- return mWidth;
+ return getBounds().width();
}
@Override
public int getMinimumHeight() {
- return mHeight;
- }
-
- public void setBitmap(Bitmap b) {
- mBitmap = b;
- if (b != null) {
- mWidth = mBitmap.getWidth();
- mHeight = mBitmap.getHeight();
- } else {
- mWidth = mHeight = 0;
- }
+ return getBounds().height();
}
public Bitmap getBitmap() {
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index f26d01f..1d234ff 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -119,6 +119,11 @@
private int DRAG_MODE_REORDER = 1;
private int mDragMode = DRAG_MODE_NONE;
+ // We avoid measuring the scroll view with a 0 width or height, as this
+ // results in CellLayout being measured as UNSPECIFIED, which it does
+ // not support.
+ private static final int MIN_CONTENT_DIMEN = 5;
+
private boolean mDestroyed;
private AutoScrollHelper mAutoScrollHelper;
@@ -787,6 +792,11 @@
}
@Override
+ public float getIntrinsicIconScaleFactor() {
+ return 1f;
+ }
+
+ @Override
public boolean supportsFlingToDelete() {
return true;
}
@@ -961,8 +971,13 @@
int maxContentAreaHeight = grid.availableHeightPx -
workspacePadding.top - workspacePadding.bottom -
mFolderNameHeight;
- return Math.min(maxContentAreaHeight,
+ int height = Math.min(maxContentAreaHeight,
mContent.getDesiredHeight());
+ return Math.max(height, MIN_CONTENT_DIMEN);
+ }
+
+ private int getContentAreaWidth() {
+ return Math.max(mContent.getDesiredWidth(), MIN_CONTENT_DIMEN);
}
private int getFolderHeight() {
@@ -974,11 +989,12 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
int height = getFolderHeight();
- int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredWidth(),
+ int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(getContentAreaWidth(),
MeasureSpec.EXACTLY);
int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(getContentAreaHeight(),
MeasureSpec.EXACTLY);
- mContent.setFixedSize(mContent.getDesiredWidth(), mContent.getDesiredHeight());
+
+ mContent.setFixedSize(getContentAreaWidth(), getContentAreaHeight());
mScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec);
mFolderName.measure(contentAreaWidthSpec,
MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 835c472..fb75161 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -294,7 +294,7 @@
// Add the new apps to the model and bind them
if (!addShortcuts.isEmpty()) {
LauncherAppState app = LauncherAppState.getInstance();
- app.getModel().addAndBindAddedApps(context, addShortcuts, null);
+ app.getModel().addAndBindAddedApps(context, addShortcuts, new ArrayList<AppInfo>());
}
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3100241..89abd9f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -45,7 +45,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -113,6 +112,7 @@
import java.util.Date;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Default launcher application.
@@ -181,8 +181,10 @@
private static final String RUNTIME_STATE_PENDING_ADD_SPAN_Y = "launcher.add_span_y";
// Type: parcelable
private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_INFO = "launcher.add_widget_info";
- // Type: parcelable
+ // Type: parcelable
private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_ID = "launcher.add_widget_id";
+ // Type: int[]
+ private static final String RUNTIME_STATE_VIEW_IDS = "launcher.view_ids";
private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
private static final String TOOLBAR_SEARCH_ICON_METADATA_NAME =
@@ -207,6 +209,9 @@
private static final Object sLock = new Object();
private static int sScreen = DEFAULT_SCREEN;
+ private HashMap<Integer, Integer> mItemIdToViewId = new HashMap<Integer, Integer>();
+ private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
+
// How long to wait before the new-shortcut animation automatically pans the workspace
private static int NEW_APPS_PAGE_MOVE_DELAY = 500;
private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
@@ -671,6 +676,34 @@
}
/**
+ * Copied from View -- the View version of the method isn't called
+ * anywhere else in our process and only exists for API level 17+,
+ * so it's ok to keep our own version with no API requirement.
+ */
+ public static int generateViewId() {
+ for (;;) {
+ final int result = sNextGeneratedId.get();
+ // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
+ int newValue = result + 1;
+ if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
+ if (sNextGeneratedId.compareAndSet(result, newValue)) {
+ return result;
+ }
+ }
+ }
+
+ public int getViewIdForItem(ItemInfo info) {
+ // This cast is safe given the > 2B range for int.
+ int itemId = (int) info.id;
+ if (mItemIdToViewId.containsKey(itemId)) {
+ return mItemIdToViewId.get(itemId);
+ }
+ int viewId = generateViewId();
+ mItemIdToViewId.put(itemId, viewId);
+ return viewId;
+ }
+
+ /**
* Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
* a configuration step, this allows the proper animations to run after other transitions.
*/
@@ -1108,6 +1141,7 @@
*
* @param savedState The previous state.
*/
+ @SuppressWarnings("unchecked")
private void restoreState(Bundle savedState) {
if (savedState == null) {
return;
@@ -1160,6 +1194,8 @@
int currentIndex = savedState.getInt("apps_customize_currentIndex");
mAppsCustomizeContent.restorePageForIndex(currentIndex);
}
+ mItemIdToViewId = (HashMap<Integer, Integer>)
+ savedState.getSerializable(RUNTIME_STATE_VIEW_IDS);
}
/**
@@ -1704,7 +1740,7 @@
// In all these cases, only animate if we're already on home
mWorkspace.exitWidgetResizeMode();
if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() &&
- openFolder == null) {
+ openFolder == null && shouldMoveToDefaultScreenOnHomeIntent()) {
mWorkspace.moveToDefaultScreen(true);
}
@@ -1730,6 +1766,8 @@
if (mAppsCustomizeTabHost != null) {
mAppsCustomizeTabHost.reset();
}
+
+ onHomeIntent();
}
if (DEBUG_RESUME_TIME) {
@@ -1737,6 +1775,21 @@
}
}
+ /**
+ * Override point for subclasses to prevent movement to the default screen when the home
+ * button is pressed. Used (for example) in GEL, to prevent movement during a search.
+ */
+ protected boolean shouldMoveToDefaultScreenOnHomeIntent() {
+ return true;
+ }
+
+ /**
+ * Override point for subclasses to provide custom behaviour for when a home intent is fired.
+ */
+ protected void onHomeIntent() {
+ // Do nothing
+ }
+
@Override
public void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
@@ -1784,6 +1837,7 @@
int currentIndex = mAppsCustomizeContent.getSaveInstanceStateIndex();
outState.putInt("apps_customize_currentIndex", currentIndex);
}
+ outState.putSerializable(RUNTIME_STATE_VIEW_IDS, mItemIdToViewId);
}
@Override
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index fe2b43f..9a47eaa 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -191,7 +191,7 @@
availableWidth, availableHeight);
return grid;
}
- DynamicGrid getDynamicGrid() {
+ public DynamicGrid getDynamicGrid() {
return mDynamicGrid;
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index b89579e..0a3ff3e 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -283,7 +283,10 @@
addAndBindAddedApps(context, workspaceApps, cb, allAppsApps);
}
public void addAndBindAddedApps(final Context context, final ArrayList<ItemInfo> workspaceApps,
- final Callbacks callbacks, final ArrayList<AppInfo> allAppsApps) {
+ final Callbacks callbacks, final ArrayList<AppInfo> allAppsApps) {
+ if (workspaceApps == null || allAppsApps == null) {
+ throw new RuntimeException("workspaceApps and allAppsApps must not be null");
+ }
if (workspaceApps.isEmpty() && allAppsApps.isEmpty()) {
return;
}
@@ -1522,7 +1525,7 @@
}
if (!added.isEmpty()) {
Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
- addAndBindAddedApps(context, added, cb, null);
+ addAndBindAddedApps(context, added, cb, new ArrayList<AppInfo>());
}
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index d517d8b..9b17fcd 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -726,7 +726,12 @@
onComplete, stripEmptyScreens);
}
return;
+ } else if (stripEmptyScreens) {
+ // If we're not going to strip the empty screens after removing
+ // the extra empty screen, do it right away.
+ stripEmptyScreens();
}
+
if (onComplete != null) {
onComplete.run();
}
@@ -977,7 +982,9 @@
}
// Get the canonical child id to uniquely represent this view in this screen
- int childId = LauncherModel.getCellLayoutChildId(container, screenId, x, y, spanX, spanY);
+ ItemInfo info = (ItemInfo) child.getTag();
+ int childId = mLauncher.getViewIdForItem(info);
+
boolean markCellsAsOccupied = !(child instanceof Folder);
if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
// TODO: This branch occurs when the workspace is adding views
@@ -2136,7 +2143,8 @@
if (stateIsSmall) {
finalAlpha = 0f;
} else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
- finalAlpha = i == getNextPage() ? 1f : 0f;
+
+ finalAlpha = (i == getNextPage() || i < numCustomPages()) ? 1f : 0f;
} else {
finalAlpha = 1f;
}
@@ -2361,7 +2369,9 @@
void hideCustomContentIfNecessary() {
boolean hide = mState != Workspace.State.NORMAL;
if (hide && hasCustomContent()) {
+ disableLayoutTransitions();
mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(INVISIBLE);
+ enableLayoutTransitions();
}
}
@@ -2377,6 +2387,11 @@
final CellLayout cl = (CellLayout) getChildAt(i);
cl.setShortcutAndWidgetAlpha(1f);
}
+ } else {
+ for (int i = 0; i < numCustomPages(); i++) {
+ final CellLayout cl = (CellLayout) getChildAt(i);
+ cl.setShortcutAndWidgetAlpha(1f);
+ }
}
showCustomContentIfNecessary();
}
@@ -2564,8 +2579,16 @@
icon.clearPressedOrFocusedBackground();
}
- mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
+ if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {
+ String msg = "Drag started with a view that has no tag set. This "
+ + "will cause a crash (issue 11627249) down the line. "
+ + "View: " + child + " tag: " + child.getTag();
+ throw new IllegalStateException(msg);
+ }
+
+ DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);
+ dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
if (child.getParent() instanceof ShortcutAndWidgetContainer) {
mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent();
@@ -2911,8 +2934,6 @@
lp.cellHSpan = item.spanX;
lp.cellVSpan = item.spanY;
lp.isLockedToGrid = true;
- cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screenId,
- mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
cell instanceof LauncherAppWidgetHostView) {
@@ -4169,6 +4190,11 @@
}
@Override
+ public float getIntrinsicIconScaleFactor() {
+ return 1f;
+ }
+
+ @Override
public boolean supportsFlingToDelete() {
return true;
}
@@ -4589,6 +4615,7 @@
child.requestFocus();
}
}
+ exitWidgetResizeMode();
}
@Override