Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd96456d authored by Ben Kwa's avatar Ben Kwa
Browse files

Implement enter key support for DocumentsUI.

- Add a click handler that basically handles all cases (including the
  enter key) of Items being clicked.
- Open the focused file in non-select mode, toggle selection if in
  selection mode.
- Remove now-redundant onSingleTapUp handlers.
- Redo focus indicator, since it's now possible to toggle selection on
  the focused file.
- Don't dismiss selection on arrow-key navigation.

BUG=24705453
BUG=25114155

Change-Id: Iba74188514ecf2bc6b56573087e3c3ccc83f85d2
parent e5971fe5
Loading
Loading
Loading
Loading
+0 −4
Original line number Original line Diff line number Diff line
@@ -15,10 +15,6 @@
-->
-->


<selector xmlns:android="http://schemas.android.com/apk/res/android">
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_focused="true"
        android:color="@color/platform_blue_a200"
        android:alpha="0.1" />
    <item
    <item
        android:state_activated="true"
        android:state_activated="true"
        android:color="?android:attr/colorAccent"
        android:color="?android:attr/colorAccent"
+9 −3
Original line number Original line Diff line number Diff line
@@ -14,10 +14,16 @@
     limitations under the License.
     limitations under the License.
-->
-->


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.android.documentsui.ListItem xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/item_doc_list_background">
    android:background="@drawable/item_doc_list_background"
    android:orientation="horizontal">

    <View
        android:id="@+id/focus_indicator"
        android:layout_width="4dp"
        android:layout_height="match_parent" />


    <LinearLayout
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_width="match_parent"
@@ -121,4 +127,4 @@


    </LinearLayout>
    </LinearLayout>


</FrameLayout>
</com.android.documentsui.ListItem>
+9 −3
Original line number Original line Diff line number Diff line
@@ -14,10 +14,16 @@
     limitations under the License.
     limitations under the License.
-->
-->


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.android.documentsui.DocListItem xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/item_doc_list_background">
    android:background="@drawable/item_doc_list_background"
    android:orientation="horizontal">
  
    <View
        android:id="@+id/focus_indicator"
        android:layout_width="4dp"
        android:layout_height="match_parent" />


    <LinearLayout
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_width="match_parent"
@@ -131,4 +137,4 @@


    </LinearLayout>
    </LinearLayout>


</FrameLayout>
</com.android.documentsui.DocListItem>
+68 −9
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@ import android.support.v7.widget.RecyclerView.LayoutManager;
import android.support.v7.widget.RecyclerView.OnItemTouchListener;
import android.support.v7.widget.RecyclerView.OnItemTouchListener;
import android.support.v7.widget.RecyclerView.RecyclerListener;
import android.support.v7.widget.RecyclerView.RecyclerListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.support.v7.widget.SimpleItemAnimator;
import android.text.TextUtils;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.DateUtils;
import android.text.format.Formatter;
import android.text.format.Formatter;
@@ -79,12 +80,12 @@ import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ActionMode;
import android.view.DragEvent;
import android.view.DragEvent;
import android.view.GestureDetector;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.ImageView;
@@ -134,6 +135,7 @@ public class DirectoryFragment extends Fragment {
    private Model mModel;
    private Model mModel;
    private MultiSelectManager mSelectionManager;
    private MultiSelectManager mSelectionManager;
    private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
    private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
    private ItemClickListener mItemClickListener = new ItemClickListener();


    private View mEmptyView;
    private View mEmptyView;
    private RecyclerView mRecView;
    private RecyclerView mRecView;
@@ -238,7 +240,7 @@ public class DirectoryFragment extends Fragment {
        // TODO: Rather than update columns on layout changes, push this
        // TODO: Rather than update columns on layout changes, push this
        // code (or something like it) into GridLayoutManager.
        // code (or something like it) into GridLayoutManager.
        mRecView.addOnLayoutChangeListener(
        mRecView.addOnLayoutChangeListener(
                new OnLayoutChangeListener() {
                new View.OnLayoutChangeListener() {


                    @Override
                    @Override
                    public void onLayoutChange(
                    public void onLayoutChange(
@@ -251,6 +253,9 @@ public class DirectoryFragment extends Fragment {
                    }
                    }
                });
                });


        // TODO: Restore transition animations.  See b/24802917.
        ((SimpleItemAnimator) mRecView.getItemAnimator()).setSupportsChangeAnimations(false);

        // TODO: Add a divider between views (which might use RecyclerView.ItemDecoration).
        // TODO: Add a divider between views (which might use RecyclerView.ItemDecoration).
        if (DEBUG_ENABLE_DND) {
        if (DEBUG_ENABLE_DND) {
            setupDragAndDropOnDirectoryView(mRecView);
            setupDragAndDropOnDirectoryView(mRecView);
@@ -450,7 +455,10 @@ public class DirectoryFragment extends Fragment {
    }
    }


    private boolean onSingleTapUp(MotionEvent e) {
    private boolean onSingleTapUp(MotionEvent e) {
        if (Events.isTouchEvent(e) && mSelectionManager.getSelection().isEmpty()) {
        // Only respond to touch events.  Single-click mouse events are selection events and are
        // handled by the selection manager.  Tap events that occur while the selection manager is
        // active are also selection events.
        if (Events.isTouchEvent(e) && !mSelectionManager.hasSelection()) {
            int position = getEventAdapterPosition(e);
            int position = getEventAdapterPosition(e);
            if (position != RecyclerView.NO_POSITION) {
            if (position != RecyclerView.NO_POSITION) {
                return handleViewItem(position);
                return handleViewItem(position);
@@ -825,7 +833,7 @@ public class DirectoryFragment extends Fragment {
        Snackbars.makeSnackbar(activity, message, Snackbar.LENGTH_LONG)
        Snackbars.makeSnackbar(activity, message, Snackbar.LENGTH_LONG)
                .setAction(
                .setAction(
                        R.string.undo,
                        R.string.undo,
                        new android.view.View.OnClickListener() {
                        new View.OnClickListener() {
                            @Override
                            @Override
                            public void onClick(View view) {}
                            public void onClick(View view) {}
                        })
                        })
@@ -889,10 +897,16 @@ public class DirectoryFragment extends Fragment {
    // Provide a reference to the views for each data item
    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    // you provide access to all the views for a data item in a view holder
    private static final class DocumentHolder extends RecyclerView.ViewHolder {
    private static final class DocumentHolder
            extends RecyclerView.ViewHolder
            implements View.OnKeyListener
    {
        // each data item is just a string in this case
        // each data item is just a string in this case
        public View view;
        public View view;
        public String docId;  // The stable document id.
        public String docId;  // The stable document id.
        private ClickListener mClickListener;
        private View.OnKeyListener mKeyListener;

        public DocumentHolder(View view) {
        public DocumentHolder(View view) {
            super(view);
            super(view);
            this.view = view;
            this.view = view;
@@ -900,6 +914,38 @@ public class DirectoryFragment extends Fragment {
            // So we set it here.  Note that touch mode focus is a separate issue - see
            // So we set it here.  Note that touch mode focus is a separate issue - see
            // View.setFocusableInTouchMode and View.isInTouchMode for more info.
            // View.setFocusableInTouchMode and View.isInTouchMode for more info.
            this.view.setFocusable(true);
            this.view.setFocusable(true);
            this.view.setOnKeyListener(this);
        }

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            // Intercept enter key-up events, and treat them as clicks.  Forward other events.
            if (event.getAction() == KeyEvent.ACTION_UP &&
                    keyCode == KeyEvent.KEYCODE_ENTER) {
                if (mClickListener != null) {
                    mClickListener.onClick(this);
                }
                return true;
            } else if (mKeyListener != null) {
                return mKeyListener.onKey(v, keyCode, event);
            }
            return false;
        }

        public void addClickListener(ClickListener listener) {
            // Just handle one for now; switch to a list if necessary.
            checkState(mClickListener == null);
            mClickListener = listener;
        }

        public void addOnKeyListener(View.OnKeyListener listener) {
            // Just handle one for now; switch to a list if necessary.
            checkState(mKeyListener == null);
            mKeyListener = listener;
        }

        interface ClickListener {
            public void onClick(DocumentHolder doc);
        }
        }
    }
    }


@@ -952,10 +998,11 @@ public class DirectoryFragment extends Fragment {
                default:
                default:
                    throw new IllegalStateException("Unsupported layout mode.");
                    throw new IllegalStateException("Unsupported layout mode.");
            }
            }
            // Key event bubbling doesn't work properly, so instead of setting one key listener on

            // the RecyclerView, we have to set it on each Item.  See b/24865023.
            DocumentHolder holder = new DocumentHolder(item);
            item.setOnKeyListener(mSelectionManager);
            holder.addClickListener(mItemClickListener);
            return new DocumentHolder(item);
            holder.addOnKeyListener(mSelectionManager);
            return holder;
        }
        }


        @Override
        @Override
@@ -1957,6 +2004,18 @@ public class DirectoryFragment extends Fragment {
        }
        }
    }
    }


    private class ItemClickListener implements DocumentHolder.ClickListener {
        @Override
        public void onClick(DocumentHolder doc) {
            final int position = doc.getAdapterPosition();
            if (mSelectionManager.hasSelection()) {
                mSelectionManager.toggleSelection(position);
            } else {
                handleViewItem(position);
            }
        }
    }

    private class ModelUpdateListener extends Model.UpdateListener {
    private class ModelUpdateListener extends Model.UpdateListener {
        @Override
        @Override
        public void onModelUpdate(Model model) {
        public void onModelUpdate(Model model) {
+52 −0
Original line number Original line Diff line number Diff line
/*
 * 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 android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.LinearLayout;

/**
 * Layout for a single item in List mode.  This class overrides the default focus listener in order
 * to light up a focus indicator when it is focused.
 */
public class ListItem extends LinearLayout
{
    public ListItem(Context context) {
        super(context);
    }

    public ListItem(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
        View indicator = findViewById(R.id.focus_indicator);
        if (gainFocus) {
            TypedValue color = new TypedValue();
            getContext().getTheme().resolveAttribute(android.R.attr.colorAccent, color, true);
            indicator.setBackgroundColor(color.data);
        } else {
            indicator.setBackgroundColor(android.R.color.transparent);
        }
        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
    }
}
Loading