1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.ui;
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Bundle;
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Parcelable;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.view.PagerAdapter;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.View;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.ViewGroup;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.UiUtils;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.annotations.VisibleForTesting;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * A PagerAdapter that provides a fixed number of paged Views provided by a fixed set of
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@link PagerViewHolder}'s. This allows us to put a fixed number of Views, instead of fragments,
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * into a given ViewPager.
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class FixedViewPagerAdapter<T extends PagerViewHolder> extends PagerAdapter {
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private final T[] mViewHolders;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public FixedViewPagerAdapter(final T[] viewHolders) {
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Assert.notNull(viewHolders);
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mViewHolders = viewHolders;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Object instantiateItem(final ViewGroup container, final int position) {
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PagerViewHolder viewHolder = getViewHolder(position);
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final View view = viewHolder.getView(container);
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (view == null) {
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        view.setTag(viewHolder);
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        container.addView(view);
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return viewHolder;
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void destroyItem(final ViewGroup container, final int position, final Object object) {
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PagerViewHolder viewHolder = getViewHolder(position);
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final View destroyedView = viewHolder.destroyView();
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (destroyedView != null) {
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            container.removeView(destroyedView);
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public int getCount() {
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mViewHolders.length;
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean isViewFromObject(final View view, final Object object) {
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return view.getTag() == object;
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public T getViewHolder(final int i) {
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return getViewHolder(i, true /* rtlAware */);
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @VisibleForTesting
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public T getViewHolder(final int i, final boolean rtlAware) {
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mViewHolders[rtlAware ? getRtlPosition(i) : i];
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Parcelable saveState() {
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // The paged views in the view pager gets created and destroyed as the user scrolls through
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // them. By default, only the pages to the immediate left and right of the current visible
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // page are realized. Moreover, if the activity gets destroyed and recreated, the pages are
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // automatically destroyed. Therefore, in order to preserve transient page UI states that
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // are not persisted in the DB we'd like to store them in a Bundle when views get
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // destroyed. When the views get recreated, we rehydrate them by passing them the saved
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // data. When the activity gets destroyed, it invokes saveState() on this adapter to
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // add this saved Bundle to the overall saved instance state.
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Bundle savedViewHolderState = new Bundle(Factory.get().getApplicationContext()
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .getClassLoader());
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0; i < mViewHolders.length; i++) {
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Parcelable pageState = getViewHolder(i).saveState();
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            savedViewHolderState.putParcelable(getInstanceStateKeyForPage(i), pageState);
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return savedViewHolderState;
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void restoreState(final Parcelable state, final ClassLoader loader) {
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (state instanceof Bundle) {
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Bundle restoredViewHolderState = (Bundle) state;
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ((Bundle) state).setClassLoader(Factory.get().getApplicationContext().getClassLoader());
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (int i = 0; i < mViewHolders.length; i++) {
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final Parcelable pageState = restoredViewHolderState
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        .getParcelable(getInstanceStateKeyForPage(i));
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                getViewHolder(i).restoreState(pageState);
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            super.restoreState(state, loader);
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void resetState() {
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0; i < mViewHolders.length; i++) {
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            getViewHolder(i).resetState();
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private String getInstanceStateKeyForPage(final int i) {
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return getViewHolder(i).getClass().getCanonicalName() + "_savedstate_" + i;
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected int getRtlPosition(final int position) {
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (UiUtils.isRtlMode()) {
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mViewHolders.length - 1 - position;
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return position;
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
133