import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.text.Selection;
+import android.text.Spannable;
+import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.method.TextKeyListener;
import android.util.AttributeSet;
-import android.view.Gravity;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
import com.android.launcher3.AppInfo;
import com.android.launcher3.BaseContainerView;
-import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeleteDropTarget;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.folder.Folder;
+import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.keyboard.FocusedItemDecorator;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.ComponentKey;
import java.nio.charset.Charset;
AlphabeticalAppsList.SectionInfo withSection,
int sectionAppCount, int numAppsPerRow, int mergeCount) {
// Don't merge the predicted apps
- if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+ if (section.firstAppItem.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
return false;
}
// Otherwise, merge every other section
AlphabeticalAppsList.SectionInfo withSection,
int sectionAppCount, int numAppsPerRow, int mergeCount) {
// Don't merge the predicted apps
- if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+ if (section.firstAppItem.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
return false;
}
private View mSearchContainer;
private ExtendedEditText mSearchInput;
- private ImageView mSearchIcon;
private HeaderElevationController mElevationController;
+ private int mSearchContainerOffsetTop;
private SpannableStringBuilder mSearchQueryBuilder = null;
private int mSectionNamesMargin;
private int mNumAppsPerRow;
private int mNumPredictedAppsPerRow;
- private int mRecyclerViewTopBottomPadding;
+ private int mRecyclerViewBottomPadding;
// This coordinate is relative to this container view
private final Point mBoundsCheckLastTouchDownPos = new Point(-1, -1);
mItemDecoration = mAdapter.getItemDecoration();
DeviceProfile grid = mLauncher.getDeviceProfile();
if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && !grid.isVerticalBarLayout()) {
- mRecyclerViewTopBottomPadding = 0;
+ mRecyclerViewBottomPadding = 0;
setPadding(0, 0, 0, 0);
} else {
- mRecyclerViewTopBottomPadding =
- res.getDimensionPixelSize(R.dimen.all_apps_list_top_bottom_padding);
+ mRecyclerViewBottomPadding =
+ res.getDimensionPixelSize(R.dimen.all_apps_list_bottom_padding);
}
mSearchQueryBuilder = new SpannableStringBuilder();
Selection.setSelection(mSearchQueryBuilder, 0);
*/
public void addApps(List<AppInfo> apps) {
mApps.addApps(apps);
+ mSearchBarController.refreshSearchResult();
}
/**
*/
public void updateApps(List<AppInfo> apps) {
mApps.updateApps(apps);
+ mSearchBarController.refreshSearchResult();
}
/**
*/
public void removeApps(List<AppInfo> apps) {
mApps.removeApps(apps);
+ mSearchBarController.refreshSearchResult();
}
public void setSearchBarVisible(boolean visible) {
/**
* Returns whether the view itself will handle the touch event or not.
*/
- public boolean shouldContainerScroll(float x, float y) {
+ public boolean shouldContainerScroll(MotionEvent ev) {
int[] point = new int[2];
- point[0] = (int) x;
- point[1] = (int) y;
+ point[0] = (int) ev.getX();
+ point[1] = (int) ev.getY();
Utilities.mapCoordInSelfToDescendent(mAppsRecyclerView, this, point);
- // if the MotionEvent is inside the thumb, container should not be pulled down.
+ // IF the MotionEvent is inside the search box, and the container keeps on receiving
+ // touch input, container should move down.
+ if (mLauncher.getDragLayer().isEventOverView(mSearchContainer, ev)) {
+ return true;
+ }
+
+ // IF the MotionEvent is inside the thumb, container should not be pulled down.
if (mAppsRecyclerView.getScrollBar().isNearThumb(point[0], point[1])) {
return false;
}
- // If scroller is at the very top, then it's okay for the container to be pulled down.
- if (Float.compare(0f, mAppsRecyclerView.getScrollBar().getThumbOffset().y) == 0) {
+
+ // IF a shortcuts container is open, container should not be pulled down.
+ if (mLauncher.getOpenShortcutsContainer() != null) {
+ return false;
+ }
+
+ // IF scroller is at the very top OR there is no scroll bar because there is probably not
+ // enough items to scroll, THEN it's okay for the container to be pulled down.
+ if (mAppsRecyclerView.getScrollBar().getThumbOffset().y <= 0) {
return true;
}
return false;
*/
public void reset() {
// Reset the search bar and base recycler view after transitioning home
+ scrollToTop();
mSearchBarController.reset();
mAppsRecyclerView.reset();
}
mSearchContainer = findViewById(R.id.search_container);
mSearchInput = (ExtendedEditText) findViewById(R.id.search_box_input);
- mSearchIcon = (ImageView) findViewById(R.id.search_icon);
- final LinearLayout.LayoutParams searchParams =
- (LinearLayout.LayoutParams) mSearchInput.getLayoutParams();
- mSearchInput.setOnFocusChangeListener(new OnFocusChangeListener() {
- @Override
- public void onFocusChange(View view, boolean focused) {
- if (focused) {
- searchParams.width = LayoutParams.MATCH_PARENT;
- mSearchInput.setLayoutParams(searchParams);
- mSearchInput.setGravity(Gravity.FILL_HORIZONTAL | Gravity.CENTER_VERTICAL);
- mSearchIcon.setVisibility(View.GONE);
- } else {
- searchParams.width = LayoutParams.WRAP_CONTENT;
- mSearchInput.setLayoutParams(searchParams);
- mSearchInput.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
- mSearchIcon.setVisibility(View.VISIBLE);
- }
- }
- });
+ // Update the hint to contain the icon.
+ // Prefix the original hint with two spaces. The first space gets replaced by the icon
+ // using span. The second space is used for a singe space character between the hint
+ // and the icon.
+ SpannableString spanned = new SpannableString(" " + mSearchInput.getHint());
+ spanned.setSpan(new TintedDrawableSpan(getContext(), R.drawable.ic_allapps_search),
+ 0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+ mSearchInput.setHint(spanned);
- final OnClickListener searchFocusListener = new OnClickListener() {
- @Override
- public void onClick(View view) {
- if (!mSearchBarController.isSearchFieldFocused()) {
- mSearchBarController.focusSearchField();
- }
- }
- };
- mSearchInput.setOnClickListener(searchFocusListener);
- mSearchContainer.setOnClickListener(searchFocusListener);
+ mSearchContainerOffsetTop = getResources().getDimensionPixelSize(
+ R.dimen.all_apps_search_bar_margin_top);
mElevationController = Utilities.ATLEAST_LOLLIPOP
? new HeaderElevationController.ControllerVL(mSearchContainer)
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mAppsRecyclerView);
mAppsRecyclerView.addItemDecoration(focusedItemDecorator);
+ mAppsRecyclerView.preMeasureViews(mAdapter);
mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
- // Precalculate the prediction icon and normal icon sizes
- LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- getResources().getDisplayMetrics().widthPixels, MeasureSpec.AT_MOST);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- getResources().getDisplayMetrics().heightPixels, MeasureSpec.AT_MOST);
-
- BubbleTextView icon = (BubbleTextView) layoutInflater.inflate(
- R.layout.all_apps_icon, this, false);
- icon.applyDummyInfo();
- icon.measure(widthMeasureSpec, heightMeasureSpec);
- BubbleTextView predIcon = (BubbleTextView) layoutInflater.inflate(
- R.layout.all_apps_prediction_bar_icon, this, false);
- predIcon.applyDummyInfo();
- predIcon.measure(widthMeasureSpec, heightMeasureSpec);
- mAppsRecyclerView.setPremeasuredIconHeights(predIcon.getMeasuredHeight(),
- icon.getMeasuredHeight());
-
- // TODO(hyunyoungs): clean up setting the content and the reveal view.
if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
- getContentView().setBackground(null);
getRevealView().setVisibility(View.VISIBLE);
- getRevealView().setAlpha(AllAppsTransitionController.ALL_APPS_FINAL_ALPHA);
+ getContentView().setVisibility(View.VISIBLE);
+ getContentView().setBackground(null);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- updatePaddingsAndMargins();
- mContentBounds.set(mHorizontalPadding, 0,
- MeasureSpec.getSize(widthMeasureSpec) - mHorizontalPadding,
- MeasureSpec.getSize(heightMeasureSpec));
+ int widthPx = MeasureSpec.getSize(widthMeasureSpec);
+ int heightPx = MeasureSpec.getSize(heightMeasureSpec);
+ updatePaddingsAndMargins(widthPx, heightPx);
+ mContentBounds.set(mContainerPaddingLeft, 0, widthPx - mContainerPaddingRight, heightPx);
DeviceProfile grid = mLauncher.getDeviceProfile();
- int availableWidth = (!mContentBounds.isEmpty() ? mContentBounds.width() :
- MeasureSpec.getSize(widthMeasureSpec))
- - 2 * mAppsRecyclerView.getMaxScrollbarWidth();
- grid.updateAppsViewNumCols(getResources(), availableWidth);
+ grid.updateAppsViewNumCols();
if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
if (mNumAppsPerRow != grid.inv.numColumns ||
mNumPredictedAppsPerRow != grid.inv.numColumns) {
mAdapter.setNumAppsPerRow(mNumAppsPerRow);
mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, new FullMergeAlgorithm());
if (mNumAppsPerRow > 0) {
- int iconSize = availableWidth / mNumAppsPerRow;
- int iconSpacing = (iconSize - grid.allAppsIconSizePx) / 2;
+ int rvPadding = mAppsRecyclerView.getPaddingStart(); // Assumes symmetry
final int thumbMaxWidth =
getResources().getDimensionPixelSize(
R.dimen.container_fastscroll_thumb_max_width);
- mSearchContainer.setPaddingRelative(
- iconSpacing + thumbMaxWidth, 0, iconSpacing + thumbMaxWidth, 0);
+ mSearchContainer.setPadding(
+ rvPadding - mContainerPaddingLeft + thumbMaxWidth,
+ mSearchContainer.getPaddingTop(),
+ rvPadding - mContainerPaddingRight + thumbMaxWidth,
+ mSearchContainer.getPaddingBottom());
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Update the number of items in the grid before we measure the view
// TODO: mSectionNamesMargin is currently 0, but also account for it,
// if it's enabled in the future.
- grid.updateAppsViewNumCols(getResources(), availableWidth);
+ grid.updateAppsViewNumCols();
if (mNumAppsPerRow != grid.allAppsNumCols ||
mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) {
mNumAppsPerRow = grid.allAppsNumCols;
mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
mAdapter.setNumAppsPerRow(mNumAppsPerRow);
mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, mergeAlgorithm);
-
- // TODO: should we not do all this complicated computation but just match the
- // numAppsPerRow with the workspace?
- if (mNumAppsPerRow > 0) {
- int iconSize = availableWidth / mNumAppsPerRow;
- int iconSpacing = (iconSize - grid.allAppsIconSizePx) / 2;
- mSearchInput.setPaddingRelative(iconSpacing, 0, iconSpacing, 0);
- }
}
// --- remove END when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. ---
* container view, we inset the background and padding of the recycler view to allow for the
* recycler view to handle touch events (for fast scrolling) all the way to the edge.
*/
- private void updatePaddingsAndMargins() {
+ private void updatePaddingsAndMargins(int widthPx, int heightPx) {
Rect bgPadding = new Rect();
getRevealView().getBackground().getPadding(bgPadding);
// names)
int maxScrollBarWidth = mAppsRecyclerView.getMaxScrollbarWidth();
int startInset = Math.max(mSectionNamesMargin, maxScrollBarWidth);
- int topBottomPadding = mRecyclerViewTopBottomPadding;
if (Utilities.isRtl(getResources())) {
- mAppsRecyclerView.setPadding(bgPadding.left + maxScrollBarWidth,
- topBottomPadding, bgPadding.right + startInset, topBottomPadding);
+ mAppsRecyclerView.setPadding(bgPadding.left + maxScrollBarWidth, 0, bgPadding.right
+ + startInset, mRecyclerViewBottomPadding);
} else {
- mAppsRecyclerView.setPadding(bgPadding.left + startInset, topBottomPadding,
- bgPadding.right + maxScrollBarWidth, topBottomPadding);
+ mAppsRecyclerView.setPadding(bgPadding.left + startInset, 0, bgPadding.right +
+ maxScrollBarWidth, mRecyclerViewBottomPadding);
}
MarginLayoutParams lp = (MarginLayoutParams) mSearchContainer.getLayoutParams();
// Clip the view to the left and right edge of the background to
// to prevent shadows from rendering beyond the edges
final Rect newClipBounds = new Rect(
- bgPadding.left,
- 0,
- getWidth() - bgPadding.right,
- getHeight()
- );
+ bgPadding.left, 0, widthPx - bgPadding.right, heightPx);
setClipBounds(newClipBounds);
// Allow the overscroll effect to reach the edges of the view
MarginLayoutParams mlp = (MarginLayoutParams) mAppsRecyclerView.getLayoutParams();
Rect insets = mLauncher.getDragLayer().getInsets();
- getContentView().setPadding(0, 0, 0, insets.bottom);
+ getContentView().setPadding(0, 0, 0, 0);
int height = insets.top + grid.hotseatCellHeightPx;
mlp.topMargin = height;
mAppsRecyclerView.setLayoutParams(mlp);
- LinearLayout.LayoutParams llp =
- (LinearLayout.LayoutParams) mSearchInput.getLayoutParams();
- llp.topMargin = insets.top;
- mSearchInput.setLayoutParams(llp);
- mSearchIcon.setLayoutParams(llp);
-
+ mSearchContainer.setPadding(
+ mSearchContainer.getPaddingLeft(),
+ insets.top + mSearchContainerOffsetTop,
+ mSearchContainer.getPaddingRight(),
+ mSearchContainer.getPaddingBottom());
lp.height = height;
View navBarBg = findViewById(R.id.nav_bar_bg);
if (!mLauncher.isDraggingEnabled()) return false;
// Start the drag
- mLauncher.getWorkspace().beginDragShared(v, this, false);
+ mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions());
// Enter spring loaded mode
mLauncher.enterSpringLoadedDragMode();
mSearchQueryBuilder.clearSpans();
Selection.setSelection(mSearchQueryBuilder, 0);
}
+
+ @Override
+ public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
+ targetParent.containerType = mAppsRecyclerView.getContainerType(v);
+ }
}