1 /* 2 * Copyright (C) 2015 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.annotation.SuppressLint; 20 import android.app.Fragment; 21 import android.app.FragmentManager; 22 import android.app.FragmentTransaction; 23 import android.support.v13.app.FragmentCompat; 24 import android.support.v4.view.PagerAdapter; 25 import android.util.ArrayMap; 26 import android.view.View; 27 import android.view.ViewGroup; 28 29 import com.android.deskclock.data.DataModel; 30 import com.android.deskclock.data.Timer; 31 import com.android.deskclock.data.TimerListener; 32 33 import java.util.List; 34 import java.util.Map; 35 36 /** 37 * This adapter produces a {@link TimerItemFragment} for each timer. 38 */ 39 class TimerPagerAdapter extends PagerAdapter implements TimerListener { 40 41 private final FragmentManager mFragmentManager; 42 43 /** Maps each timer id to the corresponding {@link TimerItemFragment} that draws it. */ 44 private final Map<Integer, TimerItemFragment> mFragments = new ArrayMap<>(); 45 46 /** The current fragment transaction in play or {@code null}. */ 47 private FragmentTransaction mCurrentTransaction; 48 49 /** The {@link TimerItemFragment} that is current visible on screen. */ 50 private Fragment mCurrentPrimaryItem; 51 TimerPagerAdapter(FragmentManager fragmentManager)52 public TimerPagerAdapter(FragmentManager fragmentManager) { 53 mFragmentManager = fragmentManager; 54 } 55 56 @Override getCount()57 public int getCount() { 58 return getTimers().size(); 59 } 60 61 @Override isViewFromObject(View view, Object object)62 public boolean isViewFromObject(View view, Object object) { 63 return ((Fragment) object).getView() == view; 64 } 65 66 @Override getItemPosition(Object object)67 public int getItemPosition(Object object) { 68 final TimerItemFragment fragment = (TimerItemFragment) object; 69 final Timer timer = fragment.getTimer(); 70 71 final int position = getTimers().indexOf(timer); 72 return position == -1 ? POSITION_NONE : position; 73 } 74 75 @Override 76 @SuppressLint("CommitTransaction") instantiateItem(ViewGroup container, int position)77 public Fragment instantiateItem(ViewGroup container, int position) { 78 if (mCurrentTransaction == null) { 79 mCurrentTransaction = mFragmentManager.beginTransaction(); 80 } 81 82 final Timer timer = getTimers().get(position); 83 84 // Search for the existing fragment by tag. 85 final String tag = getClass().getSimpleName() + timer.getId(); 86 TimerItemFragment fragment = (TimerItemFragment) mFragmentManager.findFragmentByTag(tag); 87 88 if (fragment != null) { 89 // Reattach the existing fragment. 90 mCurrentTransaction.attach(fragment); 91 } else { 92 // Create and add a new fragment. 93 fragment = TimerItemFragment.newInstance(timer); 94 mCurrentTransaction.add(container.getId(), fragment, tag); 95 } 96 97 if (fragment != mCurrentPrimaryItem) { 98 setItemVisible(fragment, false); 99 } 100 101 mFragments.put(timer.getId(), fragment); 102 103 return fragment; 104 } 105 106 @Override 107 @SuppressLint("CommitTransaction") destroyItem(ViewGroup container, int position, Object object)108 public void destroyItem(ViewGroup container, int position, Object object) { 109 final TimerItemFragment fragment = (TimerItemFragment) object; 110 111 if (mCurrentTransaction == null) { 112 mCurrentTransaction = mFragmentManager.beginTransaction(); 113 } 114 115 mFragments.remove(fragment.getTimerId()); 116 mCurrentTransaction.remove(fragment); 117 } 118 119 @Override setPrimaryItem(ViewGroup container, int position, Object object)120 public void setPrimaryItem(ViewGroup container, int position, Object object) { 121 final Fragment fragment = (Fragment) object; 122 if (fragment != mCurrentPrimaryItem) { 123 if (mCurrentPrimaryItem != null) { 124 setItemVisible(mCurrentPrimaryItem, false); 125 } 126 127 mCurrentPrimaryItem = fragment; 128 129 if (mCurrentPrimaryItem != null) { 130 setItemVisible(mCurrentPrimaryItem, true); 131 } 132 } 133 } 134 135 @Override finishUpdate(ViewGroup container)136 public void finishUpdate(ViewGroup container) { 137 if (mCurrentTransaction != null) { 138 mCurrentTransaction.commitAllowingStateLoss(); 139 mCurrentTransaction = null; 140 mFragmentManager.executePendingTransactions(); 141 } 142 } 143 144 @Override timerAdded(Timer timer)145 public void timerAdded(Timer timer) { 146 notifyDataSetChanged(); 147 } 148 149 @Override timerRemoved(Timer timer)150 public void timerRemoved(Timer timer) { 151 notifyDataSetChanged(); 152 } 153 154 @Override timerUpdated(Timer before, Timer after)155 public void timerUpdated(Timer before, Timer after) { 156 final TimerItemFragment timerItemFragment = mFragments.get(after.getId()); 157 if (timerItemFragment != null) { 158 timerItemFragment.updateTime(); 159 } 160 } 161 162 /** 163 * @return {@code true} if at least one timer is in a state requiring continuous updates 164 */ updateTime()165 boolean updateTime() { 166 boolean continuousUpdates = false; 167 for (TimerItemFragment fragment : mFragments.values()) { 168 continuousUpdates |= fragment.updateTime(); 169 } 170 return continuousUpdates; 171 } 172 getTimer(int index)173 Timer getTimer(int index) { 174 return getTimers().get(index); 175 } 176 getTimers()177 private List<Timer> getTimers() { 178 return DataModel.getDataModel().getTimers(); 179 } 180 setItemVisible(Fragment item, boolean visible)181 private static void setItemVisible(Fragment item, boolean visible) { 182 FragmentCompat.setMenuVisibility(item, visible); 183 FragmentCompat.setUserVisibleHint(item, visible); 184 } 185 }