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 */
16package com.android.messaging.ui;
17
18import android.os.Bundle;
19import android.os.Parcelable;
20import android.support.v4.view.PagerAdapter;
21import android.view.View;
22import android.view.ViewGroup;
23
24import com.android.messaging.Factory;
25import com.android.messaging.util.Assert;
26import com.android.messaging.util.UiUtils;
27import 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 */
34public class FixedViewPagerAdapter<T extends PagerViewHolder> extends PagerAdapter {
35    private final T[] mViewHolders;
36
37    public FixedViewPagerAdapter(final T[] viewHolders) {
38        Assert.notNull(viewHolders);
39        mViewHolders = viewHolders;
40    }
41
42    @Override
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
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
64    public int getCount() {
65        return mViewHolders.length;
66    }
67
68    @Override
69    public boolean isViewFromObject(final View view, final Object object) {
70        return view.getTag() == object;
71    }
72
73    public T getViewHolder(final int i) {
74        return getViewHolder(i, true /* rtlAware */);
75    }
76
77    @VisibleForTesting
78    public T getViewHolder(final int i, final boolean rtlAware) {
79        return mViewHolders[rtlAware ? getRtlPosition(i) : i];
80    }
81
82    @Override
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
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
116    public void resetState() {
117        for (int i = 0; i < mViewHolders.length; i++) {
118            getViewHolder(i).resetState();
119        }
120    }
121
122    private String getInstanceStateKeyForPage(final int i) {
123        return getViewHolder(i).getClass().getCanonicalName() + "_savedstate_" + i;
124    }
125
126    protected int getRtlPosition(final int position) {
127        if (UiUtils.isRtlMode()) {
128            return mViewHolders.length - 1 - position;
129        }
130        return position;
131    }
132}
133