com.conferenceengineer.android.iosched.ui.WhatsOnFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.conferenceengineer.android.iosched.ui.WhatsOnFragment.java

Source

/*
 * Copyright 2012 Google Inc.
 *
 * 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.conferenceengineer.android.iosched.ui;

import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.TextView;

import com.conferenceengineer.android.iosched.Config;
import com.conferenceengineer.android.iosched.conference686.R;
import com.conferenceengineer.android.iosched.provider.ScheduleContract.Announcements;
import com.conferenceengineer.android.iosched.util.TimeUtils;
import com.conferenceengineer.android.iosched.util.UIUtils;

/**
 * A fragment used in {@link HomeActivity} that shows either a countdown,
 * Announcements, or 'thank you' text, at different times (before/during/after
 * the conference).
 */
public class WhatsOnFragment extends Fragment implements LoaderCallbacks<Cursor> {
    private static final int ANNOUNCEMENTS_LOADER_ID = 0;
    private static final int ANNOUNCEMENTS_CYCLE_INTERVAL_MILLIS = 6000;

    private Handler mHandler = new Handler();

    private TextView mCountdownTextView;
    private ViewGroup mRootView;
    private View mAnnouncementView;
    private Cursor mAnnouncementsCursor;
    private String mLatestAnnouncementId;
    private LayoutInflater mInflater;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mInflater = inflater;
        mRootView = (ViewGroup) inflater.inflate(R.layout.fragment_whats_on, container);
        refresh();
        return mRootView;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mHandler.removeCallbacksAndMessages(null);
        getActivity().getContentResolver().unregisterContentObserver(mObserver);
    }

    private void refresh() {
        mHandler.removeCallbacksAndMessages(null);
        mRootView.removeAllViews();

        final long currentTimeMillis = UIUtils.getCurrentTime(getActivity());

        // Show Loading... and load the view corresponding to the current state
        if (currentTimeMillis < Config.CONFERENCE_START_MILLIS) {
            setupBefore();
        } else if (currentTimeMillis > Config.CONFERENCE_END_MILLIS) {
            setupAfter();
        } else {
            setupDuring();
        }
    }

    private void setupBefore() {
        // Before conference, show countdown.
        mCountdownTextView = (TextView) mInflater.inflate(R.layout.whats_on_countdown, mRootView, false);
        mRootView.addView(mCountdownTextView);
        mHandler.post(mCountdownRunnable);
    }

    private void setupAfter() {
        // After conference, show canned text.
        if (getResources().getBoolean(R.bool.has_conference_feedback_enabled)) {
            mInflater.inflate(R.layout.whats_on_feedback, mRootView, true);
            mRootView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent feedbackIntent = new Intent(Intent.ACTION_VIEW);
                    feedbackIntent.setData(Uri.parse(Config.FEEDBACK_URL));
                    startActivity(feedbackIntent);
                }
            });
        } else {
            mInflater.inflate(R.layout.whats_on_thank_you, mRootView, true);
        }
    }

    private void setupDuring() {
        // Start background query to load announcements
        getLoaderManager().initLoader(ANNOUNCEMENTS_LOADER_ID, null, this);
        getActivity().getContentResolver().registerContentObserver(Announcements.CONTENT_URI, true, mObserver);
    }

    /**
     * Event that updates countdown timer. Posts itself again to
     * {@link #mHandler} to continue updating time.
     */
    private Runnable mCountdownRunnable = new Runnable() {
        public void run() {
            int remainingSec = (int) Math.max(0,
                    (Config.CONFERENCE_START_MILLIS - UIUtils.getCurrentTime(getActivity())) / 1000);
            final boolean conferenceStarted = remainingSec == 0;

            if (conferenceStarted) {
                // Conference started while in countdown mode, switch modes and
                // bail on future countdown updates.
                mHandler.postDelayed(new Runnable() {
                    public void run() {
                        refresh();
                    }
                }, 100);
                return;
            }

            final int secs = remainingSec % 86400;
            final int days = remainingSec / 86400;
            final String str;
            if (days == 0) {
                str = getResources().getString(R.string.whats_on_countdown_title_0,
                        DateUtils.formatElapsedTime(secs));
            } else {
                str = getResources().getQuantityString(R.plurals.whats_on_countdown_title, days, days,
                        DateUtils.formatElapsedTime(secs));
            }
            mCountdownTextView.setText(str);

            // Repost ourselves to keep updating countdown
            mHandler.postDelayed(mCountdownRunnable, 1000);
        }
    };

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(getActivity(), Announcements.CONTENT_URI, AnnouncementsQuery.PROJECTION, null, null,
                Announcements.DEFAULT_SORT);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        if (getActivity() == null) {
            return;
        }

        if (cursor != null && cursor.getCount() > 0) {
            // Need to always set this because original gets unset in onLoaderReset
            mAnnouncementsCursor = cursor;
            cursor.moveToFirst();
            // Only update announcements if there's a new one
            String latestAnnouncementId = cursor.getString(AnnouncementsQuery.ANNOUNCEMENT_ID);
            if (!latestAnnouncementId.equals(mLatestAnnouncementId)) {
                mHandler.removeCallbacks(mCycleAnnouncementsRunnable);
                mLatestAnnouncementId = latestAnnouncementId;
                showAnnouncements();
            }
        } else {
            mHandler.removeCallbacks(mCycleAnnouncementsRunnable);
            showNoAnnouncements();
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mAnnouncementsCursor = null;
    }

    /**
     * Show the the announcements
     */
    private void showAnnouncements() {
        mAnnouncementsCursor.moveToFirst();

        ViewGroup announcementsRootView = (ViewGroup) mInflater.inflate(R.layout.whats_on_announcements, mRootView,
                false);
        mAnnouncementView = announcementsRootView.findViewById(R.id.announcement_container);

        // Begin cycling in announcements
        mHandler.post(mCycleAnnouncementsRunnable);

        final View moreButton = announcementsRootView.findViewById(R.id.extra_button);
        moreButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(getActivity(), AnnouncementsActivity.class));
            }
        });

        mRootView.removeAllViews();
        mRootView.addView(announcementsRootView);
    }

    private Runnable mCycleAnnouncementsRunnable = new Runnable() {
        @Override
        public void run() {
            // First animate the current announcement out
            final int animationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
            final int height = mAnnouncementView.getHeight();
            TranslateAnimation anim = new TranslateAnimation(0, 0, 0, height);
            anim.setDuration(animationDuration);
            anim.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationEnd(Animation animation) {
                    // Set the announcement data
                    TextView titleView = (TextView) mAnnouncementView.findViewById(R.id.announcement_title);
                    TextView agoView = (TextView) mAnnouncementView.findViewById(R.id.announcement_ago);
                    titleView.setText(mAnnouncementsCursor.getString(AnnouncementsQuery.ANNOUNCEMENT_TITLE));

                    long date = mAnnouncementsCursor.getLong(AnnouncementsQuery.ANNOUNCEMENT_DATE);
                    String when = TimeUtils.getTimeAgo(date, getActivity());
                    agoView.setText(when);

                    final String url = mAnnouncementsCursor.getString(AnnouncementsQuery.ANNOUNCEMENT_URL);
                    mAnnouncementView.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            Intent announcementIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                            announcementIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                            try {
                                startActivity(announcementIntent);
                            } catch (ActivityNotFoundException ignored) {
                            }
                        }
                    });

                    int nextPosition = (mAnnouncementsCursor.getPosition() + 1) % mAnnouncementsCursor.getCount();
                    mAnnouncementsCursor.moveToPosition(nextPosition);

                    // Animate the announcement in
                    TranslateAnimation anim = new TranslateAnimation(0, 0, height, 0);
                    anim.setDuration(animationDuration);
                    mAnnouncementView.startAnimation(anim);

                    mHandler.postDelayed(mCycleAnnouncementsRunnable,
                            ANNOUNCEMENTS_CYCLE_INTERVAL_MILLIS + animationDuration);
                }

                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
            mAnnouncementView.startAnimation(anim);
        }
    };

    /**
     * Show a placeholder message
     */
    private void showNoAnnouncements() {
        mRootView.removeAllViews();
        mInflater.inflate(R.layout.empty_announcements, mRootView, true);
    }

    private ContentObserver mObserver = new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange) {
            if (getActivity() == null) {
                return;
            }

            getLoaderManager().restartLoader(ANNOUNCEMENTS_LOADER_ID, null, WhatsOnFragment.this);
        }
    };

    private interface AnnouncementsQuery {
        String[] PROJECTION = { Announcements.ANNOUNCEMENT_ID, Announcements.ANNOUNCEMENT_TITLE,
                Announcements.ANNOUNCEMENT_DATE, Announcements.ANNOUNCEMENT_URL, };

        int ANNOUNCEMENT_ID = 0;
        int ANNOUNCEMENT_TITLE = 1;
        int ANNOUNCEMENT_DATE = 2;
        int ANNOUNCEMENT_URL = 3;
    }
}