1package android.support.v17.leanback.widget;
2
3import android.support.v17.leanback.R;
4
5import android.graphics.drawable.Drawable;
6import android.view.LayoutInflater;
7import android.view.View;
8import android.view.ViewGroup;
9import android.view.ViewGroup.MarginLayoutParams;
10import android.widget.ImageView;
11
12/**
13 * Presenter that responsible to create a ImageView and bind to DetailsOverviewRow. The default
14 * implementation uses {@link DetailsOverviewRow#getImageDrawable()} and binds to {@link ImageView}.
15 * <p>
16 * Default implementation assumes no scaleType on ImageView and uses intrinsic width and height of
17 * {@link DetailsOverviewRow#getImageDrawable()} to initialize ImageView's layout params.  To
18 * specify a fixed size and/or specify a scapeType, subclass should change ImageView's layout params
19 * and scaleType in {@link #onCreateView(ViewGroup)}.
20 * <p>
21 * Subclass may override and has its own image view. Subclass may also download image from URL
22 * instead of using {@link DetailsOverviewRow#getImageDrawable()}. It's subclass's responsibility to
23 * call {@link FullWidthDetailsOverviewRowPresenter#notifyOnBindLogo(FullWidthDetailsOverviewRowPresenter.ViewHolder)}
24 * whenever {@link #isBoundToImage(ViewHolder, DetailsOverviewRow)} turned to true so that activity
25 * transition can be started.
26 */
27public class DetailsOverviewLogoPresenter extends Presenter {
28
29    /**
30     * ViewHolder for Logo view of DetailsOverviewRow.
31     */
32    public static class ViewHolder extends Presenter.ViewHolder {
33
34        protected FullWidthDetailsOverviewRowPresenter mParentPresenter;
35        protected FullWidthDetailsOverviewRowPresenter.ViewHolder mParentViewHolder;
36        private boolean mSizeFromDrawableIntrinsic;
37
38        public ViewHolder(View view) {
39            super(view);
40        }
41
42        public FullWidthDetailsOverviewRowPresenter getParentPresenter() {
43            return mParentPresenter;
44        }
45
46        public FullWidthDetailsOverviewRowPresenter.ViewHolder getParentViewHolder() {
47            return mParentViewHolder;
48        }
49
50        /**
51         * @return True if layout size of ImageView should be changed to intrinsic size of Drawable,
52         *         false otherwise. Used by
53         *         {@link DetailsOverviewLogoPresenter#onBindViewHolder(Presenter.ViewHolder, Object)}
54         *         .
55         *
56         * @see DetailsOverviewLogoPresenter#onCreateView(ViewGroup)
57         * @see DetailsOverviewLogoPresenter#onBindViewHolder(Presenter.ViewHolder, Object)
58         */
59        public boolean isSizeFromDrawableIntrinsic() {
60            return mSizeFromDrawableIntrinsic;
61        }
62
63        /**
64         * Change if the ImageView layout size should be synchronized to Drawable intrinsic size.
65         * Used by
66         * {@link DetailsOverviewLogoPresenter#onBindViewHolder(Presenter.ViewHolder, Object)}.
67         *
68         * @param sizeFromDrawableIntrinsic True if layout size of ImageView should be changed to
69         *        intrinsic size of Drawable, false otherwise.
70         *
71         * @see DetailsOverviewLogoPresenter#onCreateView(ViewGroup)
72         * @see DetailsOverviewLogoPresenter#onBindViewHolder(Presenter.ViewHolder, Object)
73         */
74        public void setSizeFromDrawableIntrinsic(boolean sizeFromDrawableIntrinsic) {
75            mSizeFromDrawableIntrinsic = sizeFromDrawableIntrinsic;
76        }
77    }
78
79    /**
80     * Create a View for the Logo, default implementation loads from
81     * {@link R.layout#lb_fullwidth_details_overview_logo}. Subclass may override this method to use
82     * a fixed layout size and change ImageView scaleType. If the layout params is WRAP_CONTENT for
83     * both width and size, the ViewHolder would be using intrinsic size of Drawable in
84     * {@link #onBindViewHolder(Presenter.ViewHolder, Object)}.
85     *
86     * @param parent Parent view.
87     * @return View created for the logo.
88     */
89    public View onCreateView(ViewGroup parent) {
90        return LayoutInflater.from(parent.getContext())
91                .inflate(R.layout.lb_fullwidth_details_overview_logo, parent, false);
92    }
93
94    @Override
95    public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
96        View view = onCreateView(parent);
97        ViewHolder vh = new ViewHolder(view);
98        ViewGroup.LayoutParams lp = view.getLayoutParams();
99        vh.setSizeFromDrawableIntrinsic(lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
100                lp.width == ViewGroup.LayoutParams.WRAP_CONTENT);
101        return vh;
102    }
103
104    /**
105     * Called from {@link FullWidthDetailsOverviewRowPresenter} to setup FullWidthDetailsOverviewRowPresenter
106     * and FullWidthDetailsOverviewRowPresenter.ViewHolder that hosts the logo.
107     * @param viewHolder
108     * @param parentViewHolder
109     * @param parentPresenter
110     */
111    public void setContext(ViewHolder viewHolder,
112            FullWidthDetailsOverviewRowPresenter.ViewHolder parentViewHolder,
113            FullWidthDetailsOverviewRowPresenter parentPresenter) {
114        viewHolder.mParentViewHolder = parentViewHolder;
115        viewHolder.mParentPresenter = parentPresenter;
116    }
117
118    /**
119     * Returns true if the logo view is bound to image. Subclass may override. The default
120     * implementation returns true when {@link DetailsOverviewRow#getImageDrawable()} is not null.
121     * If subclass of DetailsOverviewLogoPresenter manages its own image drawable, it should
122     * override this function to report status correctly and invoke
123     * {@link FullWidthDetailsOverviewRowPresenter#notifyOnBindLogo(FullWidthDetailsOverviewRowPresenter.ViewHolder)}
124     * when image view is bound to the drawable.
125     */
126    public boolean isBoundToImage(ViewHolder viewHolder, DetailsOverviewRow row) {
127        return row != null && row.getImageDrawable() != null;
128    }
129
130    /**
131     * Bind logo View to drawable of DetailsOverviewRow and call notifyOnBindLogo().  The
132     * default implementation assumes the Logo View is an ImageView and change layout size to
133     * intrinsic size of ImageDrawable if {@link ViewHolder#isSizeFromDrawableIntrinsic()} is true.
134     * @param viewHolder ViewHolder to bind.
135     * @param item DetailsOverviewRow object to bind.
136     */
137    @Override
138    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
139        DetailsOverviewRow row = (DetailsOverviewRow) item;
140        ImageView imageView = ((ImageView) viewHolder.view);
141        imageView.setImageDrawable(row.getImageDrawable());
142        if (isBoundToImage((ViewHolder) viewHolder, row)) {
143            ViewHolder vh = (ViewHolder) viewHolder;
144            if (vh.isSizeFromDrawableIntrinsic()) {
145                ViewGroup.LayoutParams lp = imageView.getLayoutParams();
146                lp.width = row.getImageDrawable().getIntrinsicWidth();
147                lp.height = row.getImageDrawable().getIntrinsicHeight();
148                if (imageView.getMaxWidth() > 0 || imageView.getMaxHeight() > 0) {
149                    float maxScaleWidth = 1f;
150                    if (imageView.getMaxWidth() > 0) {
151                        if (lp.width > imageView.getMaxWidth()) {
152                            maxScaleWidth = imageView.getMaxWidth() / (float) lp.width;
153                        }
154                    }
155                    float maxScaleHeight = 1f;
156                    if (imageView.getMaxHeight() > 0) {
157                        if (lp.height > imageView.getMaxHeight()) {
158                            maxScaleHeight = imageView.getMaxHeight() / (float) lp.height;
159                        }
160                    }
161                    float scale = Math.min(maxScaleWidth, maxScaleHeight);
162                    lp.width = (int) (lp.width * scale);
163                    lp.height = (int) (lp.height * scale);
164                }
165                imageView.setLayoutParams(lp);
166            }
167            vh.mParentPresenter.notifyOnBindLogo(vh.mParentViewHolder);
168        }
169    }
170
171    @Override
172    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
173    }
174
175}
176