diff options
| author | 2015-07-29 15:33:49 -0700 | |
|---|---|---|
| committer | 2015-07-30 10:59:53 -0700 | |
| commit | 6b0265eeea299c772db1e92dcecda0944838d50d (patch) | |
| tree | c14780fd4a2bb65610d72848b4944e984707428b | |
| parent | 75952bac0006f986cfee9b3fe49a2a3c2e9248c1 (diff) | |
Add BandSelectManager.
BUG:20669231
Change-Id: Iea8c3866a9de020a7bebd93a967aa42d45f8e2bd
4 files changed, 188 insertions, 0 deletions
diff --git a/packages/DocumentsUI/res/drawable/band_select_overlay.xml b/packages/DocumentsUI/res/drawable/band_select_overlay.xml new file mode 100644 index 000000000000..ba4d5261e581 --- /dev/null +++ b/packages/DocumentsUI/res/drawable/band_select_overlay.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2015 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 + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/band_select_background" /> + <stroke android:width="1dp" android:color="@color/band_select_border" /> +</shape> diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml index c6f428a336d6..0735ff9de600 100644 --- a/packages/DocumentsUI/res/values/colors.xml +++ b/packages/DocumentsUI/res/values/colors.xml @@ -27,4 +27,6 @@ <color name="item_doc_grid_protect_background">#88000000</color> <color name="status_bar_background">@color/material_blue_700</color> <color name="action_mode_status_bar_background">@color/material_grey_800</color> + <color name="band_select_background">#88ffffff</color> + <color name="band_select_border">#44000000</color> </resources> diff --git a/packages/DocumentsUI/src/com/android/documentsui/BandSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/BandSelectManager.java new file mode 100644 index 000000000000..aa63837cb006 --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/BandSelectManager.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2015 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.documentsui; + +import static com.android.internal.util.Preconditions.checkState; + +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +/** + * Provides mouse driven band-select support when used in conjuction with {@link RecyclerView} and + * {@link MultiSelectManager}. This class is responsible for rendering the band select overlay and + * selecting overlaid items via MultiSelectManager. + */ +public class BandSelectManager extends RecyclerView.SimpleOnItemTouchListener { + + // For debugging purposes. + private static final String TAG = "BandSelectManager"; + private static final boolean DEBUG = false; + + private final RecyclerView mRecyclerView; + private final MultiSelectManager mSelectManager; + private final Drawable mRegionSelectorDrawable; + + private boolean mIsBandSelectActive = false; + private Point mOrigin; + private Rect mRegionBounds; + + /** + * @param recyclerView + * @param multiSelectManager + */ + public BandSelectManager(RecyclerView recyclerView, MultiSelectManager multiSelectManager) { + mRecyclerView = recyclerView; + mSelectManager = multiSelectManager; + mRegionSelectorDrawable = + mRecyclerView.getContext().getTheme().getDrawable(R.drawable.band_select_overlay); + + mRecyclerView.addOnItemTouchListener(this); + } + + @Override + public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { + // Only intercept the event if it was triggered by a mouse. If band select is inactive, + // do not intercept ACTION_UP events as they will not be processed. + return isMouseEvent(e) && + (mIsBandSelectActive || e.getActionMasked() != MotionEvent.ACTION_UP); + } + + @Override + public void onTouchEvent(RecyclerView rv, MotionEvent e) { + checkState(isMouseEvent(e)); + processMotionEvent(e); + } + + /** + * Processes a MotionEvent by starting, ending, or resizing the band select overlay. + * @param e + */ + private void processMotionEvent(MotionEvent e) { + if (mIsBandSelectActive && e.getActionMasked() == MotionEvent.ACTION_UP) { + endBandSelect(); + return; + } + + Point point = new Point((int) e.getX(), (int) e.getY()); + if (!mIsBandSelectActive) { + startBandSelect(point); + } + + resizeBandSelectRectangle(point); + selectChildrenCoveredBySelection(); + } + + /** + * Starts band select by adding the drawable to the RecyclerView's overlay. + * @param origin The starting point of the selection. + */ + private void startBandSelect(Point origin) { + if (DEBUG) Log.d(TAG, "Starting band select from (" + origin.x + "," + origin.y + ")."); + mIsBandSelectActive = true; + mOrigin = origin; + mRecyclerView.getOverlay().add(mRegionSelectorDrawable); + } + + /** + * Resizes the band select rectangle by using the origin and the current pointer positoin as + * two opposite corners of the selection. + * @param pointerPosition + */ + private void resizeBandSelectRectangle(Point pointerPosition) { + mRegionBounds = new Rect(Math.min(mOrigin.x, pointerPosition.x), + Math.min(mOrigin.y, pointerPosition.y), + Math.max(mOrigin.x, pointerPosition.x), + Math.max(mOrigin.y, pointerPosition.y)); + mRegionSelectorDrawable.setBounds(mRegionBounds); + } + + /** + * Selects the children covered by the band select overlay by delegating to MultiSelectManager. + * TODO: Provide a finished implementation. This is down and dirty, proof of concept code. + * Final optimized implementation, with support for managing offscreen selection to come. + */ + private void selectChildrenCoveredBySelection() { + for (int i = 0; i < mRecyclerView.getChildCount(); i++) { + View child = mRecyclerView.getChildAt(i); + ViewHolder holder = mRecyclerView.getChildViewHolder(child); + Rect childRect = new Rect(); + child.getHitRect(childRect); + + boolean doRectsOverlap = Rect.intersects(childRect, mRegionBounds); + mSelectManager.setItemSelected(holder.getAdapterPosition(), doRectsOverlap); + } + } + + /** + * Ends band select by removing the overlay. + */ + private void endBandSelect() { + if (DEBUG) Log.d(TAG, "Ending band select."); + mIsBandSelectActive = false; + mRecyclerView.getOverlay().remove(mRegionSelectorDrawable); + } + + /** + * Determines whether the provided event was triggered by a mouse (as opposed to a finger or + * stylus). + * @param e + * @return + */ + private static boolean isMouseEvent(MotionEvent e) { + return e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE; + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index 4cd38711dbb6..308375e73917 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -397,6 +397,7 @@ public class DirectoryFragment extends Fragment { // Kick off loader at least once getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks); + mFragmentTuner.afterActivityCreated(this); updateDisplayState(); } @@ -1662,6 +1663,7 @@ public class DirectoryFragment extends Fragment { */ private interface FragmentTuner { void updateActionMenu(Menu menu, int dirType, boolean canDelete); + void afterActivityCreated(DirectoryFragment fragment); } /** @@ -1719,6 +1721,9 @@ public class DirectoryFragment extends Fragment { // Only shown in standalone mode. copyToClipboard.setVisible(false); } + + @Override + public void afterActivityCreated(DirectoryFragment fragment) {} } /** @@ -1735,5 +1740,10 @@ public class DirectoryFragment extends Fragment { menu.findItem(R.id.menu_copy_to).setVisible(false); menu.findItem(R.id.menu_move_to).setVisible(false); } + + @Override + public void afterActivityCreated(DirectoryFragment fragment) { + new BandSelectManager(fragment.mRecView, fragment.mSelectionManager); + } } } |