147520b68e50572a9775a662410c5aff8300c8784Craig Stout/*
247520b68e50572a9775a662410c5aff8300c8784Craig Stout * Copyright (C) 2014 The Android Open Source Project
347520b68e50572a9775a662410c5aff8300c8784Craig Stout *
447520b68e50572a9775a662410c5aff8300c8784Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
547520b68e50572a9775a662410c5aff8300c8784Craig Stout * in compliance with the License. You may obtain a copy of the License at
647520b68e50572a9775a662410c5aff8300c8784Craig Stout *
747520b68e50572a9775a662410c5aff8300c8784Craig Stout * http://www.apache.org/licenses/LICENSE-2.0
847520b68e50572a9775a662410c5aff8300c8784Craig Stout *
947520b68e50572a9775a662410c5aff8300c8784Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License
1047520b68e50572a9775a662410c5aff8300c8784Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1147520b68e50572a9775a662410c5aff8300c8784Craig Stout * or implied. See the License for the specific language governing permissions and limitations under
1247520b68e50572a9775a662410c5aff8300c8784Craig Stout * the License.
1347520b68e50572a9775a662410c5aff8300c8784Craig Stout */
1447520b68e50572a9775a662410c5aff8300c8784Craig Stoutpackage android.support.v17.leanback.widget;
1547520b68e50572a9775a662410c5aff8300c8784Craig Stout
164cd4cce277571385f4d1a56d5348578c38368cbeCraig Stoutimport android.graphics.Paint;
174cf79b1c4d38a190317961891f9fd052836710fdCraig Stoutimport android.support.v17.leanback.R;
18268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stoutimport android.view.LayoutInflater;
1947520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View;
2047520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.ViewGroup;
214cd4cce277571385f4d1a56d5348578c38368cbeCraig Stoutimport android.widget.TextView;
2247520b68e50572a9775a662410c5aff8300c8784Craig Stout
2347520b68e50572a9775a662410c5aff8300c8784Craig Stout/**
24a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * RowHeaderPresenter provides a default presentation for {@link HeaderItem} using a
25a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * {@link RowHeaderView}. If a subclass creates its own view, the subclass must also override
26cb13a318e577e14461eb008071dddf762847de42Dake Gu * {@link #onSelectLevelChanged(ViewHolder)}.
2747520b68e50572a9775a662410c5aff8300c8784Craig Stout */
2847520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class RowHeaderPresenter extends Presenter {
2947520b68e50572a9775a662410c5aff8300c8784Craig Stout
30268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    private final int mLayoutResourceId;
314cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private final Paint mFontMeasurePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
32ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    private boolean mNullItemVisibilityGone;
338ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    private final boolean mAnimateSelect;
34268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
35268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    public RowHeaderPresenter() {
36268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout        this(R.layout.lb_row_header);
37268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    }
38268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
39268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    /**
40268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout     * @hide
41268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout     */
42268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    public RowHeaderPresenter(int layoutResourceId) {
438ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        this(layoutResourceId, true);
448ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
458ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
468ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    /**
478ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     * @hide
488ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     */
498ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    public RowHeaderPresenter(int layoutResourceId, boolean animateSelect) {
50268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout        mLayoutResourceId = layoutResourceId;
518ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        mAnimateSelect = animateSelect;
52268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    }
53268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
54ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    /**
55ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout     * Optionally sets the view visibility to {@link View#GONE} when bound to null.
56ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout     */
57ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    public void setNullItemVisibilityGone(boolean nullItemVisibilityGone) {
58ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        mNullItemVisibilityGone = nullItemVisibilityGone;
59ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    }
60ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout
61ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    /**
62ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout     * Returns true if the view visibility is set to {@link View#GONE} when bound to null.
63ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout     */
64ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    public boolean isNullItemVisibilityGone() {
65ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        return mNullItemVisibilityGone;
66ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    }
67ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout
68a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout    /**
69a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * A ViewHolder for the RowHeaderPresenter.
70a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     */
7147520b68e50572a9775a662410c5aff8300c8784Craig Stout    public static class ViewHolder extends Presenter.ViewHolder {
72cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        float mSelectLevel;
73cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        int mOriginalTextColor;
74268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout        float mUnselectAlpha;
75268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
7647520b68e50572a9775a662410c5aff8300c8784Craig Stout        public ViewHolder(View view) {
7747520b68e50572a9775a662410c5aff8300c8784Craig Stout            super(view);
7847520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
79cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        public final float getSelectLevel() {
80cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            return mSelectLevel;
81cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
8247520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
8347520b68e50572a9775a662410c5aff8300c8784Craig Stout
8447520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
8547520b68e50572a9775a662410c5aff8300c8784Craig Stout    public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
86268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout        RowHeaderView headerView = (RowHeaderView) LayoutInflater.from(parent.getContext())
87268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout                .inflate(mLayoutResourceId, parent, false);
88268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
89cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        ViewHolder viewHolder = new ViewHolder(headerView);
90cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        viewHolder.mOriginalTextColor = headerView.getCurrentTextColor();
91268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout        viewHolder.mUnselectAlpha = parent.getResources().getFraction(
92268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout                R.fraction.lb_browse_header_unselect_alpha, 1, 1);
938ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAnimateSelect) {
948ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            setSelectLevel(viewHolder, 0);
958ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
96cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return viewHolder;
9747520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
9847520b68e50572a9775a662410c5aff8300c8784Craig Stout
9947520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
10047520b68e50572a9775a662410c5aff8300c8784Craig Stout    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
101ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        HeaderItem headerItem = item == null ? null : ((Row) item).getHeaderItem();
102ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        if (headerItem == null) {
103ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout            ((RowHeaderView) viewHolder.view).setText(null);
104ac30644710e427c77b9d1f20ae385590bdac6c60Dake Gu            viewHolder.view.setContentDescription(null);
105ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout            if (mNullItemVisibilityGone) {
106ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout                viewHolder.view.setVisibility(View.GONE);
10747520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
108ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        } else {
109ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout            viewHolder.view.setVisibility(View.VISIBLE);
110ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout            ((RowHeaderView) viewHolder.view).setText(headerItem.getName());
111ac30644710e427c77b9d1f20ae385590bdac6c60Dake Gu            viewHolder.view.setContentDescription(headerItem.getContentDescription());
11247520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
11347520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
11447520b68e50572a9775a662410c5aff8300c8784Craig Stout
11547520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
11647520b68e50572a9775a662410c5aff8300c8784Craig Stout    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
117ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        ((RowHeaderView) viewHolder.view).setText(null);
1188ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAnimateSelect) {
1198ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            setSelectLevel((ViewHolder) viewHolder, 0);
1208ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
12147520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
122cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
123a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout    /**
124a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the select level.
125a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     */
126cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public final void setSelectLevel(ViewHolder holder, float selectLevel) {
127cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        holder.mSelectLevel = selectLevel;
128cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        onSelectLevelChanged(holder);
129cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
130cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
131a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout    /**
132a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Called when the select level changes.  The default implementation sets the alpha on the view.
133a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     */
134cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    protected void onSelectLevelChanged(ViewHolder holder) {
1358ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAnimateSelect) {
1368ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            holder.view.setAlpha(holder.mUnselectAlpha + holder.mSelectLevel *
1378ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu                    (1f - holder.mUnselectAlpha));
1388ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
139cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
1404cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
1414cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    /**
1424cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout     * Returns the space (distance in pixels) below the baseline of the
1434cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout     * text view, if one exists; otherwise, returns 0.
1444cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout     */
1454cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    public int getSpaceUnderBaseline(ViewHolder holder) {
1464cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        int space = holder.view.getPaddingBottom();
1474cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (holder.view instanceof TextView) {
1484cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            space += (int) getFontDescent((TextView) holder.view, mFontMeasurePaint);
1494cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
1504cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        return space;
1514cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
1524cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
1534cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    protected static float getFontDescent(TextView textView, Paint fontMeasurePaint) {
1544cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (fontMeasurePaint.getTextSize() != textView.getTextSize()) {
1554cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            fontMeasurePaint.setTextSize(textView.getTextSize());
1564cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
1574cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (fontMeasurePaint.getTypeface() != textView.getTypeface()) {
1584cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            fontMeasurePaint.setTypeface(textView.getTypeface());
1594cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
1604cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        return fontMeasurePaint.descent();
1614cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
1624cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout}
163