Home | History | Annotate | Download | only in selection
      1 /*
      2  * Copyright (C) 2017 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.selection;
     18 
     19 import java.util.List;
     20 import java.util.Set;
     21 
     22 /**
     23  * SelectionManager provides support for managing selection within a RecyclerView instance.
     24  *
     25  * @see DefaultSelectionHelper for details on instantiation.
     26  */
     27 public abstract class SelectionHelper {
     28 
     29     /**
     30      * This value is included in the payload when SelectionHelper implementations
     31      * notify RecyclerView of changes. Clients can look for this in
     32      * {@code onBindViewHolder} to know if the bind event is occurring in response
     33      * to a selection state change.
     34      */
     35     public static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
     36 
     37     /**
     38      * Adds {@code observe} to be notified when changes to selection occur.
     39      *
     40      * @param observer
     41      */
     42     public abstract void addObserver(SelectionObserver observer);
     43 
     44     public abstract boolean hasSelection();
     45 
     46     /**
     47      * Returns a Selection object that provides a live view on the current selection.
     48      *
     49      * @see #copySelection(Selection) on how to get a snapshot
     50      *     of the selection that will not reflect future changes
     51      *     to selection.
     52      *
     53      * @return The current selection.
     54      */
     55     public abstract Selection getSelection();
     56 
     57     /**
     58      * Updates {@code dest} to reflect the current selection.
     59      * @param dest
     60      */
     61     public abstract void copySelection(Selection dest);
     62 
     63     /**
     64      * @return true if the item specified by its id is selected. Shorthand for
     65      * {@code getSelection().contains(String)}.
     66      */
     67     public abstract boolean isSelected(String id);
     68 
     69     /**
     70      * Restores the selected state of specified items. Used in cases such as restore the selection
     71      * after rotation etc. Provisional selection, being provisional 'n all, isn't restored.
     72      */
     73     public abstract void restoreSelection(Selection other);
     74 
     75     /**
     76      * Sets the selected state of the specified items. Note that the callback will NOT
     77      * be consulted to see if an item can be selected.
     78      *
     79      * @param ids
     80      * @param selected
     81      * @return
     82      */
     83     public abstract boolean setItemsSelected(Iterable<String> ids, boolean selected);
     84 
     85     /**
     86      * Clears the selection and notifies (if something changes).
     87      */
     88     public abstract void clearSelection();
     89 
     90     /**
     91      * Attempts to select an item.
     92      *
     93      * @return true if the item was selected. False if the item was not selected, or was
     94      *         was already selected prior to the method being called.
     95      */
     96     public abstract boolean select(String itemId);
     97 
     98     /**
     99      * Attempts to deselect an item.
    100      *
    101      * @return true if the item was deselected. False if the item was not deselected, or was
    102      *         was already deselected prior to the method being called.
    103      */
    104     public abstract boolean deselect(String itemId);
    105 
    106     /**
    107      * Starts a range selection. If a range selection is already active, this will start a new range
    108      * selection (which will reset the range anchor).
    109      *
    110      * @param pos The anchor position for the selection range.
    111      */
    112     public abstract void startRange(int pos);
    113 
    114     /**
    115      * Sets the end point for the active range selection.
    116      *
    117      * <p>This function should only be called when a range selection is active
    118      * (see {@link #isRangeActive()}. Items in the range [anchor, end] will be
    119      * selected.
    120      *
    121      * @param pos The new end position for the selection range.
    122      * @param type The type of selection the range should utilize.
    123      *
    124      * @throws IllegalStateException if a range selection is not active. Range selection
    125      *         must have been started by a call to {@link #startRange(int)}.
    126      */
    127     public abstract void extendRange(int pos);
    128 
    129     /**
    130      * Stops an in-progress range selection. All selection done with
    131      * {@link #extendProvisionalRange(int)} will be lost if
    132      * {@link Selection#mergeProvisionalSelection()} is not called beforehand.
    133      */
    134     public abstract void endRange();
    135 
    136     /**
    137      * @return Whether or not there is a current range selection active.
    138      */
    139     public abstract boolean isRangeActive();
    140 
    141     /**
    142      * Sets the magic location at which a selection range begins (the selection anchor). This value
    143      * is consulted when determining how to extend, and modify selection ranges. Calling this when a
    144      * range selection is active will reset the range selection.
    145      */
    146     public abstract void anchorRange(int position);
    147 
    148     /**
    149      * @param pos
    150      */
    151     // TODO: This is smelly. Maybe this type of logic needs to move into range selection,
    152     // then selection manager can have a startProvisionalRange and startRange. Or
    153     // maybe ranges always start life as provisional.
    154     public abstract void extendProvisionalRange(int pos);
    155 
    156     /**
    157      * @param newSelection
    158      */
    159     public abstract void setProvisionalSelection(Set<String> newSelection);
    160 
    161     /**
    162      *
    163      */
    164     public abstract void clearProvisionalSelection();
    165 
    166     public abstract void mergeProvisionalSelection();
    167 
    168     /**
    169      * Observer interface providing access to information about Selection state changes.
    170      */
    171     public static abstract class SelectionObserver {
    172 
    173         /**
    174          * Called when state of an item has been changed.
    175          */
    176         public void onItemStateChanged(String id, boolean selected) {}
    177 
    178         /**
    179          * Called when the underlying data set has change. After this method is called
    180          * the selection manager will attempt traverse the existing selection,
    181          * calling {@link #onItemStateChanged(String, boolean)} for each selected item,
    182          * and deselecting any items that cannot be selected given the updated dataset.
    183          */
    184         public void onSelectionReset() {}
    185 
    186         /**
    187          * Called immediately after completion of any set of changes, excluding
    188          * those resulting in calls to {@link #onSelectionReset()} and
    189          * {@link #onSelectionRestored()}.
    190          */
    191         public void onSelectionChanged() {}
    192 
    193         /**
    194          * Called immediately after selection is restored.
    195          * {@link #onItemStateChanged(String, boolean)} will not be called
    196          * for individual items in the selection.
    197          */
    198         public void onSelectionRestored() {}
    199     }
    200 
    201     /**
    202      * Facilitates the use of stable ids.
    203      */
    204     public static abstract class StableIdProvider {
    205         /**
    206          * @return The model ID of the item at the given adapter position.
    207          */
    208         public abstract String getStableId(int position);
    209 
    210         /**
    211          * @return the position of a stable ID, or RecyclerView.NO_POSITION.
    212          */
    213         public abstract int getPosition(String id);
    214 
    215         /**
    216          * @return A list of all known stable IDs.
    217          */
    218         public abstract List<String> getStableIds();
    219     }
    220 
    221     /**
    222      * Implement SelectionPredicate to control when items can be selected or unselected.
    223      */
    224     public static abstract class SelectionPredicate {
    225 
    226         /** @return true if the item at {@code id} can be set to {@code nextState}. */
    227         public abstract boolean canSetStateForId(String id, boolean nextState);
    228 
    229         /** @return true if the item at {@code id} can be set to {@code nextState}. */
    230         public abstract boolean canSetStateAtPosition(int position, boolean nextState);
    231 
    232         /** @return true if more than a single item can be selected. */
    233         public boolean canSelectMultiple() {
    234             return true;
    235         }
    236     }
    237 }
    238