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 
17 package com.android.deskclock.timer;
18 
19 import android.app.Fragment;
20 import android.app.FragmentManager;
21 import android.app.FragmentTransaction;
22 import android.support.v13.app.FragmentCompat;
23 import android.support.v13.app.FragmentStatePagerAdapter;
24 import android.support.v4.util.SparseArrayCompat;
25 import android.support.v4.view.PagerAdapter;
26 import android.view.View;
27 import 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  */
38 public 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 
FragmentStatePagerAdapter2(FragmentManager fm)47     public FragmentStatePagerAdapter2(FragmentManager fm) {
48         mFragmentManager = fm;
49     }
50 
51     /**
52      * Return the Fragment associated with a specified position.
53      */
getItem(int position)54     public abstract Fragment getItem(int position);
55 
56     @Override
startUpdate(ViewGroup container)57     public void startUpdate(ViewGroup container) {
58     }
59 
60     @Override
instantiateItem(ViewGroup container, int position)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
destroyItem(ViewGroup container, int position, Object object)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
setPrimaryItem(ViewGroup container, int position, Object object)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
finishUpdate(ViewGroup container)112     public void finishUpdate(ViewGroup container) {
113         if (mCurTransaction != null) {
114             mCurTransaction.commitAllowingStateLoss();
115             mCurTransaction = null;
116             mFragmentManager.executePendingTransactions();
117         }
118     }
119 
120     @Override
isViewFromObject(View view, Object object)121     public boolean isViewFromObject(View view, Object object) {
122         return ((Fragment) object).getView() == view;
123     }
124 
setItemVisible(Fragment item, boolean visible)125     public void setItemVisible(Fragment item, boolean visible) {
126         FragmentCompat.setMenuVisibility(item, visible);
127         FragmentCompat.setUserVisibleHint(item, visible);
128     }
129 
130     @Override
notifyDataSetChanged()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 
getFragmentAt(int position)150     public Fragment getFragmentAt(int position) {
151         return mFragments.valueAt(position);
152     }
153 
154 }
155