com.google.samples.apps.iosched.map.MapInfoFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.google.samples.apps.iosched.map.MapInfoFragment.java

Source

/*
 * Copyright 2015 Google Inc. All rights reserved.
 *
 * 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.samples.apps.iosched.map;

import com.google.samples.apps.iosched.R;
import com.google.samples.apps.iosched.map.util.SingleSessionLoader;
import com.google.samples.apps.iosched.map.util.OverviewSessionLoader;
import com.google.samples.apps.iosched.map.util.MarkerModel;
import com.google.samples.apps.iosched.map.util.SessionLoader;
import com.google.samples.apps.iosched.model.ScheduleHelper;
import com.google.samples.apps.iosched.util.MapUtils;
import com.google.samples.apps.iosched.util.TimeUtils;
import com.google.samples.apps.iosched.util.UIUtils;

import android.app.Activity;
import android.app.Fragment;
import android.app.LoaderManager;
import android.content.Context;
import android.content.Loader;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * Displays information about the map.
 * This includes a list of sessions that are directly loaded by this fragment.
 */
public abstract class MapInfoFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {

    private static final int QUERY_TOKEN_SESSION_ROOM = 0x1;
    private static final int QUERY_TOKEN_SUBTITLE = 0x2;
    private static final String QUERY_ARG_ROOMID = "roomid";
    private static final String QUERY_ARG_ROOMTITLE = "roomtitle";
    private static final String QUERY_ARG_ROOMTYPE = "roomicon";

    protected TextView mTitle;
    protected TextView mSubtitle;
    protected ImageView mIcon;

    protected RecyclerView mList;

    protected Callback mCallback = sDummyCallback;

    private static Callback sDummyCallback = new Callback() {
        @Override
        public void onInfoSizeChanged(int left, int top, int right, int bottom) {
        }

        @Override
        public void onSessionClicked(String id) {
        }
    };

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        if (!(activity instanceof Callback)) {
            throw new ClassCastException("Activity must implement fragment's callback.");
        }

        mCallback = (Callback) activity;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mCallback = sDummyCallback;
    }

    @Nullable
    @Override
    public abstract View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);

    @Nullable
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState, int layout) {
        View root = inflater.inflate(layout, container, false);

        mTitle = (TextView) root.findViewById(R.id.map_info_title);
        mSubtitle = (TextView) root.findViewById(R.id.map_info_subtitle);
        mIcon = (ImageView) root.findViewById(R.id.map_info_icon);
        mIcon.setColorFilter(getResources().getColor(R.color.my_schedule_icon_default));
        mList = (RecyclerView) root.findViewById(R.id.map_info_list);
        final Context context = mList.getContext();
        mList.addItemDecoration(new DividerDecoration(context));
        mList.setLayoutManager(new LinearLayoutManager(context));
        return root;
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        if (id != QUERY_TOKEN_SESSION_ROOM && id != QUERY_TOKEN_SUBTITLE) {
            return null;
        }

        final long time = TimeUtils.getCurrentTime(getActivity());
        final String roomId = args.getString(QUERY_ARG_ROOMID);
        final String roomTitle = args.getString(QUERY_ARG_ROOMTITLE);
        final int roomType = args.getInt(QUERY_ARG_ROOMTYPE);

        if (id == QUERY_TOKEN_SESSION_ROOM) {
            return new OverviewSessionLoader(getActivity(), roomId, roomTitle, roomType, time);
        } else if (id == QUERY_TOKEN_SUBTITLE) {
            return new SingleSessionLoader(getActivity(), roomId, roomTitle, roomType);
        }
        return null;
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        if (getActivity() == null) {
            return;
        }
        switch (loader.getId()) {
        case QUERY_TOKEN_SESSION_ROOM: {
            SessionLoader sessionLoader = (SessionLoader) loader;
            showSessionList(sessionLoader.getRoomTitle(), sessionLoader.getRoomType(), cursor);
            break;
        }
        case QUERY_TOKEN_SUBTITLE: {
            SessionLoader sessionLoader = (SessionLoader) loader;
            showSessionSubtitle(sessionLoader.getRoomTitle(), sessionLoader.getRoomType(), cursor);
        }
        }
    }

    /**
     * Creates a new instance depending of the form factor of the device.
     * For tablets, creates an {@link com.google.samples.apps.iosched.map.InlineInfoFragment},
     * for other form factors a {@link com.google.samples.apps.iosched.map.SlideableInfoFragment}.
     *
     * @see com.google.samples.apps.iosched.util.UIUtils#isTablet(android.content.Context)
     */
    public static MapInfoFragment newInstace(Context c) {
        if (UIUtils.isTablet(c)) {
            return InlineInfoFragment.newInstance();
        } else {
            return SlideableInfoFragment.newInstance();
        }
    }

    private void showSessionList(String roomTitle, int roomType, Cursor sessions) {
        if (sessions == null || sessions.isAfterLast()) {
            onSessionLoadingFailed(roomTitle, roomType);
            return;
        }

        onSessionsLoaded(roomTitle, roomType, sessions);
        mList.setAdapter(new SessionAdapter(getActivity(), sessions, MapUtils.hasInfoSessionListIcons(roomType),
                mOnClickListener));
    }

    private void showSessionSubtitle(String roomTitle, int roomType, Cursor sessions) {
        if (sessions == null || sessions.isAfterLast()) {
            onSessionLoadingFailed(roomTitle, roomType);
            return;
        }
        sessions.moveToFirst();

        final String title = roomTitle;
        final String subtitle = sessions.getString(SingleSessionLoader.Query.SESSION_ABSTRACT);

        setHeader(MapUtils.getRoomIcon(roomType), title, subtitle);
        mList.setVisibility(View.GONE);

        onRoomSubtitleLoaded(title, roomType, subtitle);
    }

    /**
     * Called when the subtitle has been loaded for a room.
     */
    protected void onRoomSubtitleLoaded(String roomTitle, int roomType, String subTitle) {

    }

    /**
     * Called when the session list is about to be loaded for a new room.
     */
    protected void onSessionListLoading(String roomId, String roomTitle) {
        // No default behavior
    }

    /**
     * Prepares and starts a SessionLoader for the specified query token.
     */
    private void loadSessions(String roomId, String roomTitle, int roomType, int queryToken) {
        setHeader(MapUtils.getRoomIcon(roomType), roomTitle, null);
        onSessionListLoading(roomId, roomTitle);

        // Load the following sessions for this room
        LoaderManager lm = getLoaderManager();
        Bundle args = new Bundle();
        args.putString(QUERY_ARG_ROOMID, roomId);
        args.putString(QUERY_ARG_ROOMTITLE, roomTitle);
        args.putInt(QUERY_ARG_ROOMTYPE, roomType);
        lm.restartLoader(queryToken, args, this);
    }

    /**
     * Called when the abstract of the first session in this room is to be used as the subtitle.
     */
    public void showFirstSessionTitle(String roomId, String roomTitle, int roomType) {
        loadSessions(roomId, roomTitle, roomType, QUERY_TOKEN_SUBTITLE);
    }

    /**
     * Called when a session list is to be displayed and has to be loaded.
     */
    public void showSessionList(String roomId, String roomTitle, int roomType) {
        loadSessions(roomId, roomTitle, roomType, QUERY_TOKEN_SESSION_ROOM);
    }

    protected void onSessionsLoaded(String roomTitle, int roomType, Cursor cursor) {
        setHeader(MapUtils.getRoomIcon(roomType), roomTitle, null);
        mList.setVisibility(View.VISIBLE);
    }

    protected void onSessionLoadingFailed(String roomTitle, int roomType) {
        setHeader(MapUtils.getRoomIcon(roomType), roomTitle, null);
        mList.setVisibility(View.GONE);
    }

    public void showVenue() {
        setHeader(MapUtils.getRoomIcon(MarkerModel.TYPE_VENUE), R.string.map_venue_name,
                R.string.map_venue_address);
        mList.setVisibility(View.GONE);
    }

    protected void setHeader(int icon, int title, int subTitle) {
        mIcon.setImageResource(icon);

        if (title != 0) {
            mTitle.setText(title);
            mTitle.setVisibility(View.VISIBLE);
        } else {
            mTitle.setVisibility(View.GONE);
        }

        if (subTitle != 0) {
            mSubtitle.setText(subTitle);
            mSubtitle.setVisibility(View.VISIBLE);
        } else {
            mSubtitle.setVisibility(View.GONE);
        }

    }

    private void setHeader(int icon, String title, String subTitle) {
        mIcon.setImageResource(icon);

        if (title != null && !title.isEmpty()) {
            mTitle.setText(title);
            mTitle.setVisibility(View.VISIBLE);
        } else {
            mTitle.setVisibility(View.GONE);
        }

        if (subTitle != null && !subTitle.isEmpty()) {
            mSubtitle.setText(subTitle);
            mSubtitle.setVisibility(View.VISIBLE);
        } else {
            mSubtitle.setVisibility(View.GONE);
        }
    }

    public void showTitleOnly(int roomType, String title) {
        setHeader(MapUtils.getRoomIcon(roomType), title, null);
        mList.setVisibility(View.GONE);
    }

    public abstract void hide();

    public abstract boolean isExpanded();

    public abstract void minimize();

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

    }

    interface Callback {

        public void onInfoSizeChanged(int left, int top, int right, int bottom);

        public void onSessionClicked(String id);
    }

    private View.OnClickListener mOnClickListener = new View.OnClickListener() {

        @Override
        public void onClick(final View v) {
            String sessionId = (String) v.getTag(R.id.tag_session_id);
            if (sessionId != null) {
                mCallback.onSessionClicked(sessionId);
            }
        }

    };

    private static class DividerDecoration extends RecyclerView.ItemDecoration {

        private final Paint mPaint = new Paint();
        private final int mHeight;

        public DividerDecoration(Context context) {
            final Resources resources = context.getResources();
            mPaint.setColor(ResourcesCompat.getColor(resources, R.color.divider, context.getTheme()));
            mHeight = resources.getDimensionPixelSize(R.dimen.divider_height);
        }

        @Override
        public void getItemOffsets(final Rect outRect, final View view, final RecyclerView parent,
                final RecyclerView.State state) {
            outRect.set(0, 0, 0, mHeight);
        }

        @Override
        public void onDraw(final Canvas c, final RecyclerView parent, final RecyclerView.State state) {
            int width = parent.getWidth();
            for (int i = 0, count = parent.getChildCount(); i < count; i++) {
                View child = parent.getChildAt(i);
                int bottom = child.getBottom();
                c.drawRect(0, bottom, width, bottom + mHeight, mPaint);
            }
        }
    }

    /**
     * Adapter that displays a list of sessions.
     * This includes its title, time slot and icon.
     */
    private static class SessionAdapter extends RecyclerView.Adapter<ItemHolder> {

        private final StringBuilder mStringBuilder = new StringBuilder();

        private final Context mContext;

        private final Cursor mCursor;

        private final boolean mDisplayIcons;

        private final View.OnClickListener mListener;

        public SessionAdapter(Context context, Cursor cursor, boolean displayIcons, View.OnClickListener listener) {
            mContext = context;
            mCursor = cursor;
            mDisplayIcons = displayIcons;
            mListener = listener;
        }

        public String getSessionIdAtPosition(int position) {
            if (mCursor.moveToPosition(position)) {
                return mCursor.getString(OverviewSessionLoader.Query.SESSION_ID);
            } else {
                return null;
            }
        }

        @Override
        public ItemHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
            final ItemHolder holder = new ItemHolder(LayoutInflater.from(mContext), parent);
            holder.image.setVisibility(mDisplayIcons ? View.VISIBLE : View.INVISIBLE);
            holder.itemView.setOnClickListener(mListener);
            return holder;
        }

        @Override
        public void onBindViewHolder(final ItemHolder holder, final int position) {
            mCursor.moveToPosition(position);
            final String title = mCursor.getString(OverviewSessionLoader.Query.SESSION_TITLE);
            final String sessionId = mCursor.getString(OverviewSessionLoader.Query.SESSION_ID);
            final long blockStart = mCursor.getLong(OverviewSessionLoader.Query.SESSION_START);
            final long blockEnd = mCursor.getLong(OverviewSessionLoader.Query.SESSION_END);
            final String sessionTag = mCursor.getString(OverviewSessionLoader.Query.SESSION_TAGS);
            final int sessionType = ScheduleHelper.detectSessionType(sessionTag);
            final String text = UIUtils.formatIntervalTimeString(blockStart, blockEnd, mStringBuilder, mContext);

            holder.itemView.setTag(R.id.tag_session_id, sessionId);
            holder.title.setText(title);
            holder.text.setText(text);
            if (mDisplayIcons) {
                holder.image.setImageResource(UIUtils.getSessionIcon(sessionType));
            }
        }

        @Override
        public int getItemCount() {
            return mCursor.getCount();
        }

    }

    private static class ItemHolder extends RecyclerView.ViewHolder {

        TextView title;
        TextView text;
        ImageView image;

        public ItemHolder(LayoutInflater inflater, ViewGroup parent) {
            super(inflater.inflate(R.layout.map_item_session, parent, false));
            title = (TextView) itemView.findViewById(R.id.map_item_title);
            text = (TextView) itemView.findViewById(R.id.map_item_text);
            image = (ImageView) itemView.findViewById(R.id.map_item_image);
        }

    }

}