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 1647520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.support.v17.leanback.R; 1746e7de54775fc37dc51041629c79249e6dae3242Dake Guimport android.support.v17.leanback.graphics.ColorOverlayDimmer; 1847520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View; 19dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Guimport android.view.animation.AccelerateDecelerateInterpolator; 20dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Guimport android.view.animation.Interpolator; 21dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Guimport android.animation.TimeAnimator; 2255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.content.res.Resources; 2346e7de54775fc37dc51041629c79249e6dae3242Dake Guimport static android.support.v17.leanback.widget.FocusHighlight.ZOOM_FACTOR_NONE; 2446e7de54775fc37dc51041629c79249e6dae3242Dake Guimport static android.support.v17.leanback.widget.FocusHighlight.ZOOM_FACTOR_SMALL; 25575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stoutimport static android.support.v17.leanback.widget.FocusHighlight.ZOOM_FACTOR_XSMALL; 2646e7de54775fc37dc51041629c79249e6dae3242Dake Guimport static android.support.v17.leanback.widget.FocusHighlight.ZOOM_FACTOR_MEDIUM; 2746e7de54775fc37dc51041629c79249e6dae3242Dake Guimport static android.support.v17.leanback.widget.FocusHighlight.ZOOM_FACTOR_LARGE; 2847520b68e50572a9775a662410c5aff8300c8784Craig Stout 2947520b68e50572a9775a662410c5aff8300c8784Craig Stout/** 30a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets up the highlighting behavior when an item gains focus. 3147520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 3247520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class FocusHighlightHelper { 3347520b68e50572a9775a662410c5aff8300c8784Craig Stout 34575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout static boolean isValidZoomIndex(int zoomIndex) { 35575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout return zoomIndex == ZOOM_FACTOR_NONE || getResId(zoomIndex) > 0; 36575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout } 37575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout 38575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout private static int getResId(int zoomIndex) { 39575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout switch (zoomIndex) { 40575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout case ZOOM_FACTOR_SMALL: 41575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout return R.fraction.lb_focus_zoom_factor_small; 42575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout case ZOOM_FACTOR_XSMALL: 43575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout return R.fraction.lb_focus_zoom_factor_xsmall; 44575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout case ZOOM_FACTOR_MEDIUM: 45575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout return R.fraction.lb_focus_zoom_factor_medium; 46575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout case ZOOM_FACTOR_LARGE: 47575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout return R.fraction.lb_focus_zoom_factor_large; 48575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout default: 49575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout return 0; 50575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout } 51575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout } 52575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout 53575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout 543c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu static class FocusAnimator implements TimeAnimator.TimeListener { 553c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private final View mView; 563c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private final int mDuration; 573c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private final ShadowOverlayContainer mWrapper; 583c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private final float mScaleDiff; 593c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private float mFocusLevel = 0f; 603c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private float mFocusLevelStart; 613c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private float mFocusLevelDelta; 623c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private final TimeAnimator mAnimator = new TimeAnimator(); 633c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator(); 6446e7de54775fc37dc51041629c79249e6dae3242Dake Gu private final ColorOverlayDimmer mDimmer; 653c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 663c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu void animateFocus(boolean select, boolean immediate) { 673c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu endAnimation(); 683c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu final float end = select ? 1 : 0; 693c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu if (immediate) { 703c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu setFocusLevel(end); 713c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } else if (mFocusLevel != end) { 723c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mFocusLevelStart = mFocusLevel; 733c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mFocusLevelDelta = end - mFocusLevelStart; 743c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mAnimator.start(); 753c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 763c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 773c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 7846e7de54775fc37dc51041629c79249e6dae3242Dake Gu FocusAnimator(View view, float scale, boolean useDimmer, int duration) { 793c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mView = view; 803c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mDuration = duration; 813c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mScaleDiff = scale - 1f; 823c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu if (view instanceof ShadowOverlayContainer) { 833c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mWrapper = (ShadowOverlayContainer) view; 843c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } else { 853c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mWrapper = null; 863c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 873c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mAnimator.setTimeListener(this); 884d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu if (useDimmer) { 8946e7de54775fc37dc51041629c79249e6dae3242Dake Gu mDimmer = ColorOverlayDimmer.createDefault(view.getContext()); 9046e7de54775fc37dc51041629c79249e6dae3242Dake Gu } else { 9146e7de54775fc37dc51041629c79249e6dae3242Dake Gu mDimmer = null; 9246e7de54775fc37dc51041629c79249e6dae3242Dake Gu } 933c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 943c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 953c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu void setFocusLevel(float level) { 963c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mFocusLevel = level; 973c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu float scale = 1f + mScaleDiff * level; 983c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mView.setScaleX(scale); 993c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mView.setScaleY(scale); 1004d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu if (mWrapper != null) { 1014d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu mWrapper.setShadowFocusLevel(level); 1024d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu } else { 10385833087b2288e0f002de6b4ebcbc0564839a217Dake Gu ShadowOverlayHelper.setNoneWrapperShadowFocusLevel(mView, level); 1044d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu } 1054d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu if (mDimmer != null) { 106254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu mDimmer.setActiveLevel(level); 1074d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu int color = mDimmer.getPaint().getColor(); 1084d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu if (mWrapper != null) { 1094d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu mWrapper.setOverlayColor(color); 1104d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu } else { 11185833087b2288e0f002de6b4ebcbc0564839a217Dake Gu ShadowOverlayHelper.setNoneWrapperOverlayColor(mView, color); 1124d14fb53ebf304ad989afbc57baa71cfcafa4e7aDake Gu } 1133c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 1143c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 1153c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 1163c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu float getFocusLevel() { 1173c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu return mFocusLevel; 1183c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 1193c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 1203c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu void endAnimation() { 1213c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mAnimator.end(); 1223c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 1233c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 1243c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu @Override 1253c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { 1263c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu float fraction; 1273c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu if (totalTime >= mDuration) { 1283c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu fraction = 1; 1293c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mAnimator.end(); 1303c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } else { 1313c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu fraction = (float) (totalTime / (double) mDuration); 1323c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 1333c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu if (mInterpolator != null) { 1343c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu fraction = mInterpolator.getInterpolation(fraction); 1353c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 1363c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu setFocusLevel(mFocusLevelStart + fraction * mFocusLevelDelta); 1373c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 1383c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 1393c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 14046e7de54775fc37dc51041629c79249e6dae3242Dake Gu static class BrowseItemFocusHighlight implements FocusHighlightHandler { 14147520b68e50572a9775a662410c5aff8300c8784Craig Stout private static final int DURATION_MS = 150; 14247520b68e50572a9775a662410c5aff8300c8784Craig Stout 143b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout private int mScaleIndex; 14446e7de54775fc37dc51041629c79249e6dae3242Dake Gu private final boolean mUseDimmer; 145b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout 14646e7de54775fc37dc51041629c79249e6dae3242Dake Gu BrowseItemFocusHighlight(int zoomIndex, boolean useDimmer) { 147575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout if (!isValidZoomIndex(zoomIndex)) { 148575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout throw new IllegalArgumentException("Unhandled zoom index"); 14947520b68e50572a9775a662410c5aff8300c8784Craig Stout } 150575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout mScaleIndex = zoomIndex; 151575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout mUseDimmer = useDimmer; 15247520b68e50572a9775a662410c5aff8300c8784Craig Stout } 15347520b68e50572a9775a662410c5aff8300c8784Craig Stout 154575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout private float getScale(Resources res) { 155575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout return mScaleIndex == ZOOM_FACTOR_NONE ? 1f : 156575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout res.getFraction(getResId(mScaleIndex), 1, 1); 157b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout } 158b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout 15946e7de54775fc37dc51041629c79249e6dae3242Dake Gu @Override 16046e7de54775fc37dc51041629c79249e6dae3242Dake Gu public void onItemFocused(View view, boolean hasFocus) { 161dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu view.setSelected(hasFocus); 16246e7de54775fc37dc51041629c79249e6dae3242Dake Gu getOrCreateAnimator(view).animateFocus(hasFocus, false); 16346e7de54775fc37dc51041629c79249e6dae3242Dake Gu } 16446e7de54775fc37dc51041629c79249e6dae3242Dake Gu 16546e7de54775fc37dc51041629c79249e6dae3242Dake Gu @Override 16646e7de54775fc37dc51041629c79249e6dae3242Dake Gu public void onInitializeView(View view) { 16746e7de54775fc37dc51041629c79249e6dae3242Dake Gu getOrCreateAnimator(view).animateFocus(false, true); 16846e7de54775fc37dc51041629c79249e6dae3242Dake Gu } 16946e7de54775fc37dc51041629c79249e6dae3242Dake Gu 17046e7de54775fc37dc51041629c79249e6dae3242Dake Gu private FocusAnimator getOrCreateAnimator(View view) { 171dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu FocusAnimator animator = (FocusAnimator) view.getTag(R.id.lb_focus_animator); 172dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu if (animator == null) { 173575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout animator = new FocusAnimator( 174575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout view, getScale(view.getResources()), mUseDimmer, DURATION_MS); 175dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu view.setTag(R.id.lb_focus_animator, animator); 176892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 17746e7de54775fc37dc51041629c79249e6dae3242Dake Gu return animator; 17847520b68e50572a9775a662410c5aff8300c8784Craig Stout } 17947520b68e50572a9775a662410c5aff8300c8784Craig Stout 18047520b68e50572a9775a662410c5aff8300c8784Craig Stout } 18147520b68e50572a9775a662410c5aff8300c8784Craig Stout 18247520b68e50572a9775a662410c5aff8300c8784Craig Stout /** 183a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets up the focus highlight behavior of a focused item in browse list row. 184575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout * @param zoomIndex One of {@link FocusHighlight#ZOOM_FACTOR_SMALL} 185575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout * {@link FocusHighlight#ZOOM_FACTOR_XSMALL} 186575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout * {@link FocusHighlight#ZOOM_FACTOR_MEDIUM} 187575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout * {@link FocusHighlight#ZOOM_FACTOR_LARGE} 188575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout * {@link FocusHighlight#ZOOM_FACTOR_NONE}. 18946e7de54775fc37dc51041629c79249e6dae3242Dake Gu * @param useDimmer Allow dimming browse item when unselected. 19047520b68e50572a9775a662410c5aff8300c8784Craig Stout * @param adapter adapter of the list row. 19147520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 19246e7de54775fc37dc51041629c79249e6dae3242Dake Gu public static void setupBrowseItemFocusHighlight(ItemBridgeAdapter adapter, int zoomIndex, 19346e7de54775fc37dc51041629c79249e6dae3242Dake Gu boolean useDimmer) { 19446e7de54775fc37dc51041629c79249e6dae3242Dake Gu adapter.setFocusHighlight(new BrowseItemFocusHighlight(zoomIndex, useDimmer)); 19547520b68e50572a9775a662410c5aff8300c8784Craig Stout } 19655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout 19755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout /** 198a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets up the focus highlight behavior of a focused item in header list. 199c16a0e4e812e393f67b0d55a4df5667a967a8e57Dake Gu * @param gridView the header list. 20055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout */ 201a5f765740ef4451374963e6eabd5f587b94ff50eDake Gu public static void setupHeaderItemFocusHighlight(VerticalGridView gridView) { 2023c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu if (gridView.getAdapter() instanceof ItemBridgeAdapter) { 2033c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu ((ItemBridgeAdapter) gridView.getAdapter()) 2043c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu .setFocusHighlight(new HeaderItemFocusHighlight(gridView)); 2053c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 20655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout } 20755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout 20846e7de54775fc37dc51041629c79249e6dae3242Dake Gu static class HeaderItemFocusHighlight implements FocusHighlightHandler { 2093c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private static boolean sInitialized; 2103c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private static float sSelectScale; 2113c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private static int sDuration; 2123c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private BaseGridView mGridView; 21355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout 2143c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu HeaderItemFocusHighlight(BaseGridView gridView) { 2153c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mGridView = gridView; 2163c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu lazyInit(gridView.getContext().getResources()); 2173c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 2183c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 2193c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu private static void lazyInit(Resources res) { 2203c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu if (!sInitialized) { 2213c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu sSelectScale = 22255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout Float.parseFloat(res.getString(R.dimen.lb_browse_header_select_scale)); 2233c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu sDuration = 22455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout Integer.parseInt(res.getString(R.dimen.lb_browse_header_select_duration)); 2253c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu sInitialized = true; 2263c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 2273c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 2283c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 2293c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu class HeaderFocusAnimator extends FocusAnimator { 2303c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 2313c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu ItemBridgeAdapter.ViewHolder mViewHolder; 2323c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu HeaderFocusAnimator(View view, float scale, int duration) { 23346e7de54775fc37dc51041629c79249e6dae3242Dake Gu super(view, scale, false, duration); 2343c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu mViewHolder = (ItemBridgeAdapter.ViewHolder) mGridView.getChildViewHolder(view); 23555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout } 2363c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 2373c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu @Override 2383c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu void setFocusLevel(float level) { 2393c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu Presenter presenter = mViewHolder.getPresenter(); 2403c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu if (presenter instanceof RowHeaderPresenter) { 2413c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu ((RowHeaderPresenter) presenter).setSelectLevel( 2423c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu ((RowHeaderPresenter.ViewHolder) mViewHolder.getViewHolder()), level); 2433c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 2443c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu super.setFocusLevel(level); 2453c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu } 2463c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu 24755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout } 24855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout 24955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout private void viewFocused(View view, boolean hasFocus) { 2503c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu view.setSelected(hasFocus); 2513c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu FocusAnimator animator = (FocusAnimator) view.getTag(R.id.lb_focus_animator); 2523c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu if (animator == null) { 2533c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu animator = new HeaderFocusAnimator(view, sSelectScale, sDuration); 2543c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu view.setTag(R.id.lb_focus_animator, animator); 25555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout } 2563c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu animator.animateFocus(hasFocus, false); 25755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout } 25855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout 25955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout @Override 26062d36d44e03a3dd0632b156615b04563c62e83c1Dake Gu public void onItemFocused(View view, boolean hasFocus) { 26155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout viewFocused(view, hasFocus); 26255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout } 26346e7de54775fc37dc51041629c79249e6dae3242Dake Gu 26446e7de54775fc37dc51041629c79249e6dae3242Dake Gu @Override 26546e7de54775fc37dc51041629c79249e6dae3242Dake Gu public void onInitializeView(View view) { 26646e7de54775fc37dc51041629c79249e6dae3242Dake Gu } 26746e7de54775fc37dc51041629c79249e6dae3242Dake Gu 26855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout } 26947520b68e50572a9775a662410c5aff8300c8784Craig Stout} 270