FocusHighlightHelper.java revision 739e3805bf2785e6773aede5e2e1643f537305f9
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
16a83005b70853ea52c5d98910762344de16b850a8Tim Kilbournimport android.graphics.drawable.TransitionDrawable;
1747520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.support.v17.leanback.R;
1847520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View;
1955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.content.res.Resources;
2047520b68e50572a9775a662410c5aff8300c8784Craig Stout
21739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport static android.support.v17.leanback.widget.FocusHighlight.ZOOM_FACTOR_NONE;
22739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport static android.support.v17.leanback.widget.FocusHighlight.ZOOM_FACTOR_SMALL;
23739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport static android.support.v17.leanback.widget.FocusHighlight.ZOOM_FACTOR_MEDIUM;
24739e3805bf2785e6773aede5e2e1643f537305f9Craig Stoutimport static android.support.v17.leanback.widget.FocusHighlight.ZOOM_FACTOR_LARGE;
25739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
26739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout
2747520b68e50572a9775a662410c5aff8300c8784Craig Stout/**
2847520b68e50572a9775a662410c5aff8300c8784Craig Stout * Setup the behavior how to highlight when a item gains focus.
2947520b68e50572a9775a662410c5aff8300c8784Craig Stout */
3047520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class FocusHighlightHelper {
3147520b68e50572a9775a662410c5aff8300c8784Craig Stout
32b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    static class BrowseItemFocusHighlight implements FocusHighlight {
3347520b68e50572a9775a662410c5aff8300c8784Craig Stout        private static final int DURATION_MS = 150;
3447520b68e50572a9775a662410c5aff8300c8784Craig Stout
35b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        private static float[] sScaleFactor = new float[4];
36b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
37b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        private int mScaleIndex;
38b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
39b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        BrowseItemFocusHighlight(int zoomIndex) {
40b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout            mScaleIndex = (zoomIndex >= 0 && zoomIndex < sScaleFactor.length) ?
41b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout                    zoomIndex : ZOOM_FACTOR_MEDIUM;
4247520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
4347520b68e50572a9775a662410c5aff8300c8784Craig Stout
44b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        private void lazyInit(Resources resources) {
45b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout            if (sScaleFactor[ZOOM_FACTOR_NONE] == 0f) {
46b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout                sScaleFactor[ZOOM_FACTOR_NONE] = 1f;
47b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout                sScaleFactor[ZOOM_FACTOR_SMALL] =
48b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout                        resources.getFraction(R.fraction.lb_focus_zoom_factor_small, 1, 1);
49b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout                sScaleFactor[ZOOM_FACTOR_MEDIUM] =
50b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout                        resources.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1);
51b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout                sScaleFactor[ZOOM_FACTOR_LARGE] =
52b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout                        resources.getFraction(R.fraction.lb_focus_zoom_factor_large, 1, 1);
5347520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
5447520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
5547520b68e50572a9775a662410c5aff8300c8784Craig Stout
56b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        private float getScale(View view) {
57b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout            lazyInit(view.getResources());
58b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout            return sScaleFactor[mScaleIndex];
59b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        }
60b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
6147520b68e50572a9775a662410c5aff8300c8784Craig Stout        private void viewFocused(View view, boolean hasFocus) {
6247520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (hasFocus) {
6347520b68e50572a9775a662410c5aff8300c8784Craig Stout                final float scale = getScale(view);
6447520b68e50572a9775a662410c5aff8300c8784Craig Stout                view.animate().scaleX(scale).scaleY(scale).setDuration(DURATION_MS);
6547520b68e50572a9775a662410c5aff8300c8784Craig Stout            } else {
6647520b68e50572a9775a662410c5aff8300c8784Craig Stout                view.animate().scaleX(1f).scaleY(1f).setDuration(DURATION_MS);
6747520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
68892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            if (view instanceof ListRowCardWrapper) {
69892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                ListRowCardWrapper wrapper = (ListRowCardWrapper) view;
70892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                if (wrapper.mShadowNormal != null) {
71892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                    if (hasFocus) {
72892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                        wrapper.mShadowFocused.animate().alpha(1f)
73892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                                .setDuration(DURATION_MS).start();
74892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                        wrapper.mShadowNormal.animate().alpha(0f)
75892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                                .setDuration(DURATION_MS).start();
76892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                    } else {
77892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                        wrapper.mShadowFocused.animate().alpha(0f)
78892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                                .setDuration(DURATION_MS).start();
79892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                        wrapper.mShadowNormal.animate().alpha(1f)
80892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                                .setDuration(DURATION_MS).start();
81892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                    }
82892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                }
83892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            }
8447520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
8547520b68e50572a9775a662410c5aff8300c8784Craig Stout
8647520b68e50572a9775a662410c5aff8300c8784Craig Stout        @Override
8762d36d44e03a3dd0632b156615b04563c62e83c1Dake Gu        public void onItemFocused(View view, boolean hasFocus) {
8847520b68e50572a9775a662410c5aff8300c8784Craig Stout            viewFocused(view, hasFocus);
8947520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
9047520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
9147520b68e50572a9775a662410c5aff8300c8784Craig Stout
9255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    private static HeaderItemFocusHighlight sHeaderItemFocusHighlight =
9355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout            new HeaderItemFocusHighlight();
9455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
95a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    private static ActionItemFocusHighlight sActionItemFocusHighlight =
96a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            new ActionItemFocusHighlight();
97a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
9847520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
9947520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Setup the focus highlight behavior of a focused item in browse list row.
10047520b68e50572a9775a662410c5aff8300c8784Craig Stout     * @param adapter  adapter of the list row.
10147520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
102b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public static void setupBrowseItemFocusHighlight(ItemBridgeAdapter adapter, int zoomIndex) {
103b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        adapter.setFocusHighlight(new BrowseItemFocusHighlight(zoomIndex));
10447520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
10555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
10655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    /**
10755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout     * Setup the focus highlight behavior of a focused item in header list.
10855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout     * @param adapter  adapter of the header list.
10955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout     */
11055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    public static void setupHeaderItemFocusHighlight(ItemBridgeAdapter adapter) {
11155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        adapter.setFocusHighlight(sHeaderItemFocusHighlight);
11255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
11355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
114a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    /**
115a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn     * Setup the focus highlight behavior of a focused item in an action list.
116a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn     * @param adapter  adapter of the action list.
117a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn     */
118a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    public static void setupActionItemFocusHighlight(ItemBridgeAdapter adapter) {
119a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        adapter.setFocusHighlight(sActionItemFocusHighlight);
120a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    }
121a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
122a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    private static class HeaderItemFocusHighlight implements FocusHighlight {
12355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        private boolean mInitialized;
12455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        private float mSelectScale;
12555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        private float mUnselectAlpha;
12655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        private int mDuration;
12755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
12855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        private void initializeDimensions(Resources res) {
12955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout            if (!mInitialized) {
13055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                mSelectScale =
13155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                        Float.parseFloat(res.getString(R.dimen.lb_browse_header_select_scale));
13255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                mUnselectAlpha =
13355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                        Float.parseFloat(res.getString(R.dimen.lb_browse_header_unselect_alpha));
13455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                mDuration =
13555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                        Integer.parseInt(res.getString(R.dimen.lb_browse_header_select_duration));
13655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                mInitialized = true;
13755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout            }
13855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        }
13955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
14055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        private void viewFocused(View view, boolean hasFocus) {
14155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout            initializeDimensions(view.getResources());
14255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout            if (hasFocus) {
14355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                view.animate().scaleX(mSelectScale).scaleY(mSelectScale)
14455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                        .alpha(1f)
14555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                        .setDuration(mDuration);
14655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout            } else {
14755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                view.animate().scaleX(1f).scaleY(1f)
14855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                        .alpha(mUnselectAlpha)
14955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout                        .setDuration(mDuration);
15055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout            }
15155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        }
15255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
15355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        @Override
15462d36d44e03a3dd0632b156615b04563c62e83c1Dake Gu        public void onItemFocused(View view, boolean hasFocus) {
15555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout            viewFocused(view, hasFocus);
15655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        }
15755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
158a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
159a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    private static class ActionItemFocusHighlight implements FocusHighlight {
160a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        private boolean mInitialized;
161a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        private int mDuration;
162a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
163a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        private void initializeDimensions(Resources res) {
164a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            if (!mInitialized) {
165a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn                mDuration = Integer.parseInt(res.getString(R.dimen.lb_details_overview_action_select_duration));
166a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            }
167a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        }
168a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
169a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        @Override
17062d36d44e03a3dd0632b156615b04563c62e83c1Dake Gu        public void onItemFocused(View view, boolean hasFocus) {
171a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            initializeDimensions(view.getResources());
172a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            TransitionDrawable td = (TransitionDrawable) view.getBackground();
173a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            if (hasFocus) {
174a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn                td.startTransition(mDuration);
175a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            } else {
176a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn                td.reverseTransition(mDuration);
177a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            }
178a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        }
179a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    }
18047520b68e50572a9775a662410c5aff8300c8784Craig Stout}
181