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 package com.android.messaging.ui; 17 18 import android.os.Bundle; 19 import android.os.Parcelable; 20 import android.support.v4.view.PagerAdapter; 21 import android.view.View; 22 import android.view.ViewGroup; 23 24 import com.android.messaging.Factory; 25 import com.android.messaging.util.Assert; 26 import com.android.messaging.util.UiUtils; 27 import com.google.common.annotations.VisibleForTesting; 28 29 /** 30 * A PagerAdapter that provides a fixed number of paged Views provided by a fixed set of 31 * {@link PagerViewHolder}'s. This allows us to put a fixed number of Views, instead of fragments, 32 * into a given ViewPager. 33 */ 34 public class FixedViewPagerAdapter<T extends PagerViewHolder> extends PagerAdapter { 35 private final T[] mViewHolders; 36 FixedViewPagerAdapter(final T[] viewHolders)37 public FixedViewPagerAdapter(final T[] viewHolders) { 38 Assert.notNull(viewHolders); 39 mViewHolders = viewHolders; 40 } 41 42 @Override instantiateItem(final ViewGroup container, final int position)43 public Object instantiateItem(final ViewGroup container, final int position) { 44 final PagerViewHolder viewHolder = getViewHolder(position); 45 final View view = viewHolder.getView(container); 46 if (view == null) { 47 return null; 48 } 49 view.setTag(viewHolder); 50 container.addView(view); 51 return viewHolder; 52 } 53 54 @Override destroyItem(final ViewGroup container, final int position, final Object object)55 public void destroyItem(final ViewGroup container, final int position, final Object object) { 56 final PagerViewHolder viewHolder = getViewHolder(position); 57 final View destroyedView = viewHolder.destroyView(); 58 if (destroyedView != null) { 59 container.removeView(destroyedView); 60 } 61 } 62 63 @Override getCount()64 public int getCount() { 65 return mViewHolders.length; 66 } 67 68 @Override isViewFromObject(final View view, final Object object)69 public boolean isViewFromObject(final View view, final Object object) { 70 return view.getTag() == object; 71 } 72 getViewHolder(final int i)73 public T getViewHolder(final int i) { 74 return getViewHolder(i, true /* rtlAware */); 75 } 76 77 @VisibleForTesting getViewHolder(final int i, final boolean rtlAware)78 public T getViewHolder(final int i, final boolean rtlAware) { 79 return mViewHolders[rtlAware ? getRtlPosition(i) : i]; 80 } 81 82 @Override saveState()83 public Parcelable saveState() { 84 // The paged views in the view pager gets created and destroyed as the user scrolls through 85 // them. By default, only the pages to the immediate left and right of the current visible 86 // page are realized. Moreover, if the activity gets destroyed and recreated, the pages are 87 // automatically destroyed. Therefore, in order to preserve transient page UI states that 88 // are not persisted in the DB we'd like to store them in a Bundle when views get 89 // destroyed. When the views get recreated, we rehydrate them by passing them the saved 90 // data. When the activity gets destroyed, it invokes saveState() on this adapter to 91 // add this saved Bundle to the overall saved instance state. 92 final Bundle savedViewHolderState = new Bundle(Factory.get().getApplicationContext() 93 .getClassLoader()); 94 for (int i = 0; i < mViewHolders.length; i++) { 95 final Parcelable pageState = getViewHolder(i).saveState(); 96 savedViewHolderState.putParcelable(getInstanceStateKeyForPage(i), pageState); 97 } 98 return savedViewHolderState; 99 } 100 101 @Override restoreState(final Parcelable state, final ClassLoader loader)102 public void restoreState(final Parcelable state, final ClassLoader loader) { 103 if (state instanceof Bundle) { 104 final Bundle restoredViewHolderState = (Bundle) state; 105 ((Bundle) state).setClassLoader(Factory.get().getApplicationContext().getClassLoader()); 106 for (int i = 0; i < mViewHolders.length; i++) { 107 final Parcelable pageState = restoredViewHolderState 108 .getParcelable(getInstanceStateKeyForPage(i)); 109 getViewHolder(i).restoreState(pageState); 110 } 111 } else { 112 super.restoreState(state, loader); 113 } 114 } 115 resetState()116 public void resetState() { 117 for (int i = 0; i < mViewHolders.length; i++) { 118 getViewHolder(i).resetState(); 119 } 120 } 121 getInstanceStateKeyForPage(final int i)122 private String getInstanceStateKeyForPage(final int i) { 123 return getViewHolder(i).getClass().getCanonicalName() + "_savedstate_" + i; 124 } 125 getRtlPosition(final int position)126 protected int getRtlPosition(final int position) { 127 if (UiUtils.isRtlMode()) { 128 return mViewHolders.length - 1 - position; 129 } 130 return position; 131 } 132 } 133