org.dmfs.webcal.fragments.PagerFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.dmfs.webcal.fragments.PagerFragment.java

Source

/*
 * Copyright (C) 2014 SchedJoules
 *
 * 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 org.dmfs.webcal.fragments;

import org.dmfs.android.calendarcontent.provider.CalendarContentContract;
import org.dmfs.android.calendarcontent.provider.CalendarContentContract.ContentItem;
import org.dmfs.android.retentionmagic.annotations.Parameter;
import org.dmfs.android.retentionmagic.annotations.Retain;
import org.dmfs.webcal.R;
import org.dmfs.webcal.adapters.SectionsPagerAdapter;
import org.dmfs.webcal.utils.BitmapUtils;
import org.dmfs.webcal.utils.ImageProxy;
import org.dmfs.webcal.utils.ImageProxy.ImageAvailableListener;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
import android.app.Activity;
import android.app.FragmentTransaction;
import android.content.ContentUris;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.Cursor;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.schedjoules.analytics.Analytics;

/**
 * A fragment that contains a pager to present the sections of a page item to the user. It takes a {@link Uri} or a page item id.
 * 
 * @author Marten Gajda <marten@dmfs.org>
 */
public class PagerFragment extends ActionBarFragment implements LoaderCallbacks<Cursor>, TabListener,
        OnPageChangeListener, OnSharedPreferenceChangeListener, ImageAvailableListener {
    private final static String TAG = "PagerFragment";

    private final static String ARG_SECTIONS_URI = "uri";
    /**
     * FIXME: we should not publish this internal field.
     */
    public static final String ARG_PAGE_TITLE = "title";
    private static final String ARG_PAGE_ICON = "icon";

    private final static int ID_URL_LOADER = 0;

    private ViewPager mViewPager;
    private SectionsPagerAdapter mAdapter;
    private TextView mMessageText;

    @Parameter(key = ARG_SECTIONS_URI)
    private Uri mUri;

    @Parameter(key = ARG_PAGE_TITLE)
    private String mTitle;

    @Parameter(key = ARG_PAGE_ICON)
    private long mIcon = -1;

    /**
     * The id is used to store the selected tab for this page, don't remove it.
     */
    @SuppressWarnings("unused")
    private long mId;

    @Retain(permanent = true, classNS = TAG, instanceNSField = "mId", key = "selectedTab")
    private int mSelectedTab = 0;

    private ProgressBar mProgressBar;

    /**
     * Create a new {@link PagerFragment} for the given sections {@link Uri}.
     * 
     * @param sectionsUri
     *            A {@link Uri} that points to the sections to show.
     * @param pageTitle
     *            The title of the page.
     * @param pageIcon
     *            The icon of the page.
     * @return A {@link PagerFragment}.
     */
    public static PagerFragment newInstance(Uri sectionsUri, String pageTitle, long pageIcon) {
        PagerFragment result = new PagerFragment();
        Bundle args = new Bundle();
        args.putParcelable(ARG_SECTIONS_URI, sectionsUri);
        args.putString(ARG_PAGE_TITLE, pageTitle);
        args.putLong(ARG_PAGE_ICON, pageIcon);
        result.setArguments(args);
        return result;
    }

    /**
     * Create a new {@link PagerFragment} for the given page id.
     * 
     * @param context
     *            A {@link Context}.
     * @param pageId
     *            The id of a page with sections to show.
     * @param pageTitle
     *            The title of the page.
     * @param pageIcon
     *            The icon of the page.
     * @return A {@link PagerFragment}.
     */
    public static PagerFragment newInstance(Context context, long pageId, String pageTitle, long pageIcon) {
        return newInstance(CalendarContentContract.ContentItem.getSectionContentUri(context, pageId), pageTitle,
                pageIcon);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // get the id before we call super.onCreate, because it's used to retrieve the id of the section to show first
        mId = ContentUris.parseId(mUri);
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        activity.getSharedPreferences(activity.getPackageName() + "_preferences", 0)
                .registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onDetach() {
        // avoid to get notifications for changes in the shared preferences that we caused ourselves (because the active section has been stored)
        Activity activity = getActivity();
        activity.getSharedPreferences(activity.getPackageName() + "_preferences", 0)
                .unregisterOnSharedPreferenceChangeListener(this);
        super.onDetach();
    }

    @Override
    public void onStart() {
        super.onStart();
        Analytics.screen(mTitle, String.valueOf(ContentItem.getApiId(mId)), null);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View returnView = inflater.inflate(R.layout.fragment_pager, container, false);

        mProgressBar = (ProgressBar) returnView.findViewById(android.R.id.progress);
        mMessageText = (TextView) returnView.findViewById(android.R.id.message);

        mAdapter = new SectionsPagerAdapter(getChildFragmentManager(), mIcon);

        mViewPager = (ViewPager) returnView.findViewById(R.id.pager);
        mViewPager.setOnPageChangeListener(this);
        mViewPager.setAdapter(mAdapter);

        // start loading the pages
        getLoaderManager().initLoader(ID_URL_LOADER, null, this);

        // set the page title and clear the subtitle if any
        ActionBar actionBar = getActivity().getActionBar();
        actionBar.setTitle(mTitle);
        actionBar.setSubtitle(null);

        // load the icon and set it if we get any, otherwise insert a placeholder and set it later
        Drawable icon = ImageProxy.getInstance(this.getActivity()).getImage(mIcon, this);
        if (icon != null) {
            // we need to pre-scale the icon, apparently Android doesn't do that for us
            actionBar.setIcon(BitmapUtils.scaleDrawable(getResources(), (BitmapDrawable) icon, 36, 36));
        } else {
            actionBar.setIcon(new ColorDrawable(getResources().getColor(android.R.color.transparent)));
        }

        return returnView;
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle extras) {
        return new CursorLoader(getActivity().getApplicationContext(), mUri, SectionsPagerAdapter.PROJECTION, null,
                null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        mAdapter.swapCursor(cursor);
        if (cursor == null) {
            // this indicates an error when loading the page, show an error message
            mMessageText.setVisibility(View.VISIBLE);
            mProgressBar.setVisibility(View.GONE);
            mViewPager.setVisibility(View.GONE);
        } else if (cursor.getCount() > 0) {
            // indicates the page has been loaded, hide progress indicator and show pager
            mMessageText.setVisibility(View.GONE);
            mProgressBar.setVisibility(View.GONE);
            mViewPager.setVisibility(View.VISIBLE);
            setupActionBarTabs();
        } else {
            // all pages must have at least one section, 0 results means we're still waiting for the page to load, show a progress indicator
            Activity activity = getActivity();
            mProgressBar.setVisibility(View.VISIBLE);
            activity.getActionBar().removeAllTabs();
            activity.getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
        mAdapter.swapCursor(null);
    }

    @Override
    public void imageAvailable(long mIconId, Drawable drawable) {
        if (isAdded()) {
            // the image has been loaded, scale it and update the ActionBar
            getActivity().getActionBar()
                    .setIcon(BitmapUtils.scaleDrawable(getResources(), (BitmapDrawable) drawable, 36, 36));
        }
    }

    @Override
    public void setupActionBar() {
        if (mAdapter != null) {
            setupActionBarTabs();
        }
    }

    /**
     * Configures the tabs on the action bar.
     */
    private void setupActionBarTabs() {
        ActionBar actionBar = getActivity().getActionBar();

        int tabCount = actionBar.getTabCount();
        int pageCount = mAdapter.getCount();

        // replace titles and listeners of existing tabs
        int i = 0;
        for (; i < tabCount && i < pageCount; ++i) {
            final Tab tab = actionBar.getTabAt(i);
            tab.setText(mAdapter.getPageTitle(i));
            tab.setTabListener(this);
        }

        // add missing tabs
        for (; i < pageCount; ++i) {
            actionBar.addTab(actionBar.newTab().setText(mAdapter.getPageTitle(i)).setTabListener(this));
        }

        // remove remaining tabs
        for (; i < tabCount; --tabCount) {
            actionBar.removeTabAt(i);
        }

        if (pageCount > 1) {
            int selection = mSelectedTab;
            // changing the navigation mode might trigger a call to onTabSelected overriding mSelectedTab with a wrong value, so save it
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            mSelectedTab = selection;
            if (selection < pageCount) {
                mViewPager.setCurrentItem(selection, false);
            }
        } else {
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
        }
    }

    @Override
    public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
        // nothing to do
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction fragmentTransaction) {
        mSelectedTab = tab.getPosition();
        if (mSelectedTab != mViewPager.getCurrentItem()) {
            mViewPager.setCurrentItem(tab.getPosition());
        }
    }

    @Override
    public void onTabUnselected(Tab arg0, FragmentTransaction arg1) {
        // nothing to do
    }

    @Override
    public void onPageSelected(int position) {
        Activity activity = getActivity();
        if (activity == null) {
            // nothing to do
            return;
        }

        ActionBar actionBar = activity.getActionBar();

        if (actionBar != null && position != actionBar.getSelectedNavigationIndex()) {
            mSelectedTab = position;
            actionBar.setSelectedNavigationItem(position);
        }
    }

    @Override
    public void onPageScrollStateChanged(int arg0) {
        // nothing to do
    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
        // nothing to do
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1) {
        if (isAdded()) {
            // the shared preferences have been changed, restart the loader to
            getLoaderManager().restartLoader(ID_URL_LOADER, null, this);
        }
    }

}