16d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux/* 26d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * Copyright (C) 2015 The Android Open Source Project 36d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * 46d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * Licensed under the Apache License, Version 2.0 (the "License"); 56d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * you may not use this file except in compliance with the License. 66d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * You may obtain a copy of the License at 76d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * 86d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * http://www.apache.org/licenses/LICENSE-2.0 96d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * 106d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * Unless required by applicable law or agreed to in writing, software 116d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * distributed under the License is distributed on an "AS IS" BASIS, 126d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * See the License for the specific language governing permissions and 146d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * limitations under the License. 156d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux */ 166d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 176d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuxpackage com.android.deskclock.timer; 186d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 196d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport android.app.Fragment; 206d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport android.app.FragmentManager; 216d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport android.app.FragmentTransaction; 226d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport android.support.v13.app.FragmentCompat; 236d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport android.support.v4.view.PagerAdapter; 246d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport android.util.ArrayMap; 256d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport android.view.View; 266d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport android.view.ViewGroup; 276d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 286d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport com.android.deskclock.data.DataModel; 296d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport com.android.deskclock.data.Timer; 306d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport com.android.deskclock.data.TimerListener; 316d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 326d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport java.util.List; 336d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuximport java.util.Map; 346d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 356d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux/** 366d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * This adapter produces a {@link TimerItemFragment} for each timer. 376d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux */ 386d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieuxclass TimerPagerAdapter extends PagerAdapter implements TimerListener { 396d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 406d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux private final FragmentManager mFragmentManager; 416d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 426d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux /** Maps each timer id to the corresponding {@link TimerItemFragment} that draws it. */ 436d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux private final Map<Integer, TimerItemFragment> mFragments = new ArrayMap<>(); 446d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 456d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux /** The current fragment transaction in play or {@code null}. */ 466d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux private FragmentTransaction mCurrentTransaction; 476d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 486d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux /** The {@link TimerItemFragment} that is current visible on screen. */ 496d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux private Fragment mCurrentPrimaryItem; 506d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 516d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public TimerPagerAdapter(FragmentManager fragmentManager) { 526d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mFragmentManager = fragmentManager; 536d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 546d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 556d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux @Override 566d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public int getCount() { 576d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux return getTimers().size(); 586d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 596d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 606d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux @Override 616d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public boolean isViewFromObject(View view, Object object) { 626d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux return ((Fragment) object).getView() == view; 636d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 646d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 656d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux @Override 666d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public int getItemPosition(Object object) { 676d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux final TimerItemFragment fragment = (TimerItemFragment) object; 686d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux final Timer timer = fragment.getTimer(); 696d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 706d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux final int position = getTimers().indexOf(timer); 716d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux return position == -1 ? POSITION_NONE : position; 726d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 736d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 746d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux @Override 756d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public Fragment instantiateItem(ViewGroup container, int position) { 766d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux if (mCurrentTransaction == null) { 776d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mCurrentTransaction = mFragmentManager.beginTransaction(); 786d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 796d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 806d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux final Timer timer = getTimers().get(position); 81f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux 82f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux // Search for the existing fragment by tag. 83f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux final String tag = getClass().getSimpleName() + timer.getId(); 84f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux TimerItemFragment fragment = (TimerItemFragment) mFragmentManager.findFragmentByTag(tag); 85f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux 86f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux if (fragment != null) { 87f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux // Reattach the existing fragment. 88f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux mCurrentTransaction.attach(fragment); 89f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux } else { 90f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux // Create and add a new fragment. 91f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux fragment = TimerItemFragment.newInstance(timer); 92f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux mCurrentTransaction.add(container.getId(), fragment, tag); 93f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux } 94f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux 95f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux if (fragment != mCurrentPrimaryItem) { 96f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux setItemVisible(fragment, false); 97f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux } 986d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 996d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mFragments.put(timer.getId(), fragment); 1006d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1016d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux return fragment; 1026d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1036d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1046d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux @Override 1056d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public void destroyItem(ViewGroup container, int position, Object object) { 1066d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux final TimerItemFragment fragment = (TimerItemFragment) object; 1076d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1086d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux if (mCurrentTransaction == null) { 1096d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mCurrentTransaction = mFragmentManager.beginTransaction(); 1106d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1116d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1126d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mFragments.remove(fragment.getTimerId()); 1136d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mCurrentTransaction.remove(fragment); 1146d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1156d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1166d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux @Override 1176d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public void setPrimaryItem(ViewGroup container, int position, Object object) { 1186d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux final Fragment fragment = (Fragment) object; 1196d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux if (fragment != mCurrentPrimaryItem) { 1206d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux if (mCurrentPrimaryItem != null) { 1216d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux setItemVisible(mCurrentPrimaryItem, false); 1226d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1236d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1246d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mCurrentPrimaryItem = fragment; 1256d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1266d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux if (mCurrentPrimaryItem != null) { 1276d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux setItemVisible(mCurrentPrimaryItem, true); 1286d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1296d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1306d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1316d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1326d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux @Override 1336d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public void finishUpdate(ViewGroup container) { 1346d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux if (mCurrentTransaction != null) { 1356d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mCurrentTransaction.commitAllowingStateLoss(); 1366d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mCurrentTransaction = null; 1376d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux mFragmentManager.executePendingTransactions(); 1386d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1396d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1406d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1416d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux @Override 1426d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public void timerAdded(Timer timer) { 1436d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux notifyDataSetChanged(); 1446d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1456d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1466d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux @Override 147f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux public void timerRemoved(Timer timer) { 148f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux notifyDataSetChanged(); 149f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux } 150f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux 151f4d06f8040dadcf9c8c8232c33f50756bde0a2e5James Lemieux @Override 1526d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux public void timerUpdated(Timer before, Timer after) { 1536d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux final TimerItemFragment timerItemFragment = mFragments.get(after.getId()); 1546d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux if (timerItemFragment != null) { 1556d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux timerItemFragment.updateTime(); 1566d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1576d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1586d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1596d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux /** 1606d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux * @return {@code true} if at least one timer is in a state requiring continuous updates 1616d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux */ 1626d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux boolean updateTime() { 1636d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux boolean continuousUpdates = false; 1646d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux for (TimerItemFragment fragment : mFragments.values()) { 1656d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux continuousUpdates |= fragment.updateTime(); 1666d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1676d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux return continuousUpdates; 1686d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1696d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1706d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux Timer getTimer(int index) { 1716d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux return getTimers().get(index); 1726d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1736d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1746d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux private List<Timer> getTimers() { 1756d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux return DataModel.getDataModel().getTimers(); 1766d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1776d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux 1786d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux private static void setItemVisible(Fragment item, boolean visible) { 1796d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux FragmentCompat.setMenuVisibility(item, visible); 1806d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux FragmentCompat.setUserVisibleHint(item, visible); 1816d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux } 1826d603b7c62bb38d763a681a8bf20fadb1442e833James Lemieux}