Home | History | Annotate | Download | only in dirlist
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.documentsui.dirlist;
     18 
     19 import android.annotation.ColorInt;
     20 import android.content.Context;
     21 import android.database.Cursor;
     22 import android.graphics.Rect;
     23 import android.support.annotation.Nullable;
     24 import android.support.v7.widget.RecyclerView;
     25 import android.view.KeyEvent;
     26 import android.view.LayoutInflater;
     27 import android.view.MotionEvent;
     28 import android.view.View;
     29 import android.view.ViewGroup;
     30 
     31 import com.android.documentsui.Events;
     32 import com.android.documentsui.R;
     33 import com.android.documentsui.State;
     34 
     35 public abstract class DocumentHolder
     36         extends RecyclerView.ViewHolder
     37         implements View.OnKeyListener {
     38 
     39     static final float DISABLED_ALPHA = 0.3f;
     40 
     41     public @Nullable String modelId;
     42 
     43     final Context mContext;
     44     final @ColorInt int mDefaultBgColor;
     45     final @ColorInt int mSelectedBgColor;
     46 
     47     DocumentHolder.EventListener mEventListener;
     48     private View.OnKeyListener mKeyListener;
     49     private View mSelectionHotspot;
     50 
     51 
     52     public DocumentHolder(Context context, ViewGroup parent, int layout) {
     53         this(context, inflateLayout(context, parent, layout));
     54     }
     55 
     56     public DocumentHolder(Context context, View item) {
     57         super(item);
     58 
     59         itemView.setOnKeyListener(this);
     60 
     61         mContext = context;
     62 
     63         mDefaultBgColor = context.getColor(R.color.item_doc_background);
     64         mSelectedBgColor = context.getColor(R.color.item_doc_background_selected);
     65 
     66         mSelectionHotspot = itemView.findViewById(R.id.icon_check);
     67     }
     68 
     69     /**
     70      * Binds the view to the given item data.
     71      * @param cursor
     72      * @param modelId
     73      * @param state
     74      */
     75     public abstract void bind(Cursor cursor, String modelId, State state);
     76 
     77     /**
     78      * Makes the associated item view appear selected. Note that this merely affects the appearance
     79      * of the view, it doesn't actually select the item.
     80      * TODO: Use the DirectoryItemAnimator instead of manually controlling animation using a boolean
     81      * flag.
     82      *
     83      * @param selected
     84      * @param animate Whether or not to animate the change. Only selection changes initiated by the
     85      *            selection manager should be animated. See
     86      *            {@link ModelBackedDocumentsAdapter#onBindViewHolder(DocumentHolder, int, java.util.List)}
     87      */
     88     public void setSelected(boolean selected, boolean animate) {
     89         // Note: the animate param doesn't apply for this base implementation, because the
     90         // DirectoryItemAnimator takes care of it. It's required by subclasses, which perform their
     91         // own animation.
     92         itemView.setActivated(selected);
     93         itemView.setBackgroundColor(selected ? mSelectedBgColor : mDefaultBgColor);
     94     }
     95 
     96     /**
     97      * Highlights the associated item view.
     98      * @param highlighted
     99      */
    100     public void setHighlighted(boolean highlighted) {
    101         itemView.setBackgroundColor(highlighted ? mSelectedBgColor : mDefaultBgColor);
    102     }
    103 
    104     public void setEnabled(boolean enabled) {
    105         setEnabledRecursive(itemView, enabled);
    106     }
    107 
    108     @Override
    109     public boolean onKey(View v, int keyCode, KeyEvent event) {
    110         // Event listener should always be set.
    111         assert(mEventListener != null);
    112 
    113         return mEventListener.onKey(this,  keyCode,  event);
    114     }
    115 
    116     public void addEventListener(DocumentHolder.EventListener listener) {
    117         // Just handle one for now; switch to a list if necessary.
    118         assert(mEventListener == null);
    119         mEventListener = listener;
    120     }
    121 
    122     public void addOnKeyListener(View.OnKeyListener listener) {
    123         // Just handle one for now; switch to a list if necessary.
    124         assert(mKeyListener == null);
    125         mKeyListener = listener;
    126     }
    127 
    128     public boolean onSingleTapUp(MotionEvent event) {
    129         if (Events.isMouseEvent(event)) {
    130             // Mouse clicks select.
    131             // TODO:  && input.isPrimaryButtonPressed(), but it is returning false.
    132             if (mEventListener != null) {
    133                 return mEventListener.onSelect(this);
    134             }
    135         } else if (Events.isTouchEvent(event)) {
    136             // Touch events select if they occur in the selection hotspot, otherwise they activate.
    137             if (mEventListener == null) {
    138                 return false;
    139             }
    140 
    141             // Do everything in global coordinates - it makes things simpler.
    142             int[] coords = new int[2];
    143             mSelectionHotspot.getLocationOnScreen(coords);
    144             Rect rect = new Rect(coords[0], coords[1], coords[0] + mSelectionHotspot.getWidth(),
    145                     coords[1] + mSelectionHotspot.getHeight());
    146 
    147             // If the tap occurred within the icon rect, consider it a selection.
    148             if (rect.contains((int) event.getRawX(), (int) event.getRawY())) {
    149                 return mEventListener.onSelect(this);
    150             } else {
    151                 return mEventListener.onActivate(this);
    152             }
    153         }
    154         return false;
    155     }
    156 
    157     static void setEnabledRecursive(View itemView, boolean enabled) {
    158         if (itemView == null) return;
    159         if (itemView.isEnabled() == enabled) return;
    160         itemView.setEnabled(enabled);
    161 
    162         if (itemView instanceof ViewGroup) {
    163             final ViewGroup vg = (ViewGroup) itemView;
    164             for (int i = vg.getChildCount() - 1; i >= 0; i--) {
    165                 setEnabledRecursive(vg.getChildAt(i), enabled);
    166             }
    167         }
    168     }
    169 
    170     private static View inflateLayout(Context context, ViewGroup parent, int layout) {
    171         final LayoutInflater inflater = LayoutInflater.from(context);
    172         return inflater.inflate(layout, parent, false);
    173     }
    174 
    175     /**
    176      * Implement this in order to be able to respond to events coming from DocumentHolders.
    177      */
    178     interface EventListener {
    179         /**
    180          * Handles activation events on the document holder.
    181          *
    182          * @param doc The target DocumentHolder
    183          * @return Whether the event was handled.
    184          */
    185         public boolean onActivate(DocumentHolder doc);
    186 
    187         /**
    188          * Handles selection events on the document holder.
    189          *
    190          * @param doc The target DocumentHolder
    191          * @return Whether the event was handled.
    192          */
    193         public boolean onSelect(DocumentHolder doc);
    194 
    195         /**
    196          * Handles key events on the document holder.
    197          *
    198          * @param doc The target DocumentHolder.
    199          * @param keyCode Key code for the event.
    200          * @param event KeyEvent for the event.
    201          * @return Whether the event was handled.
    202          */
    203         public boolean onKey(DocumentHolder doc, int keyCode, KeyEvent event);
    204     }
    205 }
    206