1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.tv.settings.dialog.old;
18
19import android.animation.Animator;
20import android.os.Bundle;
21import android.view.LayoutInflater;
22import android.view.View;
23import android.view.ViewGroup;
24import android.view.ViewGroup.LayoutParams;
25import android.view.ViewPropertyAnimator;
26import android.view.animation.DecelerateInterpolator;
27
28import com.android.tv.settings.R;
29import com.android.tv.settings.widget.ScrollAdapter;
30import com.android.tv.settings.widget.ScrollAdapterView;
31import com.android.tv.settings.widget.ScrollAdapterView.OnScrollListener;
32
33/**
34 * Fragment which uses a ScrollAdapterView as its basic UI.
35 * <p>
36 * This fragment is meant to be inserted as the action fragment into a {@link DialogActivity}.
37 * <p>
38 * Users can either subclass this or just use listener objects to receive life cycle events.
39 */
40public class BaseScrollAdapterFragment implements OnScrollListener {
41    private int mAnimationDuration;
42    private final LiteFragment mFragment;
43
44    private ScrollAdapter mAdapter;
45    private ScrollAdapterView mScrollAdapterView;
46    private View mSelectorView;
47    private View mSelectedView = null;
48    private volatile boolean mFadedOut = true;
49
50    public BaseScrollAdapterFragment(LiteFragment fragment) {
51        mFragment = fragment;
52    }
53
54    public View onCreateView(LayoutInflater inflater, ViewGroup container,
55            Bundle savedInstanceState) {
56        View v = inflater.inflate(R.layout.settings_list, container, false);
57        mScrollAdapterView = null;
58        return v;
59    }
60
61    public void onViewCreated(View view, Bundle savedInstanceState) {
62        ensureList();
63    }
64
65    public boolean hasCreatedView() {
66        if (mFragment == null || mFragment.getView() == null) {
67            return false;
68        } else {
69            return true;
70        }
71    }
72
73    public ScrollAdapterView getScrollAdapterView() {
74        ensureList();
75        return mScrollAdapterView;
76    }
77
78    public ScrollAdapter getAdapter() {
79        return mAdapter;
80    }
81
82    public void setAdapter(ScrollAdapter adapter) {
83        mAdapter = adapter;
84        if (mScrollAdapterView != null) {
85            mScrollAdapterView.setAdapter(mAdapter);
86        }
87    }
88
89    public void setSelection(int position) {
90        mScrollAdapterView.setSelection(position);
91    }
92
93    public void setSelectionSmooth(int position) {
94        mScrollAdapterView.setSelectionSmooth(position);
95    }
96
97    public int getSelectedItemPosition() {
98        return mScrollAdapterView.getSelectedItemPosition();
99    }
100
101    public void ensureList() {
102        if (mScrollAdapterView != null) {
103            return;
104        }
105        View root = mFragment.getView();
106        if (root == null) {
107            throw new IllegalStateException("Content view not created yet.");
108        }
109        if (root instanceof ScrollAdapterView) {
110            mScrollAdapterView = (ScrollAdapterView) root;
111            mSelectorView = null;
112        } else {
113            mScrollAdapterView = (ScrollAdapterView) root.findViewById(R.id.list);
114            if (mScrollAdapterView == null) {
115                throw new IllegalStateException("No scroll adapter view exists.");
116            }
117            mSelectorView = root.findViewById(R.id.selector);
118        }
119        if (mScrollAdapterView != null) {
120            mScrollAdapterView.requestFocusFromTouch();
121            if (mAdapter != null) {
122                mScrollAdapterView.setAdapter(mAdapter);
123            }
124            if (mSelectorView != null) {
125                mAnimationDuration = mFragment.getActivity()
126                        .getResources().getInteger(R.integer.dialog_animation_duration);
127                mScrollAdapterView.addOnScrollListener(this);
128            }
129        }
130    }
131
132    /**
133     * Sets {@link BaseScrollAdapterFragment#mFadedOut}
134     *
135     * {@link BaseScrollAdapterFragment#mFadedOut} is true, iff
136     * {@link BaseScrollAdapterFragment#mSelectorView} has an alpha of 0
137     * (faded out). If false the view either has an alpha of 1 (visible) or
138     * is in the process of animating.
139     */
140    private class Listener implements Animator.AnimatorListener {
141        private boolean mFadingOut;
142        private boolean mCanceled;
143
144        public Listener(boolean fadingOut) {
145            mFadingOut = fadingOut;
146        }
147
148        @Override
149        public void onAnimationStart(Animator animation) {
150            if(!mFadingOut) {
151                mFadedOut = false;
152            }
153        }
154
155        @Override
156        public void onAnimationEnd(Animator animation) {
157            if (!mCanceled && mFadingOut) {
158                mFadedOut = true;
159            }
160        }
161
162        @Override
163        public void onAnimationCancel(Animator animation) {
164            mCanceled = true;
165        }
166
167        @Override
168        public void onAnimationRepeat(Animator animation) {
169        }
170    }
171
172    // We want to fade in the selector if we've stopped scrolling on it (mainPosition = 0).
173    // If mainPosition is not 0, we want to ensure to dim the selector if we haven't already.
174    // we dim the last highlighted view so that while a user is scrolling, nothing is highlighted.
175    @Override
176    public synchronized void onScrolled(View view, int position, float mainPosition,
177            float secondPosition) {
178        boolean hasFocus = (mainPosition == 0.0);
179        if (hasFocus) {
180            if (view != null) {
181                // The selector starts with a height of 0. In order to scale up
182                // from
183                // 0 we first need the set the height to 1 and scale form there.
184                int selectorHeight = mSelectorView.getHeight();
185                if (selectorHeight == 0) {
186                    LayoutParams lp = mSelectorView.getLayoutParams();
187                    lp.height = selectorHeight = mFragment.getActivity().getResources()
188                            .getDimensionPixelSize(R.dimen.action_fragment_selector_min_height);
189                    mSelectorView.setLayoutParams(lp);
190                }
191                float scaleY = (float) view.getHeight() / selectorHeight;
192                ViewPropertyAnimator animation = mSelectorView.animate()
193                        .alpha(1f)
194                        .setListener(new Listener(false))
195                        .setDuration(mAnimationDuration)
196                        .setInterpolator(new DecelerateInterpolator(2f));
197                if (mFadedOut) {
198                    // selector is completely faded out, so we can just scale
199                    // before fading in.
200                    mSelectorView.setScaleY(scaleY);
201                } else {
202                    // selector is not faded out, so we must animate the scale
203                    // as we fade in.
204                    animation.scaleY(scaleY);
205                }
206                animation.start();
207                mSelectedView = view;
208            } else {
209                LayoutParams lp = mSelectorView.getLayoutParams();
210                lp.height = 0;
211                mSelectorView.setLayoutParams(lp);
212            }
213        } else if (mSelectedView != null) {
214            mSelectorView.animate()
215                    .alpha(0f)
216                    .setDuration(mAnimationDuration)
217                    .setInterpolator(new DecelerateInterpolator(2f))
218                    .setListener(new Listener(true))
219                    .start();
220            mSelectedView = null;
221        }
222    }
223}
224