Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2014 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.tv.settings.widget;
     18 
     19 import android.os.Bundle;
     20 import android.os.Parcelable;
     21 import android.util.SparseArray;
     22 import android.view.View;
     23 
     24 /**
     25  * Maintains a bundle of states for a group of views. Each view must have a unique id to identify
     26  * it. There are four different strategies {@link #SAVE_NO_CHILD} {@link #SAVE_VISIBLE_CHILD}
     27  * {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}.
     28  * <p>
     29  * Why we "invent" another set of strategies beyond the default android view hierarchy saving
     30  * mechanism? Because android strategy for saving view states has two limitations: all indirect
     31  * descendant views must have a unique view id or their content will be messed together; no way of
     32  * defining saving removed views. Those two limitations are critical to AdapterView: AdapterView
     33  * will inevitably have two descendant views with same view id, we also need save the views when
     34  * they are scrolled out of viewport and removed.
     35  * <p>
     36  * The class is currently used within {@link ScrollAdapterView}, but it might be used by other
     37  * ViewGroup.
     38  */
     39 public abstract class ViewsStateBundle {
     40 
     41     /** dont save states of any child views */
     42     public static final int SAVE_NO_CHILD = 0;
     43     /** only save visible child views, the states are lost when they are gone */
     44     public static final int SAVE_VISIBLE_CHILD = 1;
     45     /** save visible views plus save removed child views states up to {@link #getLimitNumber()} */
     46     public static final int SAVE_LIMITED_CHILD = 2;
     47     /**
     48      * save visible views plus save removed child views without any limitation. This might cause out
     49      * of memory, only use it when you are dealing with limited data
     50      */
     51     public static final int SAVE_ALL_CHILD = 3;
     52 
     53     public static final int SAVE_LIMITED_CHILD_DEFAULT_VALUE = 100;
     54 
     55     private int savePolicy;
     56     private int limitNumber;
     57 
     58     private final Bundle childStates;
     59 
     60     public ViewsStateBundle(int policy, int limit) {
     61         savePolicy = policy;
     62         limitNumber = limit;
     63         childStates = new Bundle();
     64     }
     65 
     66     public void clear() {
     67         childStates.clear();
     68     }
     69 
     70     /**
     71      * @return the saved views states
     72      */
     73     public final Bundle getChildStates() {
     74         return childStates;
     75     }
     76 
     77     /**
     78      * @return the savePolicy, see {@link #SAVE_NO_CHILD} {@link #SAVE_VISIBLE_CHILD}
     79      *         {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}
     80      */
     81     public final int getSavePolicy() {
     82         return savePolicy;
     83     }
     84 
     85     /**
     86      * @return the limitNumber, only works when {@link #getSavePolicy()} is
     87      *         {@link #SAVE_LIMITED_CHILD}
     88      */
     89     public final int getLimitNumber() {
     90         return limitNumber;
     91     }
     92 
     93     /**
     94      * @see ViewsStateBundle#getSavePolicy()
     95      */
     96     public final void setSavePolicy(int savePolicy) {
     97         this.savePolicy = savePolicy;
     98     }
     99 
    100     /**
    101      * @see ViewsStateBundle#getLimitNumber()
    102      */
    103     public final void setLimitNumber(int limitNumber) {
    104         this.limitNumber = limitNumber;
    105     }
    106 
    107     /**
    108      * Load view from states, it's none operation if the there is no state associated with the id.
    109      *
    110      * @param view view where loads into
    111      * @param id unique id for the view within this ViewsStateBundle
    112      */
    113     public final void loadView(View view, int id) {
    114         String key = getSaveStatesKey(id);
    115         SparseArray<Parcelable> container = childStates.getSparseParcelableArray(key);
    116         if (container != null) {
    117             view.restoreHierarchyState(container);
    118         }
    119     }
    120 
    121     /**
    122      * Save views regardless what's the current policy is.
    123      *
    124      * @param view view to save
    125      * @param id unique id for the view within this ViewsStateBundle
    126      */
    127     protected final void saveViewUnchecked(View view, int id) {
    128         String key = getSaveStatesKey(id);
    129         SparseArray<Parcelable> container = new SparseArray<Parcelable>();
    130         view.saveHierarchyState(container);
    131         childStates.putSparseParcelableArray(key, container);
    132     }
    133 
    134     /**
    135      * The visible view is saved when policy is not {@link #SAVE_NO_CHILD}.
    136      *
    137      * @param view
    138      * @param id
    139      */
    140     public final void saveVisibleView(View view, int id) {
    141         if (savePolicy != SAVE_NO_CHILD) {
    142             saveViewUnchecked(view, id);
    143         }
    144     }
    145 
    146     /**
    147      * Save all visible views
    148      */
    149     public final void saveVisibleViews() {
    150         if (savePolicy != SAVE_NO_CHILD) {
    151             saveVisibleViewsUnchecked();
    152         }
    153     }
    154 
    155     /**
    156      * Save list of visible views without checking policy. The method is to be implemented by
    157      * subclass, client should use {@link #saveVisibleViews()}.
    158      */
    159     protected abstract void saveVisibleViewsUnchecked();
    160 
    161     /**
    162      * Save views according to policy.
    163      *
    164      * @param view view to save
    165      * @param id unique id for the view within this ViewsStateBundle
    166      */
    167     public final void saveInvisibleView(View view, int id) {
    168         switch (savePolicy) {
    169             case SAVE_LIMITED_CHILD:
    170                 if (childStates.size() > limitNumber) {
    171                     // TODO prune the Bundle to be under limit
    172                 }
    173                 // slip through next case section to save view
    174             case SAVE_ALL_CHILD:
    175                 saveViewUnchecked(view, id);
    176                 break;
    177             default:
    178                 break;
    179         }
    180     }
    181 
    182     static String getSaveStatesKey(int id) {
    183         return Integer.toString(id);
    184     }
    185 }
    186