• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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
18 
19 import android.util.ArrayMap
20 import android.view.View
21 import android.view.ViewGroup
22 import androidx.fragment.app.Fragment
23 import androidx.fragment.app.FragmentManager
24 import androidx.fragment.app.FragmentTransaction
25 import androidx.viewpager.widget.PagerAdapter
26 
27 import com.android.deskclock.uidata.UiDataModel
28 
29 /**
30  * This adapter produces the DeskClockFragments that are the content of the DeskClock tabs. The
31  * adapter presents the tabs in LTR and RTL order depending on the text layout direction for the
32  * current locale. To prevent issues when switching between LTR and RTL, fragments are registered
33  * with the manager using position-independent tags, which is an important departure from
34  * FragmentPagerAdapter.
35  */
36 internal class FragmentTabPagerAdapter(private val mDeskClock: DeskClock) : PagerAdapter() {
37 
38     /** The manager into which fragments are added.  */
39     private val mFragmentManager: FragmentManager = mDeskClock.supportFragmentManager
40 
41     /** A fragment cache that can be accessed before [.instantiateItem] is called.  */
42     private val mFragmentCache: MutableMap<UiDataModel.Tab, DeskClockFragment?> =
43             ArrayMap(getCount())
44 
45     /** The active fragment transaction if one exists.  */
46     private var mCurrentTransaction: FragmentTransaction? = null
47 
48     /** The current fragment displayed to the user.  */
49     private var mCurrentPrimaryItem: Fragment? = null
50 
getCountnull51     override fun getCount(): Int = UiDataModel.uiDataModel.tabCount
52 
53     /**
54      * @param position the left-to-right index of the fragment to be returned
55      * @return the fragment displayed at the given `position`
56      */
57     fun getDeskClockFragment(position: Int): DeskClockFragment {
58         // Fetch the tab the UiDataModel reports for the position.
59         val tab: UiDataModel.Tab = UiDataModel.uiDataModel.getTabAt(position)
60 
61         // First check the local cache for the fragment.
62         var fragment = mFragmentCache[tab]
63         if (fragment != null) {
64             return fragment
65         }
66 
67         // Next check the fragment manager; relevant when app is rebuilt after locale changes
68         // because this adapter will be new and mFragmentCache will be empty, but the fragment
69         // manager will retain the Fragments built on original application launch.
70         fragment = mFragmentManager.findFragmentByTag(tab.name) as DeskClockFragment?
71         if (fragment != null) {
72             fragment.setFabContainer(mDeskClock)
73             mFragmentCache[tab] = fragment
74             return fragment
75         }
76 
77         // Otherwise, build the fragment from scratch.
78         val fragmentClassName: String = tab.fragmentClassName
79         fragment = Fragment.instantiate(mDeskClock, fragmentClassName) as DeskClockFragment
80         fragment.setFabContainer(mDeskClock)
81         mFragmentCache[tab] = fragment
82         return fragment
83     }
84 
startUpdatenull85     override fun startUpdate(container: ViewGroup) {
86         check(container.id != View.NO_ID) { "ViewPager with adapter $this has no id" }
87     }
88 
instantiateItemnull89     override fun instantiateItem(container: ViewGroup, position: Int): Any {
90         if (mCurrentTransaction == null) {
91             mCurrentTransaction = mFragmentManager.beginTransaction()
92         }
93 
94         // Use the fragment located in the fragment manager if one exists.
95         val tab: UiDataModel.Tab = UiDataModel.uiDataModel.getTabAt(position)
96         var fragment = mFragmentManager.findFragmentByTag(tab.name)
97         if (fragment != null) {
98             mCurrentTransaction!!.attach(fragment)
99         } else {
100             fragment = getDeskClockFragment(position)
101             mCurrentTransaction!!.add(container.id, fragment, tab.name)
102         }
103 
104         if (fragment !== mCurrentPrimaryItem) {
105             fragment.setMenuVisibility(false)
106             fragment.setUserVisibleHint(false)
107         }
108 
109         return fragment
110     }
111 
destroyItemnull112     override fun destroyItem(container: ViewGroup, position: Int, any: Any) {
113         if (mCurrentTransaction == null) {
114             mCurrentTransaction = mFragmentManager.beginTransaction()
115         }
116         val fragment = any as DeskClockFragment
117         fragment.setFabContainer(null)
118         mCurrentTransaction!!.detach(fragment)
119     }
120 
setPrimaryItemnull121     override fun setPrimaryItem(container: ViewGroup, position: Int, any: Any) {
122         val fragment = any as Fragment
123         if (fragment !== mCurrentPrimaryItem) {
124             mCurrentPrimaryItem?.let {
125                 it.setMenuVisibility(false)
126                 it.setUserVisibleHint(false)
127             }
128             fragment.setMenuVisibility(true)
129             fragment.setUserVisibleHint(true)
130             mCurrentPrimaryItem = fragment
131         }
132     }
133 
finishUpdatenull134     override fun finishUpdate(container: ViewGroup) {
135         if (mCurrentTransaction != null) {
136             mCurrentTransaction!!.commitAllowingStateLoss()
137             mCurrentTransaction = null
138             mFragmentManager.executePendingTransactions()
139         }
140     }
141 
isViewFromObjectnull142     override fun isViewFromObject(view: View, any: Any): Boolean = (any as Fragment).view === view
143 }