1906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu/*
2906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * Copyright (C) 2014 The Android Open Source Project
3906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu *
4906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * in compliance with the License. You may obtain a copy of the License at
6906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu *
7906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * http://www.apache.org/licenses/LICENSE-2.0
8906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu *
9906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License
10906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * or implied. See the License for the specific language governing permissions and limitations under
12906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * the License.
13906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu */
14906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gupackage android.support.v17.leanback.widget;
15906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
16906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Guimport android.os.Bundle;
17906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Guimport android.os.Parcelable;
181102fc6fafe721522f2b67f86d89feda87096265Dake Guimport android.support.v4.util.LruCache;
19906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Guimport android.util.SparseArray;
20906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Guimport android.view.View;
21906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
221102fc6fafe721522f2b67f86d89feda87096265Dake Guimport java.util.Iterator;
231102fc6fafe721522f2b67f86d89feda87096265Dake Guimport java.util.Map;
241102fc6fafe721522f2b67f86d89feda87096265Dake Guimport java.util.Map.Entry;
251102fc6fafe721522f2b67f86d89feda87096265Dake Gu
261102fc6fafe721522f2b67f86d89feda87096265Dake Guimport static android.support.v17.leanback.widget.BaseGridView.SAVE_NO_CHILD;
271102fc6fafe721522f2b67f86d89feda87096265Dake Guimport static android.support.v17.leanback.widget.BaseGridView.SAVE_ON_SCREEN_CHILD;
281102fc6fafe721522f2b67f86d89feda87096265Dake Guimport static android.support.v17.leanback.widget.BaseGridView.SAVE_LIMITED_CHILD;
291102fc6fafe721522f2b67f86d89feda87096265Dake Guimport static android.support.v17.leanback.widget.BaseGridView.SAVE_ALL_CHILD;
301102fc6fafe721522f2b67f86d89feda87096265Dake Gu
31906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu/**
32906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * Maintains a bundle of states for a group of views. Each view must have a unique id to identify
33906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * it. There are four different strategies {@link #SAVE_NO_CHILD} {@link #SAVE_ON_SCREEN_CHILD}
34906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}.
35906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * <p>
36906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * This class serves purpose of nested "listview" e.g.  a vertical list of horizontal list.
37906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * Vertical list maintains id->bundle mapping of all it's children (even the children is offscreen
38906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * and being pruned).
39906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * <p>
40906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * The class is currently used within {@link GridLayoutManager}, but it might be used by other
41906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu * ViewGroup.
42906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu */
43906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Guclass ViewsStateBundle {
44906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
451102fc6fafe721522f2b67f86d89feda87096265Dake Gu    public static final int LIMIT_DEFAULT = 100;
461102fc6fafe721522f2b67f86d89feda87096265Dake Gu    public static final int UNLIMITED = Integer.MAX_VALUE;
47906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
48906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    private int mSavePolicy;
49906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    private int mLimitNumber;
50906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
511102fc6fafe721522f2b67f86d89feda87096265Dake Gu    private LruCache<String, SparseArray<Parcelable>> mChildStates;
52906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
531102fc6fafe721522f2b67f86d89feda87096265Dake Gu    public ViewsStateBundle() {
541102fc6fafe721522f2b67f86d89feda87096265Dake Gu        mSavePolicy = SAVE_NO_CHILD;
551102fc6fafe721522f2b67f86d89feda87096265Dake Gu        mLimitNumber = LIMIT_DEFAULT;
56906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
57906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
58906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    public void clear() {
591102fc6fafe721522f2b67f86d89feda87096265Dake Gu        if (mChildStates != null) {
601102fc6fafe721522f2b67f86d89feda87096265Dake Gu            mChildStates.evictAll();
611102fc6fafe721522f2b67f86d89feda87096265Dake Gu        }
62906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
63906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
6481a36a4dd93bf2f14c2eb88ae01464f85ddb0706Dake Gu    public void remove(int id) {
651102fc6fafe721522f2b67f86d89feda87096265Dake Gu        if (mChildStates != null && mChildStates.size() != 0) {
6681a36a4dd93bf2f14c2eb88ae01464f85ddb0706Dake Gu            mChildStates.remove(getSaveStatesKey(id));
6781a36a4dd93bf2f14c2eb88ae01464f85ddb0706Dake Gu        }
6881a36a4dd93bf2f14c2eb88ae01464f85ddb0706Dake Gu    }
6981a36a4dd93bf2f14c2eb88ae01464f85ddb0706Dake Gu
70906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    /**
71906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @return the saved views states
72906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     */
731102fc6fafe721522f2b67f86d89feda87096265Dake Gu    public final Bundle saveAsBundle() {
741102fc6fafe721522f2b67f86d89feda87096265Dake Gu        if (mChildStates == null || mChildStates.size() == 0) {
751102fc6fafe721522f2b67f86d89feda87096265Dake Gu            return null;
761102fc6fafe721522f2b67f86d89feda87096265Dake Gu        }
771102fc6fafe721522f2b67f86d89feda87096265Dake Gu        Map<String, SparseArray<Parcelable>> snapshot = mChildStates.snapshot();
781102fc6fafe721522f2b67f86d89feda87096265Dake Gu        Bundle bundle = new Bundle();
791102fc6fafe721522f2b67f86d89feda87096265Dake Gu        for (Iterator<Entry<String, SparseArray<Parcelable>>> i =
801102fc6fafe721522f2b67f86d89feda87096265Dake Gu                snapshot.entrySet().iterator(); i.hasNext(); ) {
811102fc6fafe721522f2b67f86d89feda87096265Dake Gu            Entry<String, SparseArray<Parcelable>> e = i.next();
821102fc6fafe721522f2b67f86d89feda87096265Dake Gu            bundle.putSparseParcelableArray(e.getKey(), e.getValue());
831102fc6fafe721522f2b67f86d89feda87096265Dake Gu        }
841102fc6fafe721522f2b67f86d89feda87096265Dake Gu        return bundle;
851102fc6fafe721522f2b67f86d89feda87096265Dake Gu    }
861102fc6fafe721522f2b67f86d89feda87096265Dake Gu
871102fc6fafe721522f2b67f86d89feda87096265Dake Gu    public final void loadFromBundle(Bundle savedBundle) {
881102fc6fafe721522f2b67f86d89feda87096265Dake Gu        if (mChildStates != null && savedBundle != null) {
891102fc6fafe721522f2b67f86d89feda87096265Dake Gu            mChildStates.evictAll();
901102fc6fafe721522f2b67f86d89feda87096265Dake Gu            for (Iterator<String> i = savedBundle.keySet().iterator(); i.hasNext(); ) {
911102fc6fafe721522f2b67f86d89feda87096265Dake Gu                String key = i.next();
921102fc6fafe721522f2b67f86d89feda87096265Dake Gu                mChildStates.put(key, savedBundle.getSparseParcelableArray(key));
931102fc6fafe721522f2b67f86d89feda87096265Dake Gu            }
941102fc6fafe721522f2b67f86d89feda87096265Dake Gu        }
95906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
96906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
97906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    /**
98906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @return the savePolicy, see {@link #SAVE_NO_CHILD} {@link #SAVE_ON_SCREEN_CHILD}
99906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     *         {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}
100906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     */
101906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    public final int getSavePolicy() {
102906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        return mSavePolicy;
103906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
104906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
105906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    /**
106906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @return the limitNumber, only works when {@link #getSavePolicy()} is
107906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     *         {@link #SAVE_LIMITED_CHILD}
108906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     */
109906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    public final int getLimitNumber() {
110906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        return mLimitNumber;
111906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
112906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
113906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    /**
114906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @see ViewsStateBundle#getSavePolicy()
115906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     */
116906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    public final void setSavePolicy(int savePolicy) {
117906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        this.mSavePolicy = savePolicy;
1181102fc6fafe721522f2b67f86d89feda87096265Dake Gu        applyPolicyChanges();
119906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
120906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
121906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    /**
122906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @see ViewsStateBundle#getLimitNumber()
123906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     */
124906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    public final void setLimitNumber(int limitNumber) {
125906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        this.mLimitNumber = limitNumber;
1261102fc6fafe721522f2b67f86d89feda87096265Dake Gu        applyPolicyChanges();
1271102fc6fafe721522f2b67f86d89feda87096265Dake Gu    }
1281102fc6fafe721522f2b67f86d89feda87096265Dake Gu
1291102fc6fafe721522f2b67f86d89feda87096265Dake Gu    protected void applyPolicyChanges() {
1301102fc6fafe721522f2b67f86d89feda87096265Dake Gu        if (mSavePolicy == SAVE_LIMITED_CHILD) {
1311102fc6fafe721522f2b67f86d89feda87096265Dake Gu            if (mLimitNumber <= 0) {
1321102fc6fafe721522f2b67f86d89feda87096265Dake Gu                throw new IllegalArgumentException();
1331102fc6fafe721522f2b67f86d89feda87096265Dake Gu            }
1341102fc6fafe721522f2b67f86d89feda87096265Dake Gu            if (mChildStates == null || mChildStates.maxSize() != mLimitNumber) {
1351102fc6fafe721522f2b67f86d89feda87096265Dake Gu                mChildStates = new LruCache<String, SparseArray<Parcelable>>(mLimitNumber);
1361102fc6fafe721522f2b67f86d89feda87096265Dake Gu            }
1371102fc6fafe721522f2b67f86d89feda87096265Dake Gu        } else if (mSavePolicy == SAVE_ALL_CHILD || mSavePolicy == SAVE_ON_SCREEN_CHILD) {
1381102fc6fafe721522f2b67f86d89feda87096265Dake Gu            if (mChildStates == null || mChildStates.maxSize() != UNLIMITED) {
1391102fc6fafe721522f2b67f86d89feda87096265Dake Gu                mChildStates = new LruCache<String, SparseArray<Parcelable>>(UNLIMITED);
1401102fc6fafe721522f2b67f86d89feda87096265Dake Gu            }
1411102fc6fafe721522f2b67f86d89feda87096265Dake Gu        } else {
1421102fc6fafe721522f2b67f86d89feda87096265Dake Gu            mChildStates = null;
1431102fc6fafe721522f2b67f86d89feda87096265Dake Gu        }
144906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
145906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
146906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    /**
147906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * Load view from states, it's none operation if the there is no state associated with the id.
148906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     *
149906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @param view view where loads into
150906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @param id unique id for the view within this ViewsStateBundle
151906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     */
152906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    public final void loadView(View view, int id) {
1531102fc6fafe721522f2b67f86d89feda87096265Dake Gu        if (mChildStates != null) {
1541102fc6fafe721522f2b67f86d89feda87096265Dake Gu            String key = getSaveStatesKey(id);
1551102fc6fafe721522f2b67f86d89feda87096265Dake Gu            SparseArray<Parcelable> container = mChildStates.get(key);
1561102fc6fafe721522f2b67f86d89feda87096265Dake Gu            if (container != null) {
1571102fc6fafe721522f2b67f86d89feda87096265Dake Gu                view.restoreHierarchyState(container);
1581102fc6fafe721522f2b67f86d89feda87096265Dake Gu            }
159906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        }
160906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
161906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
162906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    /**
163906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * Save views regardless what's the current policy is.
164906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     *
165906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @param view view to save
166906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @param id unique id for the view within this ViewsStateBundle
167906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     */
168906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    protected final void saveViewUnchecked(View view, int id) {
1691102fc6fafe721522f2b67f86d89feda87096265Dake Gu        if (mChildStates != null) {
1701102fc6fafe721522f2b67f86d89feda87096265Dake Gu            String key = getSaveStatesKey(id);
1711102fc6fafe721522f2b67f86d89feda87096265Dake Gu            SparseArray<Parcelable> container = new SparseArray<Parcelable>();
1721102fc6fafe721522f2b67f86d89feda87096265Dake Gu            view.saveHierarchyState(container);
1731102fc6fafe721522f2b67f86d89feda87096265Dake Gu            mChildStates.put(key, container);
1741102fc6fafe721522f2b67f86d89feda87096265Dake Gu        }
175906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
176906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
177906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    /**
178906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * The on screen view is saved when policy is not {@link #SAVE_NO_CHILD}.
179906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     *
180906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @param view
181906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @param id
182906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     */
183906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    public final void saveOnScreenView(View view, int id) {
184906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        if (mSavePolicy != SAVE_NO_CHILD) {
185906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu            saveViewUnchecked(view, id);
186906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        }
187906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
188906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
189906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    /**
190906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * Save off screen views according to policy.
191906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     *
192906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @param view view to save
193906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     * @param id unique id for the view within this ViewsStateBundle
194906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu     */
195906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    public final void saveOffscreenView(View view, int id) {
196906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        switch (mSavePolicy) {
197906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu            case SAVE_LIMITED_CHILD:
198906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu            case SAVE_ALL_CHILD:
199906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu                saveViewUnchecked(view, id);
200906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu                break;
2011102fc6fafe721522f2b67f86d89feda87096265Dake Gu            case SAVE_ON_SCREEN_CHILD:
2021102fc6fafe721522f2b67f86d89feda87096265Dake Gu                remove(id);
2031102fc6fafe721522f2b67f86d89feda87096265Dake Gu                break;
204906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu            default:
205906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu                break;
206906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        }
207906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
208906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu
209906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    static String getSaveStatesKey(int id) {
210906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu        return Integer.toString(id);
211906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu    }
212906659fc65e7b8b1bc9f0c7cc3dabf7e64e8b9bfDake Gu}
213