summaryrefslogtreecommitdiffstats
path: root/src/com/android/mail/ui/ConversationViewProgressController.java
blob: 3f711c1ef5fa3502599a0ae2c07add16e63c0eb1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * Copyright (C) 2013 Google Inc.
 * Licensed to The Android Open Source Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.mail.ui;

import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.app.Fragment;
import android.content.res.Resources;
import android.os.Handler;
import android.view.View;

import com.android.mail.R;
import com.android.mail.utils.Utils;

/**
 * <p>Controller to handle showing and hiding progress in the conversation views.</p>
 * <br>
 * <b>NOTE:</b> This class makes several assumptions about the view hierarchy
 * of the conversation view. Use with care.
 */
public class ConversationViewProgressController {
    private static int sMinDelay = -1;
    private static int sMinShowTime = -1;

    private final Handler mHandler;

    private final Fragment mFragment;

    private long mLoadingShownTime = -1;
    private View mProgressView;
    private View mBackgroundView;

    private final Runnable mDelayedShow;

    public ConversationViewProgressController(Fragment fragment, Handler handler) {
        mFragment = fragment;
        mHandler = handler;

        mDelayedShow = new FragmentRunnable("mDelayedShow", mFragment) {
            @Override
            public void go() {
                mLoadingShownTime = System.currentTimeMillis();
                mProgressView.setVisibility(View.VISIBLE);
            }
        };
    }

    public void instantiateProgressIndicators(View rootView) {
        mBackgroundView = rootView.findViewById(R.id.background_view);
        mProgressView = rootView.findViewById(R.id.loading_progress);
    }

    public void showLoadingStatus(boolean isFragmentUserVisible) {
        if (!isFragmentUserVisible) {
            return;
        }
        if (sMinDelay == -1) {
            Resources res = mFragment.getResources();
            sMinDelay = res.getInteger(R.integer.conversationview_show_loading_delay);
            sMinShowTime = res.getInteger(R.integer.conversationview_min_show_loading);
        }
        // If the loading view isn't already showing, show it and remove any
        // pending calls to show the loading screen.
        mBackgroundView.setVisibility(View.VISIBLE);
        mHandler.removeCallbacks(mDelayedShow);
        mHandler.postDelayed(mDelayedShow, sMinDelay);
    }

    public void dismissLoadingStatus() {
        dismissLoadingStatus(null);
    }

    /**
     * Begin the fade-out animation to hide the Progress overlay, either immediately or after some
     * timeout (to ensure that the progress minimum time elapses).
     *
     * @param doAfter an optional Runnable action to execute after the animation completes
     */
    public void dismissLoadingStatus(final Runnable doAfter) {
        if (mLoadingShownTime == -1) {
            // The runnable hasn't run yet, so just remove it.
            mHandler.removeCallbacks(mDelayedShow);
            dismiss(doAfter);
            return;
        }
        final long diff = Math.abs(System.currentTimeMillis() - mLoadingShownTime);
        if (diff > sMinShowTime) {
            dismiss(doAfter);
        } else {
            mHandler.postDelayed(new FragmentRunnable("dismissLoadingStatus", mFragment) {
                @Override
                public void go() {
                    dismiss(doAfter);
                }
            }, Math.abs(sMinShowTime - diff));
        }
    }

    private void dismiss(final Runnable doAfter) {
        // Reset loading shown time.
        mLoadingShownTime = -1;
        mProgressView.setVisibility(View.GONE);
        if (mBackgroundView.getVisibility() == View.VISIBLE) {
            animateDismiss(doAfter);
        } else {
            if (doAfter != null) {
                doAfter.run();
            }
        }
    }

    private void animateDismiss(final Runnable doAfter) {
        // the animation can only work (and is only worth doing) if this fragment is added
        // reasons it may not be added: fragment is being destroyed, or in the process of being
        // restored
        if (!mFragment.isAdded()) {
            mBackgroundView.setVisibility(View.GONE);
            return;
        }

        Utils.enableHardwareLayer(mBackgroundView);
        final Animator animator = AnimatorInflater.loadAnimator(
                mFragment.getActivity().getApplicationContext(), R.anim.fade_out);
        animator.setTarget(mBackgroundView);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mBackgroundView.setVisibility(View.GONE);
                mBackgroundView.setLayerType(View.LAYER_TYPE_NONE, null);
                if (doAfter != null) {
                    doAfter.run();
                }
            }
        });
        animator.start();
    }
}