ConversationPhotoTeaserView.java revision f45e0e7f65eb421fc5c2acf7bb76a714e12dc68b
1package com.android.mail.ui;
2
3import android.animation.Animator;
4import android.animation.ObjectAnimator;
5import android.animation.Animator.AnimatorListener;
6import android.app.LoaderManager;
7import android.content.Context;
8import android.content.res.Resources;
9import android.util.AttributeSet;
10import android.view.View;
11import android.view.animation.DecelerateInterpolator;
12import android.widget.FrameLayout;
13import android.widget.ImageView;
14import android.widget.LinearLayout;
15import android.widget.TextView;
16
17import com.android.mail.R;
18import com.android.mail.analytics.Analytics;
19import com.android.mail.browse.ConversationCursor;
20import com.android.mail.preferences.MailPrefs;
21import com.android.mail.providers.Folder;
22import com.android.mail.utils.Utils;
23
24/**
25 * A teaser to introduce people to the contact photo check boxes
26 */
27public class ConversationPhotoTeaserView extends FrameLayout
28        implements ConversationSpecialItemView, SwipeableItemView {
29    private static int sScrollSlop = 0;
30    private static int sShrinkAnimationDuration;
31
32    private final MailPrefs mMailPrefs;
33    private AnimatedAdapter mAdapter;
34
35    private View mSwipeableContent;
36
37    private boolean mShown;
38    private int mAnimatedHeight = -1;
39    private boolean mNeedLayout;
40    private int mTextTop;
41
42    private View mTeaserRightEdge;
43    /** Whether we are on a tablet device or not */
44    private final boolean mTabletDevice;
45    /** When in conversation mode, true if the list is hidden */
46    private final boolean mListCollapsible;
47
48    public ConversationPhotoTeaserView(final Context context) {
49        this(context, null);
50    }
51
52    public ConversationPhotoTeaserView(final Context context, final AttributeSet attrs) {
53        this(context, attrs, -1);
54    }
55
56    public ConversationPhotoTeaserView(
57            final Context context, final AttributeSet attrs, final int defStyle) {
58        super(context, attrs, defStyle);
59
60        final Resources resources = context.getResources();
61
62        synchronized (ConversationPhotoTeaserView.class) {
63            if (sScrollSlop == 0) {
64                sScrollSlop = resources.getInteger(R.integer.swipeScrollSlop);
65                sShrinkAnimationDuration = resources.getInteger(
66                        R.integer.shrink_animation_duration);
67            }
68        }
69
70        mMailPrefs = MailPrefs.get(context);
71
72        mNeedLayout = true;
73
74        mTabletDevice = Utils.useTabletUI(resources);
75        mListCollapsible = resources.getBoolean(R.bool.list_collapsible);
76    }
77
78    @Override
79    protected void onFinishInflate() {
80        mSwipeableContent = findViewById(R.id.swipeable_content);
81
82        findViewById(R.id.dismiss_button).setOnClickListener(new OnClickListener() {
83            @Override
84            public void onClick(View v) {
85                dismiss();
86            }
87        });
88
89        mTeaserRightEdge = findViewById(R.id.teaser_right_edge);
90    }
91
92    @Override
93    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
94        super.onLayout(changed, left, top, right, bottom);
95
96        final TextView text = (TextView) findViewById(R.id.text);
97        final ImageView arrow = (ImageView) findViewById(R.id.arrow);
98
99        // We post to avoid calling layout within layout
100        arrow.post(new Runnable() {
101            @Override
102            public void run() {
103
104                // The text top is changed when we move the arrow, so we need to
105                // do multiple passes
106                int textTop = text.getTop();
107                if (mNeedLayout || textTop != mTextTop) {
108                    mNeedLayout = false;
109                    mTextTop = textTop;
110
111                    final int lineHeight = text.getLineHeight();
112                    final LinearLayout.LayoutParams arrowParams = (LinearLayout.LayoutParams) arrow
113                            .getLayoutParams();
114                    arrowParams.topMargin = mTextTop + lineHeight / 2;
115                    arrow.setLayoutParams(arrowParams);
116                }
117                arrow.setVisibility(View.VISIBLE);
118            }
119        });
120    }
121
122    @Override
123    public void onUpdate(String account, Folder folder, ConversationCursor cursor) {
124        // Do nothing
125    }
126
127    @Override
128    public void onGetView() {
129        // Do nothing
130    }
131
132    @Override
133    public boolean getShouldDisplayInList() {
134        // show if 1) sender images are enabled 2) there are items
135        mShown = shouldShowSenderImage() && !mAdapter.isEmpty()
136                && !mMailPrefs.isConversationPhotoTeaserAlreadyShown();
137        return mShown;
138    }
139
140    @Override
141    public int getPosition() {
142        return 0;
143    }
144
145    @Override
146    public void setAdapter(AnimatedAdapter adapter) {
147        mAdapter = adapter;
148    }
149
150    @Override
151    public void bindLoaderManager(LoaderManager loaderManager) {
152    }
153
154    @Override
155    public void cleanup() {
156    }
157
158    @Override
159    public void onConversationSelected() {
160        // DO NOTHING
161    }
162
163    @Override
164    public void onCabModeEntered() {
165        dismiss();
166    }
167
168    @Override
169    public void onCabModeExited() {
170        // Do nothing
171    }
172
173    @Override
174    public boolean acceptsUserTaps() {
175        // No, we don't allow user taps.
176        return false;
177    }
178
179    @Override
180    public void dismiss() {
181        setDismissed();
182        startDestroyAnimation();
183    }
184
185    private void setDismissed() {
186        if (mShown) {
187            mMailPrefs.setConversationPhotoTeaserAlreadyShown();
188            mShown = false;
189            Analytics.getInstance().sendEvent("list_swipe", "photo_teaser", null, 0);
190        }
191    }
192
193    protected boolean shouldShowSenderImage() {
194        return mMailPrefs.getShowSenderImages();
195    }
196
197    @Override
198    public SwipeableView getSwipeableView() {
199        return SwipeableView.from(mSwipeableContent);
200    }
201
202    @Override
203    public boolean canChildBeDismissed() {
204        return true;
205    }
206
207    @Override
208    public float getMinAllowScrollDistance() {
209        return sScrollSlop;
210    }
211
212    private void startDestroyAnimation() {
213        final int start = getHeight();
214        final int end = 0;
215        mAnimatedHeight = start;
216        final ObjectAnimator heightAnimator =
217                ObjectAnimator.ofInt(this, "animatedHeight", start, end);
218        heightAnimator.setInterpolator(new DecelerateInterpolator(2.0f));
219        heightAnimator.setDuration(sShrinkAnimationDuration);
220        heightAnimator.addListener(new AnimatorListener() {
221            @Override
222            public void onAnimationStart(final Animator animation) {
223                // Do nothing
224            }
225
226            @Override
227            public void onAnimationRepeat(final Animator animation) {
228                // Do nothing
229            }
230
231            @Override
232            public void onAnimationEnd(final Animator animation) {
233                // We should no longer exist, so notify the adapter
234                mAdapter.notifyDataSetChanged();
235            }
236
237            @Override
238            public void onAnimationCancel(final Animator animation) {
239                // Do nothing
240            }
241        });
242        heightAnimator.start();
243    }
244
245    /**
246     * This method is used by the animator.  It is explicitly kept in proguard.flags to prevent it
247     * from being removed, inlined, or obfuscated.
248     * Edit ./packages/apps/UnifiedEmail/proguard.flags
249     * In the future, we want to use @Keep
250     */
251    public void setAnimatedHeight(final int height) {
252        mAnimatedHeight = height;
253        requestLayout();
254    }
255
256    @Override
257    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
258        if (Utils.getDisplayListRightEdgeEffect(mTabletDevice, mListCollapsible,
259                mAdapter.getViewMode())) {
260            mTeaserRightEdge.setVisibility(VISIBLE);
261        } else {
262            mTeaserRightEdge.setVisibility(GONE);
263        }
264
265        if (mAnimatedHeight == -1) {
266            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
267        } else {
268            setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mAnimatedHeight);
269        }
270    }
271}
272