com.appsimobile.appsii.AbstractSidebarPagerAdapter.java Source code

Java tutorial

Introduction

Here is the source code for com.appsimobile.appsii.AbstractSidebarPagerAdapter.java

Source

/*
 * Copyright 2015. Appsi Mobile
 *
 * 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.appsimobile.appsii;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.StringRes;
import android.support.v4.util.CircularArray;
import android.support.v4.util.SimpleArrayMap;
import android.support.v4.view.PagerAdapter;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.appsimobile.appsii.annotation.VisibleForTesting;
import com.appsimobile.appsii.module.home.provider.HomeContract;

/**
 * A pager adapter that holds client state. This is modeled after
 * fragments and the FragmentStatePagerAdapter
 * Created by nick on 10/08/14.
 */
public abstract class AbstractSidebarPagerAdapter extends PagerAdapter {

    /**
     * A controller frag that indicates that the background and
     * other decorations should not be shown
     */
    public static final int FLAG_NO_DECORATIONS = 1;

    static final int CLOSE_ACTION_AUTO_CLOSE = PageController.CLOSE_ACTION_AUTO_CLOSE;

    static final int CLOSE_ACTION_KEEP_OPEN = PageController.CLOSE_ACTION_KEEP_OPEN;

    static final int CLOSE_ACTION_ASK = PageController.CLOSE_ACTION_ASK;

    static final int CLOSE_ACTION_DONT_KNOW = PageController.CLOSE_ACTION_DONT_KNOW;

    @VisibleForTesting
    final SimpleArrayMap<HotspotPageEntry, PageController> mCachedControllers = new SimpleArrayMap<>();

    @VisibleForTesting
    final SparseArray<HotspotPageEntry> mActivePageKeys = new SparseArray<>(8);

    @VisibleForTesting
    final SparseArray<PageController> mActivePageControllers = new SparseArray<>(8);

    @VisibleForTesting
    final SparseArray<PageController> mPrevPageControllers = new SparseArray<>(8);

    final boolean mDontCachePages = true;

    private final SimpleArrayMap<HotspotPageEntry, Bundle> mSavedControllerStates = new SimpleArrayMap<>();

    private final Context mContext;

    FlagListener mFlagListener;

    boolean mAttachedToWindow;

    @VisibleForTesting
    PageController mActivePageController;

    boolean mSidebarOpening;

    public AbstractSidebarPagerAdapter(Context context) {
        mContext = context;
    }

    protected String getString(@StringRes int stringResId) {
        return mContext.getString(stringResId);
    }

    public void setFlagListener(FlagListener flagListener) {
        mFlagListener = flagListener;
    }

    public void setPages(CircularArray<HotspotPageEntry> pages) {
        // FIXME: this is a bug
        if (mActivePageKeys.equals(pages))
            return;

        // temporary keep the old items in a separate list so we can
        // figure out the exact change in getItemPosition
        mPrevPageControllers.clear();

        int count = mActivePageControllers.size();
        for (int i = 0; i < count; i++) {
            int key = mActivePageControllers.keyAt(i);
            PageController controller = mActivePageControllers.valueAt(i);
            mPrevPageControllers.put(key, controller);
        }

        mActivePageKeys.clear();
        mActivePageControllers.clear();

        for (int i = 0, position = 0; i < pages.size(); i++) {
            HotspotPageEntry page = pages.get(i);
            if (!page.mEnabled)
                continue;
            if (page.mPageType == HomeContract.Pages.PAGE_SETTINGS)
                continue;
            if (page.mPageType == HomeContract.Pages.PAGE_SMS)
                continue;

            PageController controller = mCachedControllers.get(page);

            if (controller == null) {
                controller = instantiateAndCacheControllerForPage(page);
            }
            mActivePageKeys.put(position, page);
            mActivePageControllers.put(position, controller);
            position++;
        }
        notifyDataSetChanged();
    }

    private PageController instantiateAndCacheControllerForPage(HotspotPageEntry page) {
        Bundle state = mSavedControllerStates.get(page);
        PageController controller = createPageController(page, state);
        controller.setDeferLoads(mSidebarOpening);
        controller.setUserVisible(false);
        mCachedControllers.put(page, controller);
        return controller;
    }

    public final PageController createPageController(HotspotPageEntry page, Bundle state) {
        return onCreatePageController(mContext, page);
    }

    protected abstract PageController onCreatePageController(Context context, HotspotPageEntry page);

    HotspotPageEntry getPageKey(int position) {
        return mActivePageKeys.get(position);
    }

    @Override
    public int getCount() {
        return mActivePageKeys.size();
    }

    @Override
    public final Object instantiateItem(ViewGroup container, int position) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        PageController controller = mActivePageControllers.get(position);

        if (controller == null) {
            HotspotPageEntry page = mActivePageKeys.get(position);
            controller = instantiateAndCacheControllerForPage(page);
        }

        HotspotPageEntry page = mActivePageKeys.get(position);
        controller.setPage(page);

        Bundle state = mSavedControllerStates.get(page);
        controller.performCreate(state);

        View result = controller.performCreateView(inflater, container);
        controller.performViewCreated(result);

        if (mAttachedToWindow) {
            controller.onSidebarAttached();
        } else {
            controller.onSidebarDetached();
        }

        container.addView(controller.getView());
        controller.performOnAttach();
        controller.performStart();
        controller.performRestoreInstanceState();
        controller.performResume();

        return controller;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        PageController controller = (PageController) object;

        HotspotPageEntry page = controller.getPage();

        Bundle savedControllerState = mSavedControllerStates.get(page);
        if (savedControllerState == null) {
            savedControllerState = new Bundle();
            mSavedControllerStates.put(page, savedControllerState);
        } else {
            savedControllerState.clear();
        }
        controller.performPause();
        controller.performSaveInstanceState(savedControllerState);
        controller.performStop();
        controller.performOnDetach();
        container.removeView(controller.getView());
        controller.performDestroy();

        if (mDontCachePages) {
            mActivePageControllers.remove(position);
            HotspotPageEntry e = controller.getPage();
            mCachedControllers.remove(e);
        }

    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
        if (mActivePageController != object) {

            if (mActivePageController != null) {
                mActivePageController.setUserVisible(false);
                mActivePageController.onUserInvisible();
            }

            mActivePageController = (PageController) object;

            // TODO: probably happens when the user disabled all pages (?)
            if (mActivePageController != null) {
                mActivePageController.setUserVisible(true);
                mActivePageController.onUserVisible();
                updatePageFlags(mActivePageController.getFlags());
            } else {
                updatePageFlags(0);
            }
        }
    }

    protected void updatePageFlags(int i) {
        if (mFlagListener != null) {
            mFlagListener.onFlagsChanged(i);
        }
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        PageController controller = (PageController) object;
        return view == controller.getView();
    }

    @Override
    public int getItemPosition(Object object) {
        int oldPos = keyOf(mPrevPageControllers, (PageController) object);
        int newIdx = keyOf(mActivePageControllers, (PageController) object);
        if (oldPos != -1) {
            mPrevPageControllers.remove(oldPos);
        }

        if (newIdx == -1) {
            return POSITION_NONE;
        } else if (newIdx == oldPos) {
            return POSITION_UNCHANGED;
        } else {
            return newIdx;
        }
    }

    static <T> int keyOf(SparseArray<T> array, T object) {
        int length = array.size();
        for (int i = 0; i < length; i++) {
            T value = array.valueAt(i);
            if (value == object)
                return array.keyAt(i);
        }
        return -1;
    }

    public void onTrimMemory(int level) {
        int length = mActivePageControllers.size();
        for (int i = 0; i < length; i++) {
            PageController controller = mActivePageControllers.get(i);
            if (controller != null) {
                controller.onTrimMemory(level);
            }
        }
    }

    public void setSidebarClosed() {
        if (mActivePageController != null) {
            mActivePageController.onUserInvisible();
        }

    }

    public void setSidebarOpening(boolean sidebarOpening) {
        mSidebarOpening = sidebarOpening;
        int length = mActivePageControllers.size();
        for (int i = 0; i < length; i++) {
            PageController controller = mActivePageControllers.get(i);
            if (controller != null) {
                controller.setDeferLoads(sidebarOpening);
            }
        }
        if (mActivePageController != null) {
            if (sidebarOpening) {
                mActivePageController.onUserInvisible();
            } else {
                mActivePageController.onUserVisible();
            }
            // TODO: how come this is not properly called when after using try; loading home?
            // seems like the new active page has not yet been added to the list of
            // ActivePageControllers
            mActivePageController.setDeferLoads(sidebarOpening);
        }
    }

    public void onAttachedToWindow() {
        mAttachedToWindow = true;
        int length = mActivePageControllers.size();
        for (int i = 0; i < length; i++) {
            PageController controller = mActivePageControllers.get(i);
            if (controller != null) {
                controller.onSidebarAttached();
            }
        }

    }

    public void onDetachedFromWindow() {
        mAttachedToWindow = false;
        int length = mActivePageControllers.size();
        for (int i = 0; i < length; i++) {
            PageController controller = mActivePageControllers.get(i);
            if (controller != null) {
                controller.onSidebarDetached();
            }
        }

    }

    public int shouldClose(Bundle state) {
        if (mActivePageController != null) {
            return mActivePageController.shouldClose(state);
        }
        return PageController.CLOSE_ACTION_DONT_KNOW;
    }

    public void rememberCloseAction(Bundle state, int action) {
        if (mActivePageController != null) {
            mActivePageController.rememberCloseAction(state, action);
        }
    }

    interface FlagListener {

        void onFlagsChanged(int flags);
    }

}