com.google.android.apps.iosched.ui.MyScheduleFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.google.android.apps.iosched.ui.MyScheduleFragment.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.google.android.apps.iosched.ui;

import com.google.android.apps.iosched.R;
import com.google.android.apps.iosched.provider.ScheduleContract;
import com.google.android.apps.iosched.ui.tablet.SessionsVendorsMultiPaneActivity;
import com.google.android.apps.iosched.ui.widget.SimpleSectionedListAdapter;
import com.google.android.apps.iosched.util.ParserUtils;
import com.google.android.apps.iosched.util.SessionsHelper;
import com.google.android.apps.iosched.util.UIUtils;
import com.google.android.apps.iosched.util.actionmodecompat.ActionMode;

import com.actionbarsherlock.app.SherlockListFragment;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.BaseColumns;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

import static com.google.android.apps.iosched.util.LogUtils.LOGW;
import static com.google.android.apps.iosched.util.LogUtils.makeLogTag;

/**
 * A fragment that shows the user's customized schedule, including sessions that she has chosen,
 * and common conference items such as keynote sessions, lunch breaks, after hours party, etc.
 */
public class MyScheduleFragment extends SherlockListFragment
        implements LoaderManager.LoaderCallbacks<Cursor>, ActionMode.Callback {

    private static final String TAG = makeLogTag(MyScheduleFragment.class);

    private SimpleSectionedListAdapter mAdapter;
    private MyScheduleAdapter mScheduleAdapter;
    private SparseArray<String> mLongClickedItemData;
    private View mLongClickedView;
    private ActionMode mActionMode;
    private boolean mScrollToNow;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // The MyScheduleAdapter is wrapped in a SimpleSectionedListAdapter so that
        // we can show list headers separating out the different days of the conference
        // (Wednesday/Thursday/Friday).
        mScheduleAdapter = new MyScheduleAdapter(getActivity());
        mAdapter = new SimpleSectionedListAdapter(getActivity(), R.layout.list_item_schedule_header,
                mScheduleAdapter);
        setListAdapter(mAdapter);

        if (savedInstanceState == null) {
            mScrollToNow = true;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_list_with_empty_container, container,
                false);
        inflater.inflate(R.layout.empty_waiting_for_sync, (ViewGroup) root.findViewById(android.R.id.empty), true);
        root.setBackgroundColor(Color.WHITE);
        ListView listView = (ListView) root.findViewById(android.R.id.list);
        listView.setItemsCanFocus(true);
        listView.setCacheColorHint(Color.WHITE);
        listView.setSelector(android.R.color.transparent);
        //listView.setEmptyView(root.findViewById(android.R.id.empty));
        return root;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // In support library r8, calling initLoader for a fragment in a
        // FragmentPagerAdapter in the fragment's onCreate may cause the same LoaderManager to be
        // dealt to multiple fragments because their mIndex is -1 (haven't been added to the
        // activity yet). Thus, we do this in onActivityCreated.
        getLoaderManager().initLoader(0, null, this);
    }

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

            Loader<Cursor> loader = getLoaderManager().getLoader(0);
            if (loader != null) {
                loader.forceLoad();
            }
        }
    };

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        activity.getContentResolver().registerContentObserver(ScheduleContract.Sessions.CONTENT_URI, true,
                mObserver);
    }

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

    // LoaderCallbacks
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle data) {
        return new CursorLoader(getActivity(), ScheduleContract.Blocks.CONTENT_URI, BlocksQuery.PROJECTION, null,
                null, ScheduleContract.Blocks.DEFAULT_SORT);
    }

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

        long currentTime = UIUtils.getCurrentTime(getActivity());
        int firstNowPosition = ListView.INVALID_POSITION;

        List<SimpleSectionedListAdapter.Section> sections = new ArrayList<SimpleSectionedListAdapter.Section>();
        cursor.moveToFirst();
        long previousBlockStart = -1;
        long blockStart, blockEnd;
        while (!cursor.isAfterLast()) {
            blockStart = cursor.getLong(BlocksQuery.BLOCK_START);
            blockEnd = cursor.getLong(BlocksQuery.BLOCK_END);
            if (!UIUtils.isSameDay(previousBlockStart, blockStart)) {
                sections.add(new SimpleSectionedListAdapter.Section(cursor.getPosition(),
                        DateUtils.formatDateTime(getActivity(), blockStart, DateUtils.FORMAT_ABBREV_MONTH
                                | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY)));
            }
            if (mScrollToNow && firstNowPosition == ListView.INVALID_POSITION
            // if we're currently in this block, or we're not in a block
            // and this
            // block is in the future, then this is the scroll position
                    && ((blockStart < currentTime && currentTime < blockEnd) || blockStart > currentTime)) {
                firstNowPosition = cursor.getPosition();
            }
            previousBlockStart = blockStart;
            cursor.moveToNext();
        }

        mScheduleAdapter.changeCursor(cursor);

        SimpleSectionedListAdapter.Section[] dummy = new SimpleSectionedListAdapter.Section[sections.size()];
        mAdapter.setSections(sections.toArray(dummy));

        if (mScrollToNow && firstNowPosition != ListView.INVALID_POSITION) {
            firstNowPosition = mAdapter.positionToSectionedPosition(firstNowPosition);
            getListView().setSelectionFromTop(firstNowPosition,
                    getResources().getDimensionPixelSize(R.dimen.list_scroll_top_offset));
            mScrollToNow = false;
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    }

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        SessionsHelper helper = new SessionsHelper(getActivity());
        String title = mLongClickedItemData.get(BlocksQuery.STARRED_SESSION_TITLE);
        String hashtags = mLongClickedItemData.get(BlocksQuery.STARRED_SESSION_HASHTAGS);
        String url = mLongClickedItemData.get(BlocksQuery.STARRED_SESSION_URL);
        boolean handled = false;
        int itemId = item.getItemId();
        if (itemId == R.id.menu_map) {
            String roomId = mLongClickedItemData.get(BlocksQuery.STARRED_SESSION_ROOM_ID);
            helper.startMapActivity(roomId);
            handled = true;
        } else if (itemId == R.id.menu_star) {
            String sessionId = mLongClickedItemData.get(BlocksQuery.STARRED_SESSION_ID);
            Uri sessionUri = ScheduleContract.Sessions.buildSessionUri(sessionId);
            helper.setSessionStarred(sessionUri, false, title);
            handled = true;
        } else if (itemId == R.id.menu_share) {
            // On ICS+ devices, we normally won't reach this as ShareActionProvider will handle
            // sharing.
            helper.shareSession(getActivity(), R.string.share_template, title, hashtags, url);
            handled = true;
        } else if (itemId == R.id.menu_social_stream) {
            helper.startSocialStream(hashtags);
            handled = true;
        } else {
            LOGW(TAG, "Unknown action taken");
        }
        mActionMode.finish();
        return handled;
    }

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.sessions_context, menu);
        MenuItem starMenuItem = menu.findItem(R.id.menu_star);
        starMenuItem.setTitle(R.string.description_remove_schedule);
        starMenuItem.setIcon(R.drawable.ic_action_remove_schedule);
        return true;
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        mActionMode = null;
        if (mLongClickedView != null) {
            UIUtils.setActivatedCompat(mLongClickedView, false);
        }
    }

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false;
    }

    /**
     * A list adapter that shows schedule blocks as list items. It handles a number of different
     * cases, such as empty blocks where the user has not chosen a session, blocks with conflicts
     * (i.e. multiple sessions chosen), non-session blocks, etc.
     */
    private class MyScheduleAdapter extends CursorAdapter {

        public MyScheduleAdapter(Context context) {
            super(context, null, false);
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            return getActivity().getLayoutInflater().inflate(R.layout.list_item_schedule_block, parent, false);
        }

        @Override
        public void bindView(View view, Context context, final Cursor cursor) {
            final String type = cursor.getString(BlocksQuery.BLOCK_TYPE);

            final String blockId = cursor.getString(BlocksQuery.BLOCK_ID);
            final String blockTitle = cursor.getString(BlocksQuery.BLOCK_TITLE);
            final long blockStart = cursor.getLong(BlocksQuery.BLOCK_START);
            final long blockEnd = cursor.getLong(BlocksQuery.BLOCK_END);
            final String blockMeta = cursor.getString(BlocksQuery.BLOCK_META);
            final String blockTimeString = UIUtils.formatBlockTimeString(blockStart, blockEnd, context);

            final TextView timeView = (TextView) view.findViewById(R.id.block_time);
            final TextView titleView = (TextView) view.findViewById(R.id.block_title);
            final TextView subtitleView = (TextView) view.findViewById(R.id.block_subtitle);
            final ImageButton extraButton = (ImageButton) view.findViewById(R.id.extra_button);
            final View primaryTouchTargetView = view.findViewById(R.id.list_item_middle_container);

            final Resources res = getResources();

            String subtitle;

            boolean isLiveStreamed = false;
            primaryTouchTargetView.setOnLongClickListener(null);
            UIUtils.setActivatedCompat(primaryTouchTargetView, false);

            if (ParserUtils.BLOCK_TYPE_SESSION.equals(type) || ParserUtils.BLOCK_TYPE_CODE_LAB.equals(type)) {
                final int numStarredSessions = cursor.getInt(BlocksQuery.NUM_STARRED_SESSIONS);
                final String starredSessionId = cursor.getString(BlocksQuery.STARRED_SESSION_ID);
                View.OnClickListener allSessionsListener = new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        final Uri sessionsUri = ScheduleContract.Blocks.buildSessionsUri(blockId);
                        final Intent intent = new Intent(Intent.ACTION_VIEW, sessionsUri);
                        intent.putExtra(Intent.EXTRA_TITLE, blockTimeString);
                        startActivity(intent);
                    }
                };

                if (numStarredSessions == 0) {
                    // 0 sessions starred
                    titleView.setText(getString(R.string.schedule_empty_slot_title_template,
                            TextUtils.isEmpty(blockTitle) ? "" : (" " + blockTitle.toLowerCase())));
                    titleView.setTextColor(res.getColorStateList(R.color.body_text_1_positive));
                    subtitle = getString(R.string.schedule_empty_slot_subtitle);
                    extraButton.setVisibility(View.GONE);

                    primaryTouchTargetView.setOnClickListener(allSessionsListener);

                } else if (numStarredSessions == 1) {
                    // exactly 1 session starred
                    final String starredSessionTitle = cursor.getString(BlocksQuery.STARRED_SESSION_TITLE);
                    titleView.setText(starredSessionTitle);
                    titleView.setTextColor(res.getColorStateList(R.color.body_text_1));
                    subtitle = cursor.getString(BlocksQuery.STARRED_SESSION_ROOM_NAME);
                    if (subtitle == null) {
                        // TODO: remove this WAR for API not returning rooms for code labs
                        subtitle = getString(starredSessionTitle.contains("Code Lab") ? R.string.codelab_room
                                : R.string.unknown_room);
                    }
                    isLiveStreamed = !TextUtils
                            .isEmpty(cursor.getString(BlocksQuery.STARRED_SESSION_LIVESTREAM_URL));
                    extraButton.setVisibility(View.VISIBLE);
                    extraButton.setOnClickListener(allSessionsListener);
                    if (mLongClickedItemData != null && mActionMode != null && mLongClickedItemData
                            .get(BlocksQuery.STARRED_SESSION_ID, "").equals(starredSessionId)) {
                        UIUtils.setActivatedCompat(primaryTouchTargetView, true);
                        mLongClickedView = primaryTouchTargetView;
                    }

                    primaryTouchTargetView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            final Uri sessionUri = ScheduleContract.Sessions.buildSessionUri(starredSessionId);
                            final Intent intent = new Intent(Intent.ACTION_VIEW, sessionUri);
                            intent.putExtra(SessionsVendorsMultiPaneActivity.EXTRA_MASTER_URI,
                                    ScheduleContract.Blocks.buildSessionsUri(blockId));
                            intent.putExtra(Intent.EXTRA_TITLE, blockTimeString);
                            startActivity(intent);
                        }
                    });

                    primaryTouchTargetView.setOnLongClickListener(new OnLongClickListener() {
                        @Override
                        public boolean onLongClick(View v) {
                            if (mActionMode != null) {
                                // CAB already displayed, ignore
                                return true;
                            }
                            mLongClickedView = primaryTouchTargetView;
                            String hashtags = cursor.getString(BlocksQuery.STARRED_SESSION_HASHTAGS);
                            String url = cursor.getString(BlocksQuery.STARRED_SESSION_URL);
                            String roomId = cursor.getString(BlocksQuery.STARRED_SESSION_ROOM_ID);
                            mLongClickedItemData = new SparseArray<String>();
                            mLongClickedItemData.put(BlocksQuery.STARRED_SESSION_ID, starredSessionId);
                            mLongClickedItemData.put(BlocksQuery.STARRED_SESSION_TITLE, starredSessionTitle);
                            mLongClickedItemData.put(BlocksQuery.STARRED_SESSION_HASHTAGS, hashtags);
                            mLongClickedItemData.put(BlocksQuery.STARRED_SESSION_URL, url);
                            mLongClickedItemData.put(BlocksQuery.STARRED_SESSION_ROOM_ID, roomId);
                            mActionMode = ActionMode.start(getActivity(), MyScheduleFragment.this);
                            UIUtils.setActivatedCompat(primaryTouchTargetView, true);
                            return true;
                        }
                    });

                } else {
                    // 2 or more sessions starred
                    titleView.setText(getString(R.string.schedule_conflict_title, numStarredSessions));
                    titleView.setTextColor(res.getColorStateList(R.color.body_text_1));
                    subtitle = getString(R.string.schedule_conflict_subtitle);
                    extraButton.setVisibility(View.VISIBLE);
                    extraButton.setOnClickListener(allSessionsListener);

                    primaryTouchTargetView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            final Uri sessionsUri = ScheduleContract.Blocks.buildStarredSessionsUri(blockId);
                            final Intent intent = new Intent(Intent.ACTION_VIEW, sessionsUri);
                            intent.putExtra(Intent.EXTRA_TITLE, blockTimeString);
                            startActivity(intent);
                        }
                    });
                }

                subtitleView.setTextColor(res.getColorStateList(R.color.body_text_2));
                primaryTouchTargetView.setEnabled(true);

            } else if (ParserUtils.BLOCK_TYPE_KEYNOTE.equals(type)) {
                final String starredSessionId = cursor.getString(BlocksQuery.STARRED_SESSION_ID);
                final String starredSessionTitle = cursor.getString(BlocksQuery.STARRED_SESSION_TITLE);

                long currentTimeMillis = UIUtils.getCurrentTime(context);
                boolean past = (currentTimeMillis > blockEnd && currentTimeMillis < UIUtils.CONFERENCE_END_MILLIS);
                boolean present = !past && (currentTimeMillis >= blockStart);
                boolean canViewStream = present && UIUtils.hasHoneycomb();

                isLiveStreamed = true;
                titleView.setTextColor(canViewStream ? res.getColorStateList(R.color.body_text_1)
                        : res.getColorStateList(R.color.body_text_disabled));
                subtitleView.setTextColor(canViewStream ? res.getColorStateList(R.color.body_text_2)
                        : res.getColorStateList(R.color.body_text_disabled));
                subtitle = getString(R.string.keynote_room);

                titleView.setText(starredSessionTitle);
                extraButton.setVisibility(View.GONE);
                primaryTouchTargetView.setEnabled(canViewStream);
                primaryTouchTargetView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        final Uri sessionUri = ScheduleContract.Sessions.buildSessionUri(starredSessionId);
                        Intent livestreamIntent = new Intent(Intent.ACTION_VIEW, sessionUri);
                        livestreamIntent.setClass(getActivity(), SessionLivestreamActivity.class);
                        startActivity(livestreamIntent);
                    }
                });

            } else {
                titleView.setTextColor(res.getColorStateList(R.color.body_text_disabled));
                subtitleView.setTextColor(res.getColorStateList(R.color.body_text_disabled));
                subtitle = blockMeta;
                titleView.setText(blockTitle);
                extraButton.setVisibility(View.GONE);
                primaryTouchTargetView.setEnabled(false);
                primaryTouchTargetView.setOnClickListener(null);
            }

            timeView.setText(DateUtils.formatDateTime(context, blockStart,
                    DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_12HOUR));

            // Show past/present/future and livestream status for this block.
            UIUtils.updateTimeAndLivestreamBlockUI(context, blockStart, blockEnd, isLiveStreamed, view, titleView,
                    subtitleView, subtitle);
        }
    }

    private interface BlocksQuery {

        String[] PROJECTION = { BaseColumns._ID, ScheduleContract.Blocks.BLOCK_ID,
                ScheduleContract.Blocks.BLOCK_TITLE, ScheduleContract.Blocks.BLOCK_START,
                ScheduleContract.Blocks.BLOCK_END, ScheduleContract.Blocks.BLOCK_TYPE,
                ScheduleContract.Blocks.BLOCK_META, ScheduleContract.Blocks.SESSIONS_COUNT,
                ScheduleContract.Blocks.NUM_STARRED_SESSIONS, ScheduleContract.Blocks.STARRED_SESSION_ID,
                ScheduleContract.Blocks.STARRED_SESSION_TITLE, ScheduleContract.Blocks.STARRED_SESSION_ROOM_NAME,
                ScheduleContract.Blocks.STARRED_SESSION_ROOM_ID, ScheduleContract.Blocks.STARRED_SESSION_HASHTAGS,
                ScheduleContract.Blocks.STARRED_SESSION_URL,
                ScheduleContract.Blocks.STARRED_SESSION_LIVESTREAM_URL, };

        int _ID = 0;
        int BLOCK_ID = 1;
        int BLOCK_TITLE = 2;
        int BLOCK_START = 3;
        int BLOCK_END = 4;
        int BLOCK_TYPE = 5;
        int BLOCK_META = 6;
        int SESSIONS_COUNT = 7;
        int NUM_STARRED_SESSIONS = 8;
        int STARRED_SESSION_ID = 9;
        int STARRED_SESSION_TITLE = 10;
        int STARRED_SESSION_ROOM_NAME = 11;
        int STARRED_SESSION_ROOM_ID = 12;
        int STARRED_SESSION_HASHTAGS = 13;
        int STARRED_SESSION_URL = 14;
        int STARRED_SESSION_LIVESTREAM_URL = 15;
    }
}