Merge "Setting statusbar and nav bar colors in theme instead of code" into ub-launcher3-burnaby-polish
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
index b40e4bd..5d41238 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -309,7 +309,7 @@
@Override
public float getParallaxOffset() {
- return 0;
+ return 0.5f;
}
};
req.result = new DrawableTileSource(a.getContext(),
diff --git a/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java b/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java
index 2d496a5..6baac6a 100644
--- a/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java
+++ b/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java
@@ -159,6 +159,7 @@
public enum State { NOT_LOADED, LOADED, ERROR_LOADING };
private State mState = State.NOT_LOADED;
+ /** Returns whether loading was successful. */
public boolean loadInBackground(InBitmapProvider bitmapProvider) {
ExifInterface ei = new ExifInterface();
if (readExif(ei)) {
@@ -193,7 +194,7 @@
try {
mPreview = loadPreviewBitmap(opts);
} catch (IllegalArgumentException e) {
- Log.d(TAG, "Unable to reusage bitmap", e);
+ Log.d(TAG, "Unable to reuse bitmap", e);
opts.inBitmap = null;
mPreview = null;
}
@@ -202,6 +203,10 @@
if (mPreview == null) {
mPreview = loadPreviewBitmap(opts);
}
+ if (mPreview == null) {
+ mState = State.ERROR_LOADING;
+ return false;
+ }
// Verify that the bitmap can be used on GL surface
try {
@@ -212,7 +217,7 @@
Log.d(TAG, "Image cannot be rendered on a GL surface", e);
mState = State.ERROR_LOADING;
}
- return true;
+ return mState == State.LOADED;
}
}
@@ -310,7 +315,7 @@
Bitmap b = BitmapFactory.decodeStream(is, null, options);
Utils.closeSilently(is);
return b;
- } catch (FileNotFoundException e) {
+ } catch (FileNotFoundException | OutOfMemoryError e) {
Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
return null;
}
@@ -412,7 +417,8 @@
"Failed to create preview of apropriate size! "
+ " in: %dx%d, out: %dx%d",
mWidth, mHeight,
- preview.getWidth(), preview.getHeight()));
+ preview == null ? -1 : preview.getWidth(),
+ preview == null ? -1 : preview.getHeight()));
}
}
}
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 5d69012..1025aba 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -19,11 +19,15 @@
<!-- Dynamic Grid -->
<dimen name="dynamic_grid_edge_margin">6dp</dimen>
- <dimen name="dynamic_grid_search_bar_max_width">500dp</dimen>
- <dimen name="dynamic_grid_search_bar_height">56dp</dimen>
- <!-- We want 32dp extra for the tall search bar, but 10dp comes from unwanted padding between
- the search bar and workspace. -->
- <dimen name="dynamic_grid_search_bar_height_tall">78dp</dimen>
+ <dimen name="dynamic_grid_search_bar_height">48dp</dimen>
+ <!-- We want 32dp extra for the tall search bar. -->
+ <dimen name="dynamic_grid_search_bar_height_tall">80dp</dimen>
+ <dimen name="qsb_internal_padding_top">8dp</dimen>
+ <dimen name="qsb_internal_padding_bottom">8dp</dimen>
+ <dimen name="dynamic_grid_search_bar_bottom_padding">4dp</dimen>
+ <!-- Reduce the padding between the search bar and workspace when the search bar is tall -->
+ <dimen name="dynamic_grid_search_bar_bottom_padding_short">-6dp</dimen>
+ <dimen name="dynamic_grid_search_bar_bottom_padding_tablet">16dp</dimen>
<dimen name="dynamic_grid_page_indicator_height">20dp</dimen>
<dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
<dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 71a1df3..5f64a82 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -899,9 +899,14 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() -
- (mCountX * mCellWidth);
- int left = getPaddingLeft() + (int) Math.ceil(offset / 2f);
+ boolean isFullscreen = mShortcutsAndWidgets.getChildCount() > 0 &&
+ ((LayoutParams) mShortcutsAndWidgets.getChildAt(0).getLayoutParams()).isFullscreen;
+ int left = getPaddingLeft();
+ if (!isFullscreen) {
+ int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() -
+ (mCountX * mCellWidth);
+ left += (int) Math.ceil(offset / 2f);
+ }
int top = getPaddingTop();
mTouchFeedbackView.layout(left, top,
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index ed6b7d7..ccbfba1 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -90,7 +90,7 @@
public int hotseatCellWidthPx;
public int hotseatCellHeightPx;
public int hotseatIconSizePx;
- private int hotseatBarHeightNormalPx, hotseatBarHeightShortPx;
+ private int normalHotseatBarHeightPx, shortHotseatBarHeightPx;
private int hotseatBarHeightPx; // One of the above.
// All apps
@@ -101,8 +101,11 @@
public final int allAppsIconTextSizePx;
// QSB
- private int searchBarSpaceWidthPx;
- private int searchBarSpaceHeightNormalPx, searchBarSpaceHeightTallPx;
+ private int searchBarWidgetInternalPaddingTop, searchBarWidgetInternalPaddingBottom;
+ private int searchBarTopPaddingPx;
+ private int normalSearchBarBottomPaddingPx, tallSearchBarBottomPaddingPx;
+ private int searchBarBottomPaddingPx; // One of the above.
+ private int normalSearchBarSpaceHeightPx, tallSearchBarSpaceHeightPx;
private int searchBarSpaceHeightPx; // One of the above.
public DeviceProfile(Context context, InvariantDeviceProfile inv,
@@ -205,12 +208,26 @@
hotseatIconSizePx = (int) (Utilities.pxFromDp(inv.hotseatIconSize, dm) * scale);
// Search Bar
- searchBarSpaceWidthPx = Math.min(widthPx,
- res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_max_width));
- searchBarSpaceHeightNormalPx = getSearchBarTopOffset()
- + res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_height);
- searchBarSpaceHeightTallPx = getSearchBarTopOffset()
- + res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_height_tall);
+ normalSearchBarSpaceHeightPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_search_bar_height);
+ tallSearchBarSpaceHeightPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_search_bar_height_tall);
+ searchBarWidgetInternalPaddingTop = res.getDimensionPixelSize(
+ R.dimen.qsb_internal_padding_top);
+ searchBarWidgetInternalPaddingBottom = res.getDimensionPixelSize(
+ R.dimen.qsb_internal_padding_bottom);
+ if (isTablet && !isVerticalBarLayout()) {
+ searchBarTopPaddingPx = searchBarWidgetInternalPaddingTop;
+ normalSearchBarBottomPaddingPx = searchBarWidgetInternalPaddingBottom +
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_bottom_padding_tablet);
+ tallSearchBarBottomPaddingPx = normalSearchBarBottomPaddingPx;
+ } else {
+ searchBarTopPaddingPx = searchBarWidgetInternalPaddingTop;
+ normalSearchBarBottomPaddingPx = searchBarWidgetInternalPaddingBottom +
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_bottom_padding);
+ tallSearchBarBottomPaddingPx = searchBarWidgetInternalPaddingBottom +
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_bottom_padding_short);
+ }
// Calculate the actual text height
Paint textPaint = new Paint();
@@ -222,13 +239,15 @@
dragViewScale = (iconSizePx + scaleDps) / iconSizePx;
// Hotseat
- hotseatBarHeightNormalPx = iconSizePx + 4 * edgeMarginPx;
- hotseatBarHeightShortPx = iconSizePx + 2 * edgeMarginPx;
+ normalHotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx;
+ shortHotseatBarHeightPx = iconSizePx + 2 * edgeMarginPx;
hotseatCellWidthPx = iconSizePx;
hotseatCellHeightPx = iconSizePx;
// Folder
- folderCellWidthPx = Math.min(cellWidthPx + 6 * edgeMarginPx,
+ int folderCellPadding = isTablet || isLandscape ? 6 * edgeMarginPx : 3 * edgeMarginPx;
+ // Don't let the folder get too close to the edges of the screen.
+ folderCellWidthPx = Math.min(cellWidthPx + folderCellPadding,
(availableWidthPx - 4 * edgeMarginPx) / inv.numFolderColumns);
folderCellHeightPx = cellHeightPx + edgeMarginPx;
folderBackgroundOffset = -edgeMarginPx;
@@ -251,13 +270,20 @@
allAppsNumPredictiveCols = numPredictiveAppCols;
}
- /** Returns the search bar top offset */
- private int getSearchBarTopOffset() {
- if (isTablet && !isVerticalBarLayout()) {
- return 4 * edgeMarginPx;
- } else {
- return 2 * edgeMarginPx;
+ /** Returns the amount of extra space to allocate to the search bar for vertical padding. */
+ private int getSearchBarTotalVerticalPadding() {
+ return searchBarTopPaddingPx + searchBarBottomPaddingPx;
+ }
+
+ /** Returns the width and height of the search bar, ignoring any padding. */
+ public Point getSearchBarDimensForWidgetOpts(Resources res) {
+ Rect searchBarBounds = getSearchBarBounds(Utilities.isRtl(res));
+ if (isVerticalBarLayout()) {
+ return new Point(searchBarBounds.width(), searchBarBounds.height());
}
+ int widgetInternalPadding = searchBarWidgetInternalPaddingTop +
+ searchBarWidgetInternalPaddingBottom;
+ return new Point(searchBarBounds.width(), searchBarSpaceHeightPx + widgetInternalPadding);
}
/** Returns the search bar bounds in the current orientation */
@@ -265,13 +291,14 @@
Rect bounds = new Rect();
if (isVerticalBarLayout()) {
if (isLayoutRtl) {
- bounds.set(availableWidthPx - searchBarSpaceHeightNormalPx, edgeMarginPx,
+ bounds.set(availableWidthPx - normalSearchBarSpaceHeightPx, edgeMarginPx,
availableWidthPx, availableHeightPx - edgeMarginPx);
} else {
- bounds.set(0, edgeMarginPx, searchBarSpaceHeightNormalPx,
+ bounds.set(0, edgeMarginPx, normalSearchBarSpaceHeightPx,
availableHeightPx - edgeMarginPx);
}
} else {
+ int boundsBottom = searchBarSpaceHeightPx + getSearchBarTotalVerticalPadding();
if (isTablet) {
// Pad the left and right of the workspace to ensure consistent spacing
// between all icons
@@ -280,14 +307,13 @@
// that into account here too.
int gap = (int) ((width - 2 * edgeMarginPx -
(inv.numColumns * cellWidthPx)) / (2 * (inv.numColumns + 1)));
- bounds.set(edgeMarginPx + gap, getSearchBarTopOffset(),
- availableWidthPx - (edgeMarginPx + gap),
- searchBarSpaceHeightPx);
+ bounds.set(edgeMarginPx + gap, 0,
+ availableWidthPx - (edgeMarginPx + gap), boundsBottom);
} else {
bounds.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
- getSearchBarTopOffset(),
+ 0,
availableWidthPx - (desiredWorkspaceLeftRightMarginPx -
- defaultWidgetPadding.right), searchBarSpaceHeightPx);
+ defaultWidgetPadding.right), boundsBottom);
}
}
return bounds;
@@ -300,21 +326,21 @@
if (isVerticalBarLayout()) {
// Pad the left and right of the workspace with search/hotseat bar sizes
if (isLayoutRtl) {
- padding.set(hotseatBarHeightNormalPx, edgeMarginPx,
+ padding.set(normalHotseatBarHeightPx, edgeMarginPx,
searchBarBounds.width(), edgeMarginPx);
} else {
padding.set(searchBarBounds.width(), edgeMarginPx,
- hotseatBarHeightNormalPx, edgeMarginPx);
+ normalHotseatBarHeightPx, edgeMarginPx);
}
} else {
+ int paddingTop = searchBarBounds.bottom;
+ int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
if (isTablet) {
// Pad the left and right of the workspace to ensure consistent spacing
// between all icons
float gapScale = 1f + (dragViewScale - 1f) / 2f;
int width = getCurrentWidth();
int height = getCurrentHeight();
- int paddingTop = searchBarBounds.bottom;
- int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
// The amount of screen space available for left/right padding.
int availablePaddingX = Math.max(0, width - (int) ((inv.numColumns * cellWidthPx) +
((inv.numColumns - 1) * gapScale * cellWidthPx)));
@@ -327,9 +353,9 @@
} else {
// Pad the top and bottom of the workspace with search/hotseat bar sizes
padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
- searchBarBounds.bottom,
+ paddingTop,
desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
- hotseatBarHeightPx + pageIndicatorHeightPx);
+ paddingBottom);
}
}
return padding;
@@ -357,7 +383,7 @@
// The rect returned will be extended to below the system ui that covers the workspace
Rect getHotseatRect() {
if (isVerticalBarLayout()) {
- return new Rect(availableWidthPx - hotseatBarHeightNormalPx, 0,
+ return new Rect(availableWidthPx - normalHotseatBarHeightPx, 0,
Integer.MAX_VALUE, availableHeightPx);
} else {
return new Rect(0, availableHeightPx - hotseatBarHeightPx,
@@ -398,11 +424,13 @@
// TODO(twickham): b/25154513
public void setSearchBarHeight(int searchBarHeight) {
if (searchBarHeight == LauncherCallbacks.SEARCH_BAR_HEIGHT_TALL) {
- hotseatBarHeightPx = hotseatBarHeightShortPx;
- searchBarSpaceHeightPx = searchBarSpaceHeightTallPx;
+ hotseatBarHeightPx = shortHotseatBarHeightPx;
+ searchBarSpaceHeightPx = tallSearchBarSpaceHeightPx;
+ searchBarBottomPaddingPx = tallSearchBarBottomPaddingPx;
} else {
- hotseatBarHeightPx = hotseatBarHeightNormalPx;
- searchBarSpaceHeightPx = searchBarSpaceHeightNormalPx;
+ hotseatBarHeightPx = normalHotseatBarHeightPx;
+ searchBarSpaceHeightPx = normalSearchBarSpaceHeightPx;
+ searchBarBottomPaddingPx = normalSearchBarBottomPaddingPx;
}
}
@@ -412,13 +440,15 @@
final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources());
// Layout the search bar space
+ Rect searchBarBounds = getSearchBarBounds(isLayoutRtl);
View searchBar = launcher.getSearchDropTargetBar();
lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
+ lp.width = searchBarBounds.width();
+ lp.height = searchBarBounds.height();
if (hasVerticalBarLayout) {
// Vertical search bar space -- The search bar is fixed in the layout to be on the left
// of the screen regardless of RTL
lp.gravity = Gravity.LEFT;
- lp.width = searchBarSpaceHeightNormalPx;
LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
targets.setOrientation(LinearLayout.VERTICAL);
@@ -428,11 +458,7 @@
} else {
// Horizontal search bar space
- lp.gravity = Gravity.TOP;
- lp.height = searchBarSpaceHeightPx;
-
- LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
- targets.getLayoutParams().width = searchBarSpaceWidthPx;
+ lp.gravity = Gravity.TOP|Gravity.CENTER_HORIZONTAL;
}
searchBar.setLayoutParams(lp);
@@ -459,7 +485,7 @@
// Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
// screen regardless of RTL
lp.gravity = Gravity.RIGHT;
- lp.width = hotseatBarHeightNormalPx;
+ lp.width = normalHotseatBarHeightPx;
lp.height = LayoutParams.MATCH_PARENT;
hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
} else if (isTablet) {
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 30bc7ea..d7f1d86 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -42,8 +42,8 @@
NORMAL (0f, 0f, 1f, new DecelerateInterpolator()),
PRESSED (0f, 100f / 255f, 1f, CLICK_FEEDBACK_INTERPOLATOR),
- FAST_SCROLL_HIGHLIGHTED (0f, 0f, 1.1f, new DecelerateInterpolator()),
- FAST_SCROLL_UNHIGHLIGHTED (0.8f, 0.35f, 1f, new DecelerateInterpolator()),
+ FAST_SCROLL_HIGHLIGHTED (0f, 0f, 1.15f, new DecelerateInterpolator()),
+ FAST_SCROLL_UNHIGHLIGHTED (0f, 0f, 1f, new DecelerateInterpolator()),
DISABLED (1f, 0.5f, 1f, new DecelerateInterpolator());
public final float desaturation;
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index 6872d5b..44403e2 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -142,7 +142,8 @@
newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex + 1);
if (newParent != null) {
pagedView.snapToPage(pageIndex + 1);
- child = FocusLogic.getAdjacentChildInNextPage(newParent, v, newIconIndex);
+ child = FocusLogic.getAdjacentChildInNextFolderPage(
+ newParent, v, newIconIndex);
}
break;
case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
@@ -173,7 +174,7 @@
}
/**
- * Handles key events in the workspace hot seat (bottom of the screen).
+ * Handles key events in the workspace hotseat (bottom of the screen).
* <p>Currently we don't special case for the phone UI in different orientations, even though
* the hotseat is on the side in landscape mode. This is to ensure that accessibility
* consistency is maintained across rotations.
@@ -262,12 +263,38 @@
countY, matrix, iconIndex, pageIndex, pageCount, Utilities.isRtl(v.getResources()));
View newIcon = null;
- if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) {
- parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
- newIcon = parent.getChildAt(0);
- // TODO(hyunyoungs): handle cases where the child is not an icon but
- // a folder or a widget.
- workspace.snapToPage(pageIndex + 1);
+ switch (newIconIndex) {
+ case FocusLogic.NEXT_PAGE_FIRST_ITEM:
+ parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
+ newIcon = parent.getChildAt(0);
+ // TODO(hyunyoungs): handle cases where the child is not an icon but
+ // a folder or a widget.
+ workspace.snapToPage(pageIndex + 1);
+ break;
+ case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
+ parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
+ newIcon = parent.getChildAt(0);
+ // TODO(hyunyoungs): handle cases where the child is not an icon but
+ // a folder or a widget.
+ workspace.snapToPage(pageIndex - 1);
+ break;
+ case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
+ parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
+ newIcon = parent.getChildAt(parent.getChildCount() - 1);
+ // TODO(hyunyoungs): handle cases where the child is not an icon but
+ // a folder or a widget.
+ workspace.snapToPage(pageIndex - 1);
+ break;
+ case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
+ case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
+ // Go to the previous page but keep the focus on the same hotseat icon.
+ workspace.snapToPage(pageIndex - 1);
+ break;
+ case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
+ case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
+ // Go to the next page but keep the focus on the same hotseat icon.
+ workspace.snapToPage(pageIndex + 1);
+ break;
}
if (parent == iconParent && newIconIndex >= iconParent.getChildCount()) {
newIconIndex -= iconParent.getChildCount();
@@ -364,12 +391,10 @@
}
int row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
- workspace.snapToPage(newPageIndex);
if (parent != null) {
- workspace.snapToPage(newPageIndex);
iconLayout = (CellLayout) parent.getParent();
matrix = FocusLogic.createSparseMatrix(iconLayout,
- iconLayout.getCountX(), row);
+ iconLayout.getCountX(), row);
newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY,
matrix, FocusLogic.PIVOT, newPageIndex, pageCount,
Utilities.isRtl(v.getResources()));
@@ -379,17 +404,14 @@
case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
newIcon = parent.getChildAt(0);
- workspace.snapToPage(pageIndex - 1);
break;
case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
newIcon = parent.getChildAt(parent.getChildCount() - 1);
- workspace.snapToPage(pageIndex - 1);
break;
case FocusLogic.NEXT_PAGE_FIRST_ITEM:
parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
newIcon = parent.getChildAt(0);
- workspace.snapToPage(pageIndex + 1);
break;
case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
@@ -397,11 +419,9 @@
if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) {
newPageIndex = pageIndex - 1;
}
- workspace.snapToPage(newPageIndex);
row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
if (parent != null) {
- workspace.snapToPage(newPageIndex);
iconLayout = (CellLayout) parent.getParent();
matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row);
newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY,
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 9377bad..8c831b9 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -318,9 +318,10 @@
sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
String.format(getContext().getString(R.string.folder_renamed), newTitle));
}
- // In order to clear the focus from the text field, we set the focus on ourself. This
- // ensures that every time the field is clicked, focus is gained, giving reliable behavior.
- requestFocus();
+
+ // This ensures that focus is gained every time the field is clicked, which selects all
+ // the text and brings up the soft keyboard if necessary.
+ mFolderName.clearFocus();
Selection.setSelection((Spannable) mFolderName.getText(), 0, 0);
mIsEditingName = false;
@@ -640,7 +641,7 @@
@Override
public void onAnimationEnd(Animator animation) {
setLayerType(LAYER_TYPE_NONE, null);
- close();
+ close(true);
}
@Override
public void onAnimationStart(Animator animation) {
@@ -654,7 +655,7 @@
oa.start();
}
- public void close() {
+ public void close(boolean wasAnimated) {
// TODO: Clear all active animations.
DragLayer parent = (DragLayer) getParent();
if (parent != null) {
@@ -662,7 +663,9 @@
}
mDragController.removeDropTarget(this);
clearFocus();
- mFolderIcon.requestFocus();
+ if (wasAnimated) {
+ mFolderIcon.requestFocus();
+ }
if (mRearrangeOnClose) {
rearrangeChildren();
@@ -1144,10 +1147,10 @@
// addInScreenFromBind() to ensure that hotseat items are placed correctly.
mLauncher.getWorkspace().addInScreenFromBind(newIcon, mInfo.container,
mInfo.screenId, mInfo.cellX, mInfo.cellY, mInfo.spanX, mInfo.spanY);
- }
- // Focus the newly created child
- newIcon.requestFocus();
+ // Focus the newly created child
+ newIcon.requestFocus();
+ }
}
}
};
@@ -1164,15 +1167,37 @@
return mDestroyed;
}
- // This method keeps track of the last item in the folder for the purposes
+ // This method keeps track of the first and last item in the folder for the purposes
// of keyboard focus
public void updateTextViewFocus() {
- View lastChild = mContent.getLastItem();
- if (lastChild != null) {
+ final View firstChild = mContent.getFirstItem();
+ final View lastChild = mContent.getLastItem();
+ if (firstChild != null && lastChild != null) {
mFolderName.setNextFocusDownId(lastChild.getId());
mFolderName.setNextFocusRightId(lastChild.getId());
mFolderName.setNextFocusLeftId(lastChild.getId());
mFolderName.setNextFocusUpId(lastChild.getId());
+ // Hitting TAB from the folder name wraps around to the first item on the current
+ // folder page, and hitting SHIFT+TAB from that item wraps back to the folder name.
+ mFolderName.setNextFocusForwardId(firstChild.getId());
+ // When clicking off the folder when editing the name, this Folder gains focus. When
+ // pressing an arrow key from that state, give the focus to the first item.
+ this.setNextFocusDownId(firstChild.getId());
+ this.setNextFocusRightId(firstChild.getId());
+ this.setNextFocusLeftId(firstChild.getId());
+ this.setNextFocusUpId(firstChild.getId());
+ // When pressing shift+tab in the above state, give the focus to the last item.
+ setOnKeyListener(new OnKeyListener() {
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ boolean isShiftPlusTab = keyCode == KeyEvent.KEYCODE_TAB &&
+ event.hasModifiers(KeyEvent.META_SHIFT_ON);
+ if (isShiftPlusTab && Folder.this.isFocused()) {
+ return lastChild.requestFocus();
+ }
+ return false;
+ }
+ });
}
}
@@ -1293,7 +1318,11 @@
rearrangeChildren();
}
if (getItemCount() <= 1) {
- replaceFolderWithFinalItem();
+ if (mInfo.opened) {
+ mLauncher.closeFolder(this, true);
+ } else {
+ replaceFolderWithFinalItem();
+ }
}
}
@@ -1337,6 +1366,8 @@
public void onFocusChange(View v, boolean hasFocus) {
if (v == mFolderName && hasFocus) {
startEditingFolderName();
+ } else if (v == mFolderName && !hasFocus) {
+ dismissEditingName();
}
}
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index cc9c573..d503d2c 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -402,16 +402,28 @@
return !ALLOW_FOLDER_SCROLL && getItemCount() >= mMaxItemsPerPage;
}
+ public View getFirstItem() {
+ if (getChildCount() < 1) {
+ return null;
+ }
+ ShortcutAndWidgetContainer currContainer = getCurrentCellLayout().getShortcutsAndWidgets();
+ if (mGridCountX > 0) {
+ return currContainer.getChildAt(0, 0);
+ } else {
+ return currContainer.getChildAt(0);
+ }
+ }
+
public View getLastItem() {
if (getChildCount() < 1) {
return null;
}
- ShortcutAndWidgetContainer lastContainer = getCurrentCellLayout().getShortcutsAndWidgets();
- int lastRank = lastContainer.getChildCount() - 1;
+ ShortcutAndWidgetContainer currContainer = getCurrentCellLayout().getShortcutsAndWidgets();
+ int lastRank = currContainer.getChildCount() - 1;
if (mGridCountX > 0) {
- return lastContainer.getChildAt(lastRank % mGridCountX, lastRank / mGridCountX);
+ return currContainer.getChildAt(lastRank % mGridCountX, lastRank / mGridCountX);
} else {
- return lastContainer.getChildAt(lastRank);
+ return currContainer.getChildAt(lastRank);
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d3934e6..97a4eed 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -52,6 +52,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
@@ -3203,7 +3204,7 @@
if (animate) {
folder.animateClosed();
} else {
- folder.close();
+ folder.close(false);
}
// Notify the accessibility manager that this folder "window" has disappeared and no
@@ -3607,17 +3608,17 @@
DeviceProfile portraitProfile = app.getInvariantDeviceProfile().portraitProfile;
DeviceProfile landscapeProfile = app.getInvariantDeviceProfile().landscapeProfile;
float density = getResources().getDisplayMetrics().density;
- Rect searchBounds = portraitProfile.getSearchBarBounds(Utilities.isRtl(getResources()));
- int maxHeight = (int) (searchBounds.height() / density);
+ Point searchDimens = portraitProfile.getSearchBarDimensForWidgetOpts(getResources());
+ int maxHeight = (int) (searchDimens.y / density);
int minHeight = maxHeight;
- int maxWidth = (int) (searchBounds.width() / density);
+ int maxWidth = (int) (searchDimens.x / density);
int minWidth = maxWidth;
if (!landscapeProfile.isVerticalBarLayout()) {
- searchBounds = landscapeProfile.getSearchBarBounds(Utilities.isRtl(getResources()));
- maxHeight = (int) Math.max(maxHeight, searchBounds.height() / density);
- minHeight = (int) Math.min(minHeight, searchBounds.height() / density);
- maxWidth = (int) Math.max(maxWidth, searchBounds.width() / density);
- minWidth = (int) Math.min(minWidth, searchBounds.width() / density);
+ searchDimens = landscapeProfile.getSearchBarDimensForWidgetOpts(getResources());
+ maxHeight = (int) Math.max(maxHeight, searchDimens.y / density);
+ minHeight = (int) Math.min(minHeight, searchDimens.y / density);
+ maxWidth = (int) Math.max(maxWidth, searchDimens.x / density);
+ minWidth = (int) Math.min(minWidth, searchDimens.x / density);
}
opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight);
opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, minHeight);
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 28c5eac..b07ccc3 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -20,6 +20,7 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+import android.os.DeadObjectException;
import android.os.TransactionTooLargeException;
import android.view.LayoutInflater;
import android.view.View;
@@ -69,7 +70,8 @@
try {
super.startListening();
} catch (Exception e) {
- if (e.getCause() instanceof TransactionTooLargeException) {
+ if (e.getCause() instanceof TransactionTooLargeException ||
+ e.getCause() instanceof DeadObjectException) {
// We're willing to let this slide. The exception is being caused by the list of
// RemoteViews which is being passed back. The startListening relationship will
// have been established by this point, and we will end up populating the
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 2579ea3..9258360 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -2078,11 +2078,6 @@
whichPage = validateNewPage(whichPage);
mNextPage = whichPage;
- View focusedChild = getFocusedChild();
- if (focusedChild != null && whichPage != mCurrentPage &&
- focusedChild == getPageAt(mCurrentPage)) {
- focusedChild.clearFocus();
- }
pageBeginMoving();
awakenScrollBars(duration);
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 157b48a..56282fe 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -23,7 +23,6 @@
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
public class ShortcutAndWidgetContainer extends ViewGroup {
static final String TAG = "CellLayoutChildren";
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index 1045342..73de45e 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -27,7 +27,7 @@
public class AllAppsFastScrollHelper implements AllAppsGridAdapter.BindViewCallback {
- private static final int INITIAL_TOUCH_SETTLING_DURATION = 300;
+ private static final int INITIAL_TOUCH_SETTLING_DURATION = 100;
private static final int REPEAT_TOUCH_SETTLING_DURATION = 200;
private static final float FAST_SCROLL_TOUCH_VELOCITY_BARRIER = 1900f;
@@ -219,7 +219,9 @@
FastBitmapDrawable.State newState = FastBitmapDrawable.State.NORMAL;
if (mCurrentFastScrollSection != null && pos > -1) {
AlphabeticalAppsList.AdapterItem item = mApps.getAdapterItems().get(pos);
- newState = item.sectionName.equals(mCurrentFastScrollSection) ?
+ boolean highlight = item.sectionName.equals(mCurrentFastScrollSection) &&
+ item.position == mTargetFastScrollPosition;
+ newState = highlight ?
FastBitmapDrawable.State.FAST_SCROLL_HIGHLIGHTED :
FastBitmapDrawable.State.FAST_SCROLL_UNHIGHLIGHTED;
}
diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java
index 7f0da77..2aae3c0 100644
--- a/src/com/android/launcher3/util/FocusLogic.java
+++ b/src/com/android/launcher3/util/FocusLogic.java
@@ -346,6 +346,18 @@
}
}
}
+
+ // Rule 3: if switching between pages, do a brute-force search to find an item that was
+ // missed by rules 1 and 2 (such as when going from a bottom right icon to top left)
+ if (iconIdx == PIVOT) {
+ for (int x = xPos + increment; 0 <= x && x < cntX; x = x + increment) {
+ for (int y = 0; y < cntY; y++) {
+ if ((newIconIndex = inspectMatrix(x, y, cntX, cntY, matrix)) != NOOP) {
+ return newIconIndex;
+ }
+ }
+ }
+ }
return newIconIndex;
}
@@ -494,9 +506,9 @@
/**
* @param edgeColumn the column of the new icon. either {@link #NEXT_PAGE_LEFT_COLUMN} or
* {@link #NEXT_PAGE_RIGHT_COLUMN}
- * @return the view adjacent to {@param oldView} in the {@param nextPage}.
+ * @return the view adjacent to {@param oldView} in the {@param nextPage} of the folder.
*/
- public static View getAdjacentChildInNextPage(
+ public static View getAdjacentChildInNextFolderPage(
ShortcutAndWidgetContainer nextPage, View oldView, int edgeColumn) {
final int newRow = ((CellLayout.LayoutParams) oldView.getLayoutParams()).cellY;
diff --git a/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java b/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
index a99ae4f..db3f72f 100644
--- a/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
+++ b/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
@@ -15,15 +15,14 @@
*/
package com.android.launcher3;
+import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.util.FocusLogic;
-
import java.util.ArrayList;
/**
@@ -123,4 +122,72 @@
// Add more tests for other devices, however, running them once on a single device is enough
// for verifying that for a platform version, the WindowManager and DisplayMetrics is
// working as intended.
+
+ /**
+ * Make sure that the height for the QSB is what we expect in normal mode.
+ */
+ public void testQsbNormalHeight() {
+ Resources resources = getContext().getResources();
+ DeviceProfile landscapeProfile = mInvariantProfile.landscapeProfile;
+ DeviceProfile portraitProfile = mInvariantProfile.portraitProfile;
+ landscapeProfile.setSearchBarHeight(LauncherCallbacks.SEARCH_BAR_HEIGHT_NORMAL);
+ portraitProfile.setSearchBarHeight(LauncherCallbacks.SEARCH_BAR_HEIGHT_NORMAL);
+ Rect portraitBounds = portraitProfile.getSearchBarBounds(true); // RTL shouldn't matter.
+ int portraitHeight = (int) Utilities.dpiFromPx(portraitBounds.height(),
+ resources.getDisplayMetrics());
+ Rect landscapeBounds = landscapeProfile.getSearchBarBounds(true); // RTL shouldn't matter.
+ int landscapeHeight = (int) Utilities.dpiFromPx(landscapeBounds.height(),
+ resources.getDisplayMetrics());
+ if (portraitProfile.isTablet) {
+ assertEquals(8 + 48 + 24, portraitHeight);
+ } else {
+ assertEquals(8 + 48 + 12, portraitHeight);
+ }
+ // Make sure the height that we pass in the widget options bundle is the height of the
+ // search bar + 8dps padding top and bottom.
+ Point portraitDimens = portraitProfile.getSearchBarDimensForWidgetOpts(resources);
+ int portraitWidgetOptsHeight = portraitDimens.y;
+ Point landscapeDimens = landscapeProfile.getSearchBarDimensForWidgetOpts(resources);
+ int landscapeWidgetOptsHeight = landscapeDimens.y;
+ assertEquals(8 + 48 + 8, (int) Utilities.dpiFromPx(portraitWidgetOptsHeight,
+ resources.getDisplayMetrics()));
+ if (!landscapeProfile.isVerticalBarLayout()) {
+ assertEquals(portraitHeight, landscapeHeight);
+ assertEquals(portraitWidgetOptsHeight, landscapeWidgetOptsHeight);
+ }
+ }
+
+ /**
+ * Make sure that the height for the QSB is what we expect in tall mode.
+ */
+ public void testQsbTallHeight() {
+ Resources resources = getContext().getResources();
+ DeviceProfile landscapeProfile = mInvariantProfile.landscapeProfile;
+ DeviceProfile portraitProfile = mInvariantProfile.portraitProfile;
+ landscapeProfile.setSearchBarHeight(LauncherCallbacks.SEARCH_BAR_HEIGHT_TALL);
+ portraitProfile.setSearchBarHeight(LauncherCallbacks.SEARCH_BAR_HEIGHT_TALL);
+ Rect portraitBounds = portraitProfile.getSearchBarBounds(true); // RTL shouldn't matter.
+ int portraitHeight = (int) Utilities.dpiFromPx(portraitBounds.height(),
+ resources.getDisplayMetrics());
+ Rect landscapeBounds = landscapeProfile.getSearchBarBounds(true); // RTL shouldn't matter.
+ int landscapeHeight = (int) Utilities.dpiFromPx(landscapeBounds.height(),
+ resources.getDisplayMetrics());
+ if (portraitProfile.isTablet) {
+ assertEquals(8 + 80 + 24, portraitHeight);
+ } else {
+ assertEquals(8 + 80 + 2, portraitHeight);
+ }
+ // Make sure the height that we pass in the widget options bundle is the height of the
+ // search bar + 8dps padding top and bottom.
+ Point portraitDimens = portraitProfile.getSearchBarDimensForWidgetOpts(resources);
+ int portraitWidgetOptsHeight = portraitDimens.y;
+ Point landscapeDimens = landscapeProfile.getSearchBarDimensForWidgetOpts(resources);
+ int landscapeWidgetOptsHeight = landscapeDimens.y;
+ assertEquals(8 + 80 + 8, (int) Utilities.dpiFromPx(portraitWidgetOptsHeight,
+ resources.getDisplayMetrics()));
+ if (!landscapeProfile.isVerticalBarLayout()) {
+ assertEquals(portraitHeight, landscapeHeight);
+ assertEquals(portraitWidgetOptsHeight, landscapeWidgetOptsHeight);
+ }
+ }
}
diff --git a/tests/src/com/android/launcher3/util/FocusLogicTest.java b/tests/src/com/android/launcher3/util/FocusLogicTest.java
index ea87014..2c2f0d3 100644
--- a/tests/src/com/android/launcher3/util/FocusLogicTest.java
+++ b/tests/src/com/android/launcher3/util/FocusLogicTest.java
@@ -57,4 +57,39 @@
// may get created in real world to test this method. OR 2) Move all the matrix
// management routine to celllayout and write tests for them.
}
+
+ public void testMoveFromBottomRightToBottomLeft() {
+ int[][] map = transpose(new int[][] {
+ {-1, 0, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1},
+ {100, 1, -1, -1, -1, -1},
+ });
+ int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, 6, 5, map, 100, 1, 2, false);
+ assertEquals(1, i);
+ }
+
+ public void testMoveFromBottomRightToTopLeft() {
+ int[][] map = transpose(new int[][] {
+ {-1, 0, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, -1},
+ {100, -1, -1, -1, -1, -1},
+ });
+ int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, 6, 5, map, 100, 1, 2, false);
+ assertEquals(0, i);
+ }
+
+ /** Transposes the matrix so that we can write it in human-readable format in the tests. */
+ private int[][] transpose(int[][] m) {
+ int[][] t = new int[m[0].length][m.length];
+ for (int i = 0; i < m.length; i++) {
+ for (int j = 0; j < m[0].length; j++) {
+ t[j][i] = m[i][j];
+ }
+ }
+ return t;
+ }
}