120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn/*
220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Copyright (C) 2014 The Android Open Source Project
320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * in compliance with the License. You may obtain a copy of the License at
620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * http://www.apache.org/licenses/LICENSE-2.0
820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * Unless required by applicable law or agreed to in writing, software distributed under the License
1020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * or implied. See the License for the specific language governing permissions and limitations under
1220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * the License.
1320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */
1420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournpackage android.support.v17.leanback.widget;
1520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
1620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.view.View;
1720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbournimport android.view.ViewGroup;
1820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
1908c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Guimport java.util.HashMap;
2008a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangliimport java.util.List;
2108c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Guimport java.util.Map;
2208c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu
2320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn/**
2420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * A Presenter is used to generate {@link View}s and bind Objects to them on
25a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * demand. It is closely related to the concept of an {@link
2660d34fdccbe92a77e01b2cc63ffcab092a91009fTim Kilbourn * android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, but is
27a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * not position-based.  The leanback framework implements the adapter concept using
28a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * {@link ObjectAdapter} which refers to a Presenter (or {@link PresenterSelector}) instance.
29a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout *
30a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * <p>
31a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Presenters should be stateless.  Presenters typically extend {@link ViewHolder} to store all
32a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * necessary view state information, such as references to child views to be used when
33a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * binding to avoid expensive calls to {@link View#findViewById(int)}.
34a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * </p>
3520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
3620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * <p>
3720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * A trivial Presenter that takes a string and renders it into a {@link
3860d34fdccbe92a77e01b2cc63ffcab092a91009fTim Kilbourn * android.widget.TextView TextView}:
3920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
4020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * <pre class="prettyprint">
4120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * public class StringTextViewPresenter extends Presenter {
4220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *     // This class does not need a custom ViewHolder, since it does not use
4320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *     // a complex layout.
4420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
4520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *     {@literal @}Override
4660d34fdccbe92a77e01b2cc63ffcab092a91009fTim Kilbourn *     public ViewHolder onCreateViewHolder(ViewGroup parent) {
4720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *         return new ViewHolder(new TextView(parent.getContext()));
4820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *     }
4920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
5020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *     {@literal @}Override
5160d34fdccbe92a77e01b2cc63ffcab092a91009fTim Kilbourn *     public void onBindViewHolder(ViewHolder viewHolder, Object item) {
5220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *         String str = (String) item;
5320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *         TextView textView = (TextView) viewHolder.mView;
5420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
5520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *         textView.setText(item);
5620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *     }
5720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *
5820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *     {@literal @}Override
5960d34fdccbe92a77e01b2cc63ffcab092a91009fTim Kilbourn *     public void onUnbindViewHolder(ViewHolder viewHolder) {
6060d34fdccbe92a77e01b2cc63ffcab092a91009fTim Kilbourn *         // Nothing to unbind for TextView, but if this viewHolder had
6160d34fdccbe92a77e01b2cc63ffcab092a91009fTim Kilbourn *         // allocated bitmaps, they can be released here.
6220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn *     }
6320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * }
6420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn * </pre>
6508c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu * In addition to view creation and binding, Presenter allows dynamic interface (facet) to
6608c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu * be added: {@link #setFacet(Class, Object)}.  Supported facets:
6708c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu * <li> {@link ItemAlignmentFacet} is used by {@link HorizontalGridView} and
6808c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu * {@link VerticalGridView} to customize child alignment.
6920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn */
7008c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gupublic abstract class Presenter implements FacetProvider {
7120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
7220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * ViewHolder can be subclassed and used to cache any view accessors needed
7320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * to improve binding performance (for example, results of findViewById)
7420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * without needing to subclass a View.
7520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
7608c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu    public static class ViewHolder implements FacetProvider {
7720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        public final View view;
7808c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        private Map<Class, Object> mFacets;
7920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
8020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        public ViewHolder(View view) {
8120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn            this.view = view;
8220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn        }
8308c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu
8408c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        @Override
8508c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        public final Object getFacet(Class<?> facetClass) {
8608c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu            if (mFacets == null) {
8708c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu                return null;
8808c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu            }
8908c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu            return mFacets.get(facetClass);
9008c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        }
9108c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu
9208c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        /**
9308c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu         * Sets dynamic implemented facet in addition to basic ViewHolder functions.
9408c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu         * @param facetClass   Facet classes to query,  can be class of {@link ItemAlignmentFacet}.
9508c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu         * @param facetImpl  Facet implementation.
9608c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu         */
9708c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        public final void setFacet(Class<?> facetClass, Object facetImpl) {
9808c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu            if (mFacets == null) {
9908c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu                mFacets = new HashMap<Class, Object>();
10008c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu            }
10108c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu            mFacets.put(facetClass, facetImpl);
10208c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        }
10320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    }
10420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
105cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu    /**
106cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu     * Base class to perform a task on Presenter.ViewHolder.
107cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu     */
108cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu    public static abstract class ViewHolderTask {
109cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        /**
110cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * Called to perform a task on view holder.
111cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * @param holder The view holder to perform task.
112cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         */
113cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        public void run(Presenter.ViewHolder holder) {
114cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        }
115cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu    }
116cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
11708c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu    private Map<Class, Object> mFacets;
11808c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu
11920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
12020c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Creates a new {@link View}.
12120c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
12220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public abstract ViewHolder onCreateViewHolder(ViewGroup parent);
12320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
12420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
12520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Binds a {@link View} to an item.
12620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
12720c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public abstract void onBindViewHolder(ViewHolder viewHolder, Object item);
12820c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn
12920c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    /**
13008a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli     * Binds a {@link View} to an item with a list of payloads.
13108a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli     * @param viewHolder  The ViewHolder which should be updated to represent the contents of the
13208a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli     *                    item at the given position in the data set.
13308a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli     * @param item        The item which should be bound to view holder.
13408a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli     * @param payloads    A non-null list of merged payloads. Can be empty list if requires full
13508a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli     *                    update.
13608a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli     */
13708a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli    public void onBindViewHolder(ViewHolder viewHolder, Object item, List<Object> payloads) {
13808a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli        onBindViewHolder(viewHolder, item);
13908a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli    }
14008a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli
14108a38559a3751252fc8a1f36db0a431508a8f7d5jingjiangli    /**
14220c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * Unbinds a {@link View} from an item. Any expensive references may be
14320c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * released here, and any fields that are not bound for every item should be
14420c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     * cleared here.
14520c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn     */
14620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn    public abstract void onUnbindViewHolder(ViewHolder viewHolder);
14747520b68e50572a9775a662410c5aff8300c8784Craig Stout
14847520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
14947520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Called when a view created by this presenter has been attached to a window.
15047520b68e50572a9775a662410c5aff8300c8784Craig Stout     *
15147520b68e50572a9775a662410c5aff8300c8784Craig Stout     * <p>This can be used as a reasonable signal that the view is about to be seen
15247520b68e50572a9775a662410c5aff8300c8784Craig Stout     * by the user. If the adapter previously freed any resources in
15347520b68e50572a9775a662410c5aff8300c8784Craig Stout     * {@link #onViewDetachedFromWindow(ViewHolder)}
15447520b68e50572a9775a662410c5aff8300c8784Craig Stout     * those resources should be restored here.</p>
15547520b68e50572a9775a662410c5aff8300c8784Craig Stout     *
15647520b68e50572a9775a662410c5aff8300c8784Craig Stout     * @param holder Holder of the view being attached
15747520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
15847520b68e50572a9775a662410c5aff8300c8784Craig Stout    public void onViewAttachedToWindow(ViewHolder holder) {
15947520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
16047520b68e50572a9775a662410c5aff8300c8784Craig Stout
16147520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
16247520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Called when a view created by this presenter has been detached from its window.
16347520b68e50572a9775a662410c5aff8300c8784Craig Stout     *
16447520b68e50572a9775a662410c5aff8300c8784Craig Stout     * <p>Becoming detached from the window is not necessarily a permanent condition;
16547520b68e50572a9775a662410c5aff8300c8784Craig Stout     * the consumer of an presenter's views may choose to cache views offscreen while they
166ef9d4aa4eb25e5a0e6ec3ff7c406ced131726ff2Nick Chalko     * are not visible, attaching and detaching them as appropriate.</p>
16747520b68e50572a9775a662410c5aff8300c8784Craig Stout     *
1685358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout     * Any view property animations should be cancelled here or the view may fail
1695358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout     * to be recycled.
1705358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout     *
17147520b68e50572a9775a662410c5aff8300c8784Craig Stout     * @param holder Holder of the view being detached
17247520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
17347520b68e50572a9775a662410c5aff8300c8784Craig Stout    public void onViewDetachedFromWindow(ViewHolder holder) {
1745358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout        // If there are view property animations running then RecyclerView won't recycle.
1755358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout        cancelAnimationsRecursive(holder.view);
1765358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout    }
1775358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout
1785358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout    /**
1795358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout     * Utility method for removing all running animations on a view.
1805358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout     */
1815358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout    protected static void cancelAnimationsRecursive(View view) {
182b455339a4d442068dd312fb93c0544106810dfadDake Gu        if (view != null && view.hasTransientState()) {
1835358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout            view.animate().cancel();
1845358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout            if (view instanceof ViewGroup) {
1855358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout                final int count = ((ViewGroup) view).getChildCount();
1865358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout                for (int i = 0; view.hasTransientState() && i < count; i++) {
1875358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout                    cancelAnimationsRecursive(((ViewGroup) view).getChildAt(i));
1885358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout                }
1895358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout            }
1905358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout        }
19147520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
19247520b68e50572a9775a662410c5aff8300c8784Craig Stout
1937ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    /**
1947ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     * Called to set a click listener for the given view holder.
1957ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     *
1967ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     * The default implementation sets the click listener on the root view in the view holder.
1977ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     * If the root view isn't focusable this method should be overridden to set the listener
1987ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     * on the appropriate focusable child view(s).
1997ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     *
2007ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     * @param holder The view holder containing the view(s) on which the listener should be set.
2017ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     * @param listener The click listener to be set.
2027ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     */
2037ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    public void setOnClickListener(ViewHolder holder, View.OnClickListener listener) {
2047ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        holder.view.setOnClickListener(listener);
2057ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    }
20608c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu
20708c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu    @Override
20808c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu    public final Object getFacet(Class<?> facetClass) {
20908c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        if (mFacets == null) {
21008c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu            return null;
21108c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        }
21208c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        return mFacets.get(facetClass);
21308c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu    }
21408c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu
21508c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu    /**
21608c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu     * Sets dynamic implemented facet in addition to basic Presenter functions.
21708c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu     * @param facetClass   Facet classes to query,  can be class of {@link ItemAlignmentFacet}.
21808c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu     * @param facetImpl  Facet implementation.
21908c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu     */
22008c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu    public final void setFacet(Class<?> facetClass, Object facetImpl) {
22108c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        if (mFacets == null) {
22208c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu            mFacets = new HashMap<Class, Object>();
22308c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        }
22408c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu        mFacets.put(facetClass, facetImpl);
22508c56822b71ab0aa0b9bb03e5fd45e28f6e358b8Dake Gu    }
22620c094c196271089a7119a965b6a99786ea9ed36Tim Kilbourn}
227