1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.deskclock.timer;
18
19import android.app.Fragment;
20import android.app.FragmentManager;
21import android.app.FragmentTransaction;
22import android.support.v13.app.FragmentCompat;
23import android.support.v13.app.FragmentStatePagerAdapter;
24import android.support.v4.util.SparseArrayCompat;
25import android.support.v4.view.PagerAdapter;
26import android.view.View;
27import android.view.ViewGroup;
28
29/**
30 * Forked from support lib's {@link FragmentStatePagerAdapter}, with some minor
31 * changes that couldn't be accomplished through subclassing: we need to override the
32 * onDataSetChanged method using the private member mFragments which cannot be accessed outside.
33 *
34 * This class is used for TimerFragment's vertical view pager only. It removed the save/restore
35 * functionality, because all the fragments needs to be destroyed whenever TimerFragment's
36 * onPause, in order to bind the newly created timer view with the new pager fragment.
37 */
38public abstract class FragmentStatePagerAdapter2 extends PagerAdapter {
39
40    private final FragmentManager mFragmentManager;
41    private FragmentTransaction mCurTransaction = null;
42
43    private SparseArrayCompat<Fragment> mFragments = new SparseArrayCompat<Fragment>();
44    private Fragment mCurrentPrimaryItem = null;
45
46
47    public FragmentStatePagerAdapter2(FragmentManager fm) {
48        mFragmentManager = fm;
49    }
50
51    /**
52     * Return the Fragment associated with a specified position.
53     */
54    public abstract Fragment getItem(int position);
55
56    @Override
57    public void startUpdate(ViewGroup container) {
58    }
59
60    @Override
61    public Object instantiateItem(ViewGroup container, int position) {
62        // If we already have this item instantiated, there is nothing
63        // to do.  This can happen when we are restoring the entire pager
64        // from its saved state, where the fragment manager has already
65        // taken care of restoring the fragments we previously had instantiated.
66        final Fragment existing = mFragments.get(position);
67        if (existing != null) {
68            return existing;
69        }
70
71        if (mCurTransaction == null) {
72            mCurTransaction = mFragmentManager.beginTransaction();
73        }
74
75        Fragment fragment = getItem(position);
76        if (fragment != mCurrentPrimaryItem) {
77            setItemVisible(fragment, false);
78        }
79        mFragments.put(position, fragment);
80        mCurTransaction.add(container.getId(), fragment);
81
82        return fragment;
83    }
84
85    @Override
86    public void destroyItem(ViewGroup container, int position, Object object) {
87        Fragment fragment = (Fragment) object;
88
89        if (mCurTransaction == null) {
90            mCurTransaction = mFragmentManager.beginTransaction();
91        }
92        mFragments.delete(position);
93
94        mCurTransaction.remove(fragment);
95    }
96
97    @Override
98    public void setPrimaryItem(ViewGroup container, int position, Object object) {
99        Fragment fragment = (Fragment) object;
100        if (fragment != mCurrentPrimaryItem) {
101            if (mCurrentPrimaryItem != null) {
102                setItemVisible(mCurrentPrimaryItem, false);
103            }
104            if (fragment != null) {
105                setItemVisible(fragment, true);
106            }
107            mCurrentPrimaryItem = fragment;
108        }
109    }
110
111    @Override
112    public void finishUpdate(ViewGroup container) {
113        if (mCurTransaction != null) {
114            mCurTransaction.commitAllowingStateLoss();
115            mCurTransaction = null;
116            mFragmentManager.executePendingTransactions();
117        }
118    }
119
120    @Override
121    public boolean isViewFromObject(View view, Object object) {
122        return ((Fragment) object).getView() == view;
123    }
124
125    public void setItemVisible(Fragment item, boolean visible) {
126        FragmentCompat.setMenuVisibility(item, visible);
127        FragmentCompat.setUserVisibleHint(item, visible);
128    }
129
130    @Override
131    public void notifyDataSetChanged() {
132        // update positions in mFragments
133        SparseArrayCompat<Fragment> newFragments =
134                new SparseArrayCompat<Fragment>(mFragments.size());
135        for (int i = 0; i < mFragments.size(); i++) {
136            final int oldPos = mFragments.keyAt(i);
137            final Fragment f = mFragments.valueAt(i);
138            final int newPos = getItemPosition(f);
139
140            if (newPos != POSITION_NONE) {
141                final int pos = (newPos >= 0) ? newPos : oldPos;
142                newFragments.put(pos, f);
143            }
144        }
145        mFragments = newFragments;
146
147        super.notifyDataSetChanged();
148    }
149
150    public Fragment getFragmentAt(int position) {
151        return mFragments.valueAt(position);
152    }
153
154}
155