165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/* 265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Copyright (C) 2014 The Android Open Source Project 365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Licensed under the Apache License, Version 2.0 (the "License"); 565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * you may not use this file except in compliance with the License. 665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * You may obtain a copy of the License at 765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * http://www.apache.org/licenses/LICENSE-2.0 965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 1065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Unless required by applicable law or agreed to in writing, software 1165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * distributed under the License is distributed on an "AS IS" BASIS, 1265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * See the License for the specific language governing permissions and 1465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * limitations under the License. 1565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 1665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepackage com.android.tv.settings.dialog.old; 1865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.animation.Animator; 2065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.animation.AnimatorListenerAdapter; 2165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.animation.ObjectAnimator; 2265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Context; 2365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.res.Resources; 2465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.Bitmap; 2565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.drawable.Drawable; 2665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.media.AudioManager; 2765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.net.Uri; 2865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.text.TextUtils; 2965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.Log; 3065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.TypedValue; 3165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.KeyEvent; 3265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.LayoutInflater; 3365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.View; 3465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.ViewGroup; 3565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.WindowManager; 3665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.animation.DecelerateInterpolator; 3765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.animation.Interpolator; 3865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.BaseAdapter; 3965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.ImageView; 4065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.TextView; 4165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.R; 4365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.BitmapDownloader; 4465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.BitmapDownloader.BitmapCallback; 4565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.BitmapWorkerOptions; 4665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.ScrollAdapter; 4765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.ScrollAdapterBase; 4865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.ScrollAdapterView; 4965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.ScrollAdapterView.OnScrollListener; 5065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.ArrayList; 5265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.List; 5365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/** 5565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Adapter class which creates actions. 5665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 5765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepublic class ActionAdapter extends BaseAdapter implements ScrollAdapter, 5865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane OnScrollListener, View.OnKeyListener, View.OnClickListener { 5965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final String TAG = "ActionAdapter"; 6065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 6165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final boolean DEBUG = false; 6265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 6365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int SELECT_ANIM_DURATION = 100; 6465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int SELECT_ANIM_DELAY = 0; 6565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final float SELECT_ANIM_SELECTED_ALPHA = 0.2f; 6665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final float SELECT_ANIM_UNSELECTED_ALPHA = 1.0f; 6765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final float CHECKMARK_ANIM_UNSELECTED_ALPHA = 0.0f; 6865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final float CHECKMARK_ANIM_SELECTED_ALPHA = 1.0f; 6965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static Integer sDescriptionMaxHeight = null; 7165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // TODO: this constant is only in KLP: update when KLP has a more standard SDK. 7365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int FX_KEYPRESS_INVALID = 9; // AudioManager.FX_KEYPRESS_INVALID; 7465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 7665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Object listening for adapter events. 7765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 7865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public interface Listener { 7965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 8165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Called when the user clicks on an action. 8265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 8365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onActionClicked(Action action); 8465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 8565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public interface OnFocusListener { 8765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 8965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Called when the user focuses on an action. 9065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 9165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onActionFocused(Action action); 9265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 9365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 9465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 9565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Object listening for adapter action select/unselect events. 9665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 9765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public interface OnKeyListener { 9865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 9965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 10065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Called when user finish selecting an action. 10165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 10265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onActionSelect(Action action); 10365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 10465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 10565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Called when user finish unselecting an action. 10665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 10765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onActionUnselect(Action action); 10865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final Context mContext; 11265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final float mUnselectedAlpha; 11365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final float mSelectedTitleAlpha; 11465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final float mDisabledTitleAlpha; 11565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final float mSelectedDescriptionAlpha; 11665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final float mDisabledDescriptionAlpha; 11765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final float mUnselectedDescriptionAlpha; 11865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final float mSelectedChevronAlpha; 11965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final float mDisabledChevronAlpha; 12065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private List<Action> mActions; 12165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private Listener mListener; 12265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private OnFocusListener mOnFocusListener; 12365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private OnKeyListener mOnKeyListener; 12465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private boolean mKeyPressed; 12565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private ScrollAdapterView mScrollAdapterView; 12665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final int mAnimationDuration; 12765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private View mSelectedView = null; 12865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 12965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public ActionAdapter(Context context) { 13065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane super(); 13165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mContext = context; 13265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final Resources res = context.getResources(); 13365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mAnimationDuration = res.getInteger(R.integer.dialog_animation_duration); 13565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mUnselectedAlpha = getFloat(R.dimen.list_item_unselected_text_alpha); 13665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mSelectedTitleAlpha = getFloat(R.dimen.list_item_selected_title_text_alpha); 13865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mDisabledTitleAlpha = getFloat(R.dimen.list_item_disabled_title_text_alpha); 13965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 14065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mSelectedDescriptionAlpha = getFloat(R.dimen.list_item_selected_description_text_alpha); 14165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mUnselectedDescriptionAlpha = getFloat(R.dimen.list_item_unselected_description_text_alpha); 14265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mDisabledDescriptionAlpha = getFloat(R.dimen.list_item_disabled_description_text_alpha); 14365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 14465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mSelectedChevronAlpha = getFloat(R.dimen.list_item_selected_chevron_background_alpha); 14565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mDisabledChevronAlpha = getFloat(R.dimen.list_item_disabled_chevron_background_alpha); 14665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 14765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mActions = new ArrayList<Action>(); 14865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mKeyPressed = false; 14965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 15065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 15165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 15265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void viewRemoved(View view) { 15365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // Do nothing. 15465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 15565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 15665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 15765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public View getScrapView(ViewGroup parent) { 15865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane LayoutInflater inflater = LayoutInflater.from(mContext); 15965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane View view = inflater.inflate(R.layout.settings_list_item, parent, false); 16065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return view; 16165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 16365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 16465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int getCount() { 16565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mActions.size(); 16665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 16865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 16965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public Object getItem(int position) { 17065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mActions.get(position); 17165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 17365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 17465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public long getItemId(int position) { 17565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return position; 17665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 17865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 17965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public boolean hasStableIds() { 18065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return true; 18165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 18265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 18365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 18465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public View getView(int position, View convertView, ViewGroup parent) { 18565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (convertView == null) { 18665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane convertView = getScrapView(parent); 18765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 18865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Action action = mActions.get(position); 18965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TextView title = (TextView) convertView.findViewById(R.id.action_title); 19065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TextView description = (TextView) convertView.findViewById(R.id.action_description); 19165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane description.setText(action.getDescription()); 19265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane description.setVisibility( 19365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TextUtils.isEmpty(action.getDescription()) ? View.GONE : View.VISIBLE); 19465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane title.setText(action.getTitle()); 19565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ImageView checkmarkView = (ImageView) convertView.findViewById(R.id.action_checkmark); 19665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkmarkView.setVisibility(action.isChecked() ? View.VISIBLE : View.INVISIBLE); 19765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 19865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ImageView indicatorView = (ImageView) convertView.findViewById(R.id.action_icon); 19965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setIndicator(indicatorView, action); 20065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 20165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ImageView chevronView = (ImageView) convertView.findViewById(R.id.action_next_chevron); 20265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane chevronView.setVisibility(action.hasNext() ? View.VISIBLE : View.GONE); 20365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 20465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane View chevronBackgroundView = convertView.findViewById(R.id.action_next_chevron_background); 20565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane chevronBackgroundView.setVisibility(action.hasNext() ? View.VISIBLE : View.INVISIBLE); 20665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 20765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final Resources res = convertView.getContext().getResources(); 20865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (action.hasMultilineDescription()) { 20965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane title.setMaxLines(res.getInteger(R.integer.action_title_max_lines)); 21065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane description.setMaxHeight( 21165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane getDescriptionMaxHeight(convertView.getContext(), title, description)); 21265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 21365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane title.setMaxLines(res.getInteger(R.integer.action_title_min_lines)); 21465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane description.setMaxLines( 21565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane res.getInteger(R.integer.action_description_min_lines)); 21665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 21765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 21865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane convertView.setTag(R.id.action_title, action); 21965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane convertView.setOnKeyListener(this); 22065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane convertView.setOnClickListener(this); 22165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane changeFocus(convertView, false /* hasFocus */, false /* shouldAnimate */); 22265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 22365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return convertView; 22465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 22565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 22665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 22765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public ScrollAdapterBase getExpandAdapter() { 22865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 22965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 23065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 23165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void setListener(Listener listener) { 23265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mListener = listener; 23365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 23465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 23565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void setOnFocusListener(OnFocusListener onFocusListener) { 23665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mOnFocusListener = onFocusListener; 23765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 23865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 23965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void setOnKeyListener(OnKeyListener onKeyListener) { 24065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mOnKeyListener = onKeyListener; 24165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 24265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 24365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void addAction(Action action) { 24465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mActions.add(action); 24565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane notifyDataSetChanged(); 24665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 24765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 24865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 24965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Used for serialization only. 25065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 25165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public ArrayList<Action> getActions() { 25265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new ArrayList<Action>(mActions); 25365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 25465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 25565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void setActions(ArrayList<Action> actions) { 25665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane changeFocus(mSelectedView, false /* hasFocus */, false /* shouldAnimate */); 25765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mActions.clear(); 25865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mActions.addAll(actions); 25965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane notifyDataSetChanged(); 26065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 26165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 26265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // We want to highlight a view if we've stopped scrolling on it (mainPosition = 0). 26365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // If mainPosition is not 0, we don't want to do anything with view, but we do want to ensure 26465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // we dim the last highlighted view so that while a user is scrolling, nothing is highlighted. 26565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 26665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onScrolled(View view, int position, float mainPosition, float secondPosition) { 26765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane boolean hasFocus = (mainPosition == 0.0); 26865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (hasFocus) { 26965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (view != null) { 27065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane changeFocus(view, true /* hasFocus */, true /* shouldAniamte */); 27165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mSelectedView = view; 27265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 27365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (mSelectedView != null) { 27465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane changeFocus(mSelectedView, false /* hasFocus */, true /* shouldAniamte */); 27565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mSelectedView = null; 27665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 27765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 27865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 27965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void changeFocus(View v, boolean hasFocus, boolean shouldAnimate) { 28065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (v == null) { 28165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return; 28265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 28365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Action action = (Action) v.getTag(R.id.action_title); 28465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 28565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float titleAlpha = action.isEnabled() && !action.infoOnly() 28665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ? (hasFocus ? mSelectedTitleAlpha : mUnselectedAlpha) : mDisabledTitleAlpha; 28765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float descriptionAlpha = (!hasFocus || action.infoOnly()) ? mUnselectedDescriptionAlpha 28865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane : (action.isEnabled() ? mSelectedDescriptionAlpha : mDisabledDescriptionAlpha); 28965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float chevronAlpha = action.hasNext() && !action.infoOnly() 29065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ? (action.isEnabled() ? mSelectedChevronAlpha : mDisabledChevronAlpha) : 0; 29165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 29265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TextView title = (TextView) v.findViewById(R.id.action_title); 29365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setAlpha(title, shouldAnimate, titleAlpha); 29465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 29565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TextView description = (TextView) v.findViewById(R.id.action_description); 29665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setAlpha(description, shouldAnimate, descriptionAlpha); 29765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 29865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ImageView checkmark = (ImageView) v.findViewById(R.id.action_checkmark); 29965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setAlpha(checkmark, shouldAnimate, titleAlpha); 30065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 30165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ImageView icon = (ImageView) v.findViewById(R.id.action_icon); 30265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setAlpha(icon, shouldAnimate, titleAlpha); 30365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 30465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane View chevronBackground = v.findViewById(R.id.action_next_chevron_background); 30565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setAlpha(chevronBackground, shouldAnimate, chevronAlpha); 30665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 30765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mOnFocusListener != null && hasFocus) { 30865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // We still call onActionFocused so that listeners can clear state if they want. 30965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mOnFocusListener.onActionFocused((Action) v.getTag(R.id.action_title)); 31065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 31165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 31265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 31365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void setIndicator(final ImageView indicatorView, Action action) { 31465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 31565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Drawable indicator = action.getIndicator(mContext); 31665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (indicator != null) { 31765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane indicatorView.setImageDrawable(indicator); 31865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane indicatorView.setVisibility(View.VISIBLE); 31965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 32065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Uri iconUri = action.getIconUri(); 32165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (iconUri != null) { 32265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane indicatorView.setVisibility(View.INVISIBLE); 32365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 32465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane BitmapDownloader.getInstance(mContext).getBitmap(new BitmapWorkerOptions.Builder( 32565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mContext).resource(iconUri) 32665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .width(indicatorView.getLayoutParams().width).build(), 32765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane new BitmapCallback() { 32865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 32965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onBitmapRetrieved(Bitmap bitmap) { 33065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (bitmap != null) { 33165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane indicatorView.setVisibility(View.VISIBLE); 33265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane indicatorView.setImageBitmap(bitmap); 33365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane fadeIn(indicatorView); 33465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 33565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 33665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }); 33765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 33865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane indicatorView.setVisibility(View.GONE); 33965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 34065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 34165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 34265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 34365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void fadeIn(View v) { 34465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane v.setAlpha(0f); 34565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(v, "alpha", 1f); 34665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane alphaAnimator.setDuration(mContext.getResources().getInteger( 34765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane android.R.integer.config_mediumAnimTime)); 34865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane alphaAnimator.start(); 34965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 35065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 35165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void setAlpha(View view, boolean shouldAnimate, float alpha) { 35265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (shouldAnimate) { 35365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane view.animate().alpha(alpha) 35465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .setDuration(mAnimationDuration) 35565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .setInterpolator(new DecelerateInterpolator(2F)) 35665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .start(); 35765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 35865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane view.setAlpha(alpha); 35965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 36065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 36165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 36265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void setScrollAdapterView(ScrollAdapterView scrollAdapterView) { 36365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mScrollAdapterView = scrollAdapterView; 36465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 36565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 36665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 36765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onClick(View v) { 36865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (v != null && v.getWindowToken() != null && mListener != null) { 36965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final Action action = (Action) v.getTag(R.id.action_title); 37065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mListener.onActionClicked(action); 37165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 37265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 37365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 37465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 37565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Now only handles KEYCODE_ENTER and KEYCODE_NUMPAD_ENTER key event. 37665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 37765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 37865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public boolean onKey(View v, int keyCode, KeyEvent event) { 37965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (v == null) { 38065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return false; 38165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 38265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane boolean handled = false; 38365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Action action = (Action) v.getTag(R.id.action_title); 38465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane switch (keyCode) { 38565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.KEYCODE_DPAD_CENTER: 38665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.KEYCODE_NUMPAD_ENTER: 38765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.KEYCODE_BUTTON_X: 38865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.KEYCODE_BUTTON_Y: 38965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.KEYCODE_ENTER: 39065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane AudioManager manager = (AudioManager) v.getContext().getSystemService( 39165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Context.AUDIO_SERVICE); 39265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!action.isEnabled() || action.infoOnly()) { 39365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (v.isSoundEffectsEnabled() && event.getAction() == KeyEvent.ACTION_DOWN) { 39465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane manager.playSoundEffect(FX_KEYPRESS_INVALID); 39565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 39665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return true; 39765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 39865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 39965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane switch (event.getAction()) { 40065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.ACTION_DOWN: 40165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!mKeyPressed) { 40265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mKeyPressed = true; 40365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 40465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (v.isSoundEffectsEnabled()) { 40565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane manager.playSoundEffect(AudioManager.FX_KEY_CLICK); 40665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 40765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 40865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (DEBUG) { 40965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.d(TAG, "Enter Key down"); 41065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 41165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 41265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane prepareAndAnimateView(v, SELECT_ANIM_UNSELECTED_ALPHA, 41365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane SELECT_ANIM_SELECTED_ALPHA, SELECT_ANIM_DURATION, 41465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane SELECT_ANIM_DELAY, null, mKeyPressed); 41565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane handled = true; 41665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 41765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 41865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.ACTION_UP: 41965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mKeyPressed) { 42065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mKeyPressed = false; 42165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 42265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (DEBUG) { 42365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.d(TAG, "Enter Key up"); 42465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 42565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 42665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane prepareAndAnimateView(v, SELECT_ANIM_SELECTED_ALPHA, 42765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane SELECT_ANIM_UNSELECTED_ALPHA, SELECT_ANIM_DURATION, 42865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane SELECT_ANIM_DELAY, null, mKeyPressed); 42965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane handled = true; 43065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 43165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 43265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane default: 43365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 43465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 43565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 43665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane default: 43765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 43865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 43965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return handled; 44065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 44165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 44265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void prepareAndAnimateView(final View v, float initAlpha, float destAlpha, int duration, 44365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int delay, Interpolator interpolator, final boolean pressed) { 44465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (v != null && v.getWindowToken() != null) { 44565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final Action action = (Action) v.getTag(R.id.action_title); 44665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 44765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!pressed) { 44865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane fadeCheckmarks(v, action, duration, delay, interpolator); 44965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 45065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 45165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane v.setAlpha(initAlpha); 45265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane v.setLayerType(View.LAYER_TYPE_HARDWARE, null); 45365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane v.buildLayer(); 45465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane v.animate().alpha(destAlpha).setDuration(duration).setStartDelay(delay); 45565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (interpolator != null) { 45665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane v.animate().setInterpolator(interpolator); 45765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 45865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane v.animate().setListener(new AnimatorListenerAdapter() { 45965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 46065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onAnimationEnd(Animator animation) { 46165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 46265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane v.setLayerType(View.LAYER_TYPE_NONE, null); 46365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (pressed) { 46465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mOnKeyListener != null) { 46565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mOnKeyListener.onActionSelect(action); 46665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 46765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 46865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mOnKeyListener != null) { 46965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mOnKeyListener.onActionUnselect(action); 47065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 47165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mListener != null) { 47265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mListener.onActionClicked(action); 47365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 47465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 47565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 47665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }); 47765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane v.animate().start(); 47865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 47965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 48065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 48165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void fadeCheckmarks(final View v, final Action action, int duration, int delay, 48265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Interpolator interpolator) { 48365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int actionCheckSetId = action.getCheckSetId(); 48465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (actionCheckSetId != Action.NO_CHECK_SET) { 48565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // Find any actions that are checked and are in the same group 48665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // as the selected action. Fade their checkmarks out. 48765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (int i = 0, size = mActions.size(); i < size; i++) { 48865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Action a = mActions.get(i); 48965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (a != action && a.getCheckSetId() == actionCheckSetId && a.isChecked()) { 49065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane a.setChecked(false); 49165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mScrollAdapterView != null) { 49265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane View viewToAnimateOut = mScrollAdapterView.getItemView(i); 49365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (viewToAnimateOut != null) { 49465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final View checkView = viewToAnimateOut.findViewById( 49565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.id.action_checkmark); 49665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkView.animate().alpha(CHECKMARK_ANIM_UNSELECTED_ALPHA) 49765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .setDuration(duration).setStartDelay(delay); 49865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (interpolator != null) { 49965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkView.animate().setInterpolator(interpolator); 50065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 50165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkView.animate().setListener(new AnimatorListenerAdapter() { 50265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 50365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onAnimationEnd(Animator animation) { 50465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkView.setVisibility(View.INVISIBLE); 50565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 50665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }); 50765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 50865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 50965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 51065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 51165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 51265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // If we we'ren't already checked, fade our checkmark in. 51365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!action.isChecked()) { 51465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane action.setChecked(true); 51565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mScrollAdapterView != null) { 51665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final View checkView = v.findViewById(R.id.action_checkmark); 51765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkView.setVisibility(View.VISIBLE); 51865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkView.setAlpha(CHECKMARK_ANIM_UNSELECTED_ALPHA); 51965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkView.animate().alpha(CHECKMARK_ANIM_SELECTED_ALPHA).setDuration(duration) 52065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .setStartDelay(delay); 52165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (interpolator != null) { 52265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkView.animate().setInterpolator(interpolator); 52365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 52465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane checkView.animate().setListener(null); 52565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 52665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 52765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 52865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 52965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 53065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 53165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * @return the max height in pixels the description can be such that the 53265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * action nicely takes up the entire screen. 53365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 53465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static Integer getDescriptionMaxHeight(Context context, TextView title, 53565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TextView description) { 53665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (sDescriptionMaxHeight == null) { 53765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final Resources res = context.getResources(); 53865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final float verticalPadding = res.getDimension(R.dimen.list_item_vertical_padding); 53965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final int titleMaxLines = res.getInteger(R.integer.action_title_max_lines); 54065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final int displayHeight = ((WindowManager) context.getSystemService( 54165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight(); 54265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 54365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // The 2 multiplier on the title height calculation is a conservative 54465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // estimate for font padding which can not be calculated at this stage 54565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // since the view hasn't been rendered yet. 54665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sDescriptionMaxHeight = (int) (displayHeight - 54765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 2 * verticalPadding - 2 * titleMaxLines * title.getLineHeight()); 54865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 54965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return sDescriptionMaxHeight; 55065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 55165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 55265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private float getFloat(int resourceId) { 55365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TypedValue buffer = new TypedValue(); 55465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mContext.getResources().getValue(resourceId, buffer, true); 55565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return buffer.getFloat(); 55665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 55765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane} 558