Loading res/values/dimens.xml +2 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ <dimen name="list_item_thumbnail_size">40dp</dimen> <dimen name="grid_item_icon_size">30dp</dimen> <dimen name="progress_bar_height">4dp</dimen> <fraction name="grid_scale_min">85%</fraction> <fraction name="grid_scale_max">200%</fraction> <dimen name="grid_width">152dp</dimen> <dimen name="grid_height">176dp</dimen> <dimen name="grid_item_width">152dp</dimen> Loading src/com/android/documentsui/BaseActivity.java +1 −1 Original line number Diff line number Diff line Loading @@ -731,7 +731,7 @@ public abstract class BaseActivity<T extends ActionHandler> }); } public final class RetainedState { public static final class RetainedState { public @Nullable Selection selection; public boolean hasSelection() { Loading src/com/android/documentsui/queries/SetQuickViewerCommand.java→src/com/android/documentsui/base/DebugFlags.java +45 −0 Original line number Diff line number Diff line Loading @@ -13,36 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.documentsui.queries; import android.text.TextUtils; import android.util.Log; import com.android.documentsui.base.EventHandler; public class SetQuickViewerCommand implements EventHandler<String[]> { // This is a quick/easy shortcut to sharing quick viewer debug settings // with QuickViewIntent builder. Tried setting at a system property // but got a native error. This being quick and easy, didn't investigate that err. public static String sQuickViewer; private static final String TAG = "SetQuickViewerCommand"; @Override public boolean accept(String[] tokens) { if ("setqv".equals(tokens[0])) { if (tokens.length == 2 && !TextUtils.isEmpty(tokens[1])) { sQuickViewer = tokens[1]; Log.i(TAG, "Set quick viewer to: " + sQuickViewer); return true; } else { Log.w(TAG, "Invalid command structure: " + tokens); package com.android.documentsui.base; import javax.annotation.Nullable; /** * Shared values that may be set by {@link DebugCommandProcessor}. */ public final class DebugFlags { private DebugFlags() {} private static String mQvPackage; private static boolean sGestureScaleEnabled; public static void setQuickViewer(@Nullable String qvPackage) { mQvPackage = qvPackage; } } else if ("unsetqv".equals(tokens[0])) { Log.i(TAG, "Unset quick viewer"); sQuickViewer = null; return true; public static @Nullable String getQuickViewer() { return mQvPackage; } return false; public static void setGestureScaleEnabled(boolean enabled) { sGestureScaleEnabled = enabled; } public static boolean getGestureScaleEnabled() { return sGestureScaleEnabled; } } src/com/android/documentsui/dirlist/DirectoryFragment.java +61 −9 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static com.android.documentsui.base.Shared.DEBUG; import static com.android.documentsui.base.State.MODE_GRID; import static com.android.documentsui.base.State.MODE_LIST; import android.annotation.DimenRes; import android.annotation.FractionRes; import android.annotation.IntDef; import android.annotation.StringRes; import android.app.Activity; Loading @@ -36,6 +38,7 @@ import android.content.Intent; import android.content.Loader; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Parcelable; Loading Loading @@ -66,8 +69,8 @@ import com.android.documentsui.ActivityConfig; import com.android.documentsui.BaseActivity; import com.android.documentsui.BaseActivity.RetainedState; import com.android.documentsui.DirectoryLoader; import com.android.documentsui.DirectoryResult; import com.android.documentsui.DirectoryReloadLock; import com.android.documentsui.DirectoryResult; import com.android.documentsui.DocumentsApplication; import com.android.documentsui.FocusManager; import com.android.documentsui.ItemDragListener; Loading Loading @@ -183,6 +186,9 @@ public class DirectoryFragment extends Fragment private GridLayoutManager mLayout; private int mColumnCount = 1; // This will get updated when layout changes. private float mLiveScale = 1.0f; private int mMode; private MessageBar mMessageBar; private View mProgressBar; Loading @@ -204,7 +210,7 @@ public class DirectoryFragment extends Fragment public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { BaseActivity activity = (BaseActivity<?>) getActivity(); BaseActivity<?> activity = (BaseActivity<?>) getActivity(); final View view = inflater.inflate(R.layout.fragment_directory, container, false); mMessageBar = MessageBar.create(getChildFragmentManager()); Loading Loading @@ -342,6 +348,7 @@ public class DirectoryFragment extends Fragment EventHandler<InputEvent> gestureHandler = mState.allowMultiple ? gestureSel::start : EventHandler.createStub(false); mInputHandler = new UserInputHandler<>( mActions, mFocusManager, Loading @@ -359,7 +366,8 @@ public class DirectoryFragment extends Fragment mDragStartListener::onMouseDragEvent, gestureSel, mInputHandler, mBandController); mBandController, this::scaleLayout); mMenuManager = mActivity.getMenuManager(); Loading Loading @@ -497,6 +505,7 @@ public class DirectoryFragment extends Fragment * @param mode The new view mode. */ private void updateLayout(@ViewMode int mode) { mMode = mode; mColumnCount = calculateColumnCount(mode); if (mLayout != null) { mLayout.setSpanCount(mColumnCount); Loading @@ -511,22 +520,65 @@ public class DirectoryFragment extends Fragment mIconHelper.setViewMode(mode); } /** * Updates the layout after the view mode switches. * @param mode The new view mode. */ private void scaleLayout(float scale) { assert(Build.IS_DEBUGGABLE); if (DEBUG) Log.v(TAG, "Handling scale event: " + scale + ", existing scale: " + mLiveScale); if (mMode == MODE_GRID) { float minScale = getFraction(R.fraction.grid_scale_min); float maxScale = getFraction(R.fraction.grid_scale_max); float nextScale = mLiveScale * scale; if (DEBUG) Log.v(TAG, "Next scale " + nextScale + ", Min/max scale " + minScale + "/" + maxScale); if (nextScale > minScale && nextScale < maxScale) { if (DEBUG) Log.d(TAG, "Updating grid scale: " + scale); mLiveScale = nextScale; updateLayout(mMode); } } else { if (DEBUG) Log.d(TAG, "List mode, ignoring scale: " + scale); mLiveScale = 1.0f; } } private int calculateColumnCount(@ViewMode int mode) { if (mode == MODE_LIST) { // List mode is a "grid" with 1 column. return 1; } int cellWidth = getResources().getDimensionPixelSize(R.dimen.grid_width); int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin); int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight(); int cellWidth = getScaledSize(R.dimen.grid_width); int cellMargin = 2 * getScaledSize(R.dimen.grid_item_margin); int viewPadding = (int) ((mRecView.getPaddingLeft() + mRecView.getPaddingRight()) * mLiveScale); // RecyclerView sometimes gets a width of 0 (see b/27150284). Clamp so that we always lay // out the grid with at least 2 columns. // RecyclerView sometimes gets a width of 0 (see b/27150284). // Clamp so that we always lay out the grid with at least 2 columns by default. int columnCount = Math.max(2, (mRecView.getWidth() - viewPadding) / (cellWidth + cellMargin)); return columnCount; // Finally with our grid count logic firmly in place, we apply any live scaling // captured by the scale gesture detector. return Math.max(1, Math.round(columnCount / mLiveScale)); } /** * Moderately abuse the "fraction" resource type for our purposes. */ private float getFraction(@FractionRes int id) { return getResources().getFraction(id, 1, 0); } private int getScaledSize(@DimenRes int id) { return (int) (getResources().getDimensionPixelSize(id) * mLiveScale); } private int getDirectoryPadding(@ViewMode int mode) { Loading src/com/android/documentsui/dirlist/ListeningGestureDetector.java +40 −1 Original line number Diff line number Diff line Loading @@ -16,15 +16,21 @@ package com.android.documentsui.dirlist; import static com.android.documentsui.base.Shared.DEBUG; import android.annotation.Nullable; import android.content.Context; import android.os.Build; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.OnItemTouchListener; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import android.view.View.OnTouchListener; import com.android.documentsui.base.DebugFlags; import com.android.documentsui.base.EventHandler; import com.android.documentsui.base.Events; import com.android.documentsui.base.Events.InputEvent; Loading @@ -32,18 +38,25 @@ import com.android.documentsui.base.Events.MotionInputEvent; import com.android.documentsui.selection.BandController; import com.android.documentsui.selection.GestureSelector; import java.util.function.Consumer; //Receives event meant for both directory and empty view, and either pass them to //{@link UserInputHandler} for simple gestures (Single Tap, Long-Press), or intercept them for //other types of gestures (drag n' drop) final class ListeningGestureDetector extends GestureDetector implements OnItemTouchListener, OnTouchListener { private static final String TAG = "ListeningGestureDetector"; private final GestureSelector mGestureSelector; private final EventHandler<InputEvent> mMouseDragListener; private final BandController mBandController; private final MouseDelegate mMouseDelegate = new MouseDelegate(); private final TouchDelegate mTouchDelegate = new TouchDelegate(); // Currently only initialized on IS_DEBUGGABLE builds. private final @Nullable ScaleGestureDetector mScaleDetector; public ListeningGestureDetector( Context context, RecyclerView recView, Loading @@ -51,19 +64,45 @@ final class ListeningGestureDetector extends GestureDetector EventHandler<InputEvent> mouseDragListener, GestureSelector gestureSelector, UserInputHandler<? extends InputEvent> handler, @Nullable BandController bandController) { @Nullable BandController bandController, Consumer<Float> scaleHandler) { super(context, handler); mMouseDragListener = mouseDragListener; mGestureSelector = gestureSelector; mBandController = bandController; recView.addOnItemTouchListener(this); emptyView.setOnTouchListener(this); mScaleDetector = !Build.IS_DEBUGGABLE ? null : new ScaleGestureDetector( context, new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScale(ScaleGestureDetector detector) { if (DEBUG) Log.v(TAG, "Received scale event: " + detector.getScaleFactor()); scaleHandler.accept(detector.getScaleFactor()); return true; } }); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { boolean handled = false; // This is an in-development feature. // TODO: Re-wire event handling so that we're not dispatching // events to to scaledetector's #onTouchEvent from this // #onInterceptTouchEvent touch event. if (DebugFlags.getGestureScaleEnabled() && mScaleDetector != null) { mScaleDetector.onTouchEvent(e); } try (InputEvent event = MotionInputEvent.obtain(e, rv)) { if (event.isMouseEvent()) { handled |= mMouseDelegate.onInterceptTouchEvent(event); Loading Loading
res/values/dimens.xml +2 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ <dimen name="list_item_thumbnail_size">40dp</dimen> <dimen name="grid_item_icon_size">30dp</dimen> <dimen name="progress_bar_height">4dp</dimen> <fraction name="grid_scale_min">85%</fraction> <fraction name="grid_scale_max">200%</fraction> <dimen name="grid_width">152dp</dimen> <dimen name="grid_height">176dp</dimen> <dimen name="grid_item_width">152dp</dimen> Loading
src/com/android/documentsui/BaseActivity.java +1 −1 Original line number Diff line number Diff line Loading @@ -731,7 +731,7 @@ public abstract class BaseActivity<T extends ActionHandler> }); } public final class RetainedState { public static final class RetainedState { public @Nullable Selection selection; public boolean hasSelection() { Loading
src/com/android/documentsui/queries/SetQuickViewerCommand.java→src/com/android/documentsui/base/DebugFlags.java +45 −0 Original line number Diff line number Diff line Loading @@ -13,36 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.documentsui.queries; import android.text.TextUtils; import android.util.Log; import com.android.documentsui.base.EventHandler; public class SetQuickViewerCommand implements EventHandler<String[]> { // This is a quick/easy shortcut to sharing quick viewer debug settings // with QuickViewIntent builder. Tried setting at a system property // but got a native error. This being quick and easy, didn't investigate that err. public static String sQuickViewer; private static final String TAG = "SetQuickViewerCommand"; @Override public boolean accept(String[] tokens) { if ("setqv".equals(tokens[0])) { if (tokens.length == 2 && !TextUtils.isEmpty(tokens[1])) { sQuickViewer = tokens[1]; Log.i(TAG, "Set quick viewer to: " + sQuickViewer); return true; } else { Log.w(TAG, "Invalid command structure: " + tokens); package com.android.documentsui.base; import javax.annotation.Nullable; /** * Shared values that may be set by {@link DebugCommandProcessor}. */ public final class DebugFlags { private DebugFlags() {} private static String mQvPackage; private static boolean sGestureScaleEnabled; public static void setQuickViewer(@Nullable String qvPackage) { mQvPackage = qvPackage; } } else if ("unsetqv".equals(tokens[0])) { Log.i(TAG, "Unset quick viewer"); sQuickViewer = null; return true; public static @Nullable String getQuickViewer() { return mQvPackage; } return false; public static void setGestureScaleEnabled(boolean enabled) { sGestureScaleEnabled = enabled; } public static boolean getGestureScaleEnabled() { return sGestureScaleEnabled; } }
src/com/android/documentsui/dirlist/DirectoryFragment.java +61 −9 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static com.android.documentsui.base.Shared.DEBUG; import static com.android.documentsui.base.State.MODE_GRID; import static com.android.documentsui.base.State.MODE_LIST; import android.annotation.DimenRes; import android.annotation.FractionRes; import android.annotation.IntDef; import android.annotation.StringRes; import android.app.Activity; Loading @@ -36,6 +38,7 @@ import android.content.Intent; import android.content.Loader; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Parcelable; Loading Loading @@ -66,8 +69,8 @@ import com.android.documentsui.ActivityConfig; import com.android.documentsui.BaseActivity; import com.android.documentsui.BaseActivity.RetainedState; import com.android.documentsui.DirectoryLoader; import com.android.documentsui.DirectoryResult; import com.android.documentsui.DirectoryReloadLock; import com.android.documentsui.DirectoryResult; import com.android.documentsui.DocumentsApplication; import com.android.documentsui.FocusManager; import com.android.documentsui.ItemDragListener; Loading Loading @@ -183,6 +186,9 @@ public class DirectoryFragment extends Fragment private GridLayoutManager mLayout; private int mColumnCount = 1; // This will get updated when layout changes. private float mLiveScale = 1.0f; private int mMode; private MessageBar mMessageBar; private View mProgressBar; Loading @@ -204,7 +210,7 @@ public class DirectoryFragment extends Fragment public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { BaseActivity activity = (BaseActivity<?>) getActivity(); BaseActivity<?> activity = (BaseActivity<?>) getActivity(); final View view = inflater.inflate(R.layout.fragment_directory, container, false); mMessageBar = MessageBar.create(getChildFragmentManager()); Loading Loading @@ -342,6 +348,7 @@ public class DirectoryFragment extends Fragment EventHandler<InputEvent> gestureHandler = mState.allowMultiple ? gestureSel::start : EventHandler.createStub(false); mInputHandler = new UserInputHandler<>( mActions, mFocusManager, Loading @@ -359,7 +366,8 @@ public class DirectoryFragment extends Fragment mDragStartListener::onMouseDragEvent, gestureSel, mInputHandler, mBandController); mBandController, this::scaleLayout); mMenuManager = mActivity.getMenuManager(); Loading Loading @@ -497,6 +505,7 @@ public class DirectoryFragment extends Fragment * @param mode The new view mode. */ private void updateLayout(@ViewMode int mode) { mMode = mode; mColumnCount = calculateColumnCount(mode); if (mLayout != null) { mLayout.setSpanCount(mColumnCount); Loading @@ -511,22 +520,65 @@ public class DirectoryFragment extends Fragment mIconHelper.setViewMode(mode); } /** * Updates the layout after the view mode switches. * @param mode The new view mode. */ private void scaleLayout(float scale) { assert(Build.IS_DEBUGGABLE); if (DEBUG) Log.v(TAG, "Handling scale event: " + scale + ", existing scale: " + mLiveScale); if (mMode == MODE_GRID) { float minScale = getFraction(R.fraction.grid_scale_min); float maxScale = getFraction(R.fraction.grid_scale_max); float nextScale = mLiveScale * scale; if (DEBUG) Log.v(TAG, "Next scale " + nextScale + ", Min/max scale " + minScale + "/" + maxScale); if (nextScale > minScale && nextScale < maxScale) { if (DEBUG) Log.d(TAG, "Updating grid scale: " + scale); mLiveScale = nextScale; updateLayout(mMode); } } else { if (DEBUG) Log.d(TAG, "List mode, ignoring scale: " + scale); mLiveScale = 1.0f; } } private int calculateColumnCount(@ViewMode int mode) { if (mode == MODE_LIST) { // List mode is a "grid" with 1 column. return 1; } int cellWidth = getResources().getDimensionPixelSize(R.dimen.grid_width); int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin); int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight(); int cellWidth = getScaledSize(R.dimen.grid_width); int cellMargin = 2 * getScaledSize(R.dimen.grid_item_margin); int viewPadding = (int) ((mRecView.getPaddingLeft() + mRecView.getPaddingRight()) * mLiveScale); // RecyclerView sometimes gets a width of 0 (see b/27150284). Clamp so that we always lay // out the grid with at least 2 columns. // RecyclerView sometimes gets a width of 0 (see b/27150284). // Clamp so that we always lay out the grid with at least 2 columns by default. int columnCount = Math.max(2, (mRecView.getWidth() - viewPadding) / (cellWidth + cellMargin)); return columnCount; // Finally with our grid count logic firmly in place, we apply any live scaling // captured by the scale gesture detector. return Math.max(1, Math.round(columnCount / mLiveScale)); } /** * Moderately abuse the "fraction" resource type for our purposes. */ private float getFraction(@FractionRes int id) { return getResources().getFraction(id, 1, 0); } private int getScaledSize(@DimenRes int id) { return (int) (getResources().getDimensionPixelSize(id) * mLiveScale); } private int getDirectoryPadding(@ViewMode int mode) { Loading
src/com/android/documentsui/dirlist/ListeningGestureDetector.java +40 −1 Original line number Diff line number Diff line Loading @@ -16,15 +16,21 @@ package com.android.documentsui.dirlist; import static com.android.documentsui.base.Shared.DEBUG; import android.annotation.Nullable; import android.content.Context; import android.os.Build; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.OnItemTouchListener; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import android.view.View.OnTouchListener; import com.android.documentsui.base.DebugFlags; import com.android.documentsui.base.EventHandler; import com.android.documentsui.base.Events; import com.android.documentsui.base.Events.InputEvent; Loading @@ -32,18 +38,25 @@ import com.android.documentsui.base.Events.MotionInputEvent; import com.android.documentsui.selection.BandController; import com.android.documentsui.selection.GestureSelector; import java.util.function.Consumer; //Receives event meant for both directory and empty view, and either pass them to //{@link UserInputHandler} for simple gestures (Single Tap, Long-Press), or intercept them for //other types of gestures (drag n' drop) final class ListeningGestureDetector extends GestureDetector implements OnItemTouchListener, OnTouchListener { private static final String TAG = "ListeningGestureDetector"; private final GestureSelector mGestureSelector; private final EventHandler<InputEvent> mMouseDragListener; private final BandController mBandController; private final MouseDelegate mMouseDelegate = new MouseDelegate(); private final TouchDelegate mTouchDelegate = new TouchDelegate(); // Currently only initialized on IS_DEBUGGABLE builds. private final @Nullable ScaleGestureDetector mScaleDetector; public ListeningGestureDetector( Context context, RecyclerView recView, Loading @@ -51,19 +64,45 @@ final class ListeningGestureDetector extends GestureDetector EventHandler<InputEvent> mouseDragListener, GestureSelector gestureSelector, UserInputHandler<? extends InputEvent> handler, @Nullable BandController bandController) { @Nullable BandController bandController, Consumer<Float> scaleHandler) { super(context, handler); mMouseDragListener = mouseDragListener; mGestureSelector = gestureSelector; mBandController = bandController; recView.addOnItemTouchListener(this); emptyView.setOnTouchListener(this); mScaleDetector = !Build.IS_DEBUGGABLE ? null : new ScaleGestureDetector( context, new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScale(ScaleGestureDetector detector) { if (DEBUG) Log.v(TAG, "Received scale event: " + detector.getScaleFactor()); scaleHandler.accept(detector.getScaleFactor()); return true; } }); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { boolean handled = false; // This is an in-development feature. // TODO: Re-wire event handling so that we're not dispatching // events to to scaledetector's #onTouchEvent from this // #onInterceptTouchEvent touch event. if (DebugFlags.getGestureScaleEnabled() && mScaleDetector != null) { mScaleDetector.onTouchEvent(e); } try (InputEvent event = MotionInputEvent.obtain(e, rv)) { if (event.isMouseEvent()) { handled |= mMouseDelegate.onInterceptTouchEvent(event); Loading