1 /*
2  * Copyright (C) 2017 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.dialer.app.list;
18 
19 import android.app.Fragment;
20 import android.app.FragmentManager;
21 import android.content.Context;
22 import android.support.annotation.IntDef;
23 import android.support.v13.app.FragmentPagerAdapter;
24 import android.view.ViewGroup;
25 import com.android.dialer.app.calllog.CallLogFragment;
26 import com.android.dialer.app.calllog.VisualVoicemailCallLogFragment;
27 import com.android.dialer.calllog.CallLogComponent;
28 import com.android.dialer.calllog.CallLogFramework;
29 import com.android.dialer.calllog.ui.NewCallLogFragment;
30 import com.android.dialer.common.Assert;
31 import com.android.dialer.common.ConfigProviderBindings;
32 import com.android.dialer.common.LogUtil;
33 import com.android.dialer.contactsfragment.ContactsFragment;
34 import com.android.dialer.database.CallLogQueryHandler;
35 import com.android.dialer.speeddial.SpeedDialFragment;
36 import com.android.dialer.util.ViewUtil;
37 import java.lang.annotation.Retention;
38 import java.lang.annotation.RetentionPolicy;
39 import java.util.ArrayList;
40 import java.util.Collections;
41 import java.util.List;
42 
43 /** ViewPager adapter for {@link com.android.dialer.app.DialtactsActivity}. */
44 public class DialtactsPagerAdapter extends FragmentPagerAdapter {
45 
46   /** IntDef for indices of ViewPager tabs. */
47   @Retention(RetentionPolicy.SOURCE)
48   @IntDef({TAB_INDEX_SPEED_DIAL, TAB_INDEX_HISTORY, TAB_INDEX_ALL_CONTACTS, TAB_INDEX_VOICEMAIL})
49   public @interface TabIndex {}
50 
51   public static final int TAB_INDEX_SPEED_DIAL = 0;
52   public static final int TAB_INDEX_HISTORY = 1;
53   public static final int TAB_INDEX_ALL_CONTACTS = 2;
54   public static final int TAB_INDEX_VOICEMAIL = 3;
55   public static final int TAB_COUNT_DEFAULT = 3;
56   public static final int TAB_COUNT_WITH_VOICEMAIL = 4;
57 
58   private final List<Fragment> fragments = new ArrayList<>();
59   private final String[] tabTitles;
60   private final boolean useNewSpeedDialTab;
61   private final boolean useNewCallLogTab;
62   private final boolean useNewContactsTab;
63   private OldSpeedDialFragment oldSpeedDialFragment;
64   private SpeedDialFragment speedDialFragment;
65   private CallLogFragment callLogFragment;
66   private NewCallLogFragment newCallLogFragment;
67   private AllContactsFragment oldContactsFragment;
68   private ContactsFragment contactsFragment;
69   private CallLogFragment voicemailFragment;
70 
71   public boolean hasActiveVoicemailProvider;
72 
DialtactsPagerAdapter( Context context, FragmentManager fm, String[] tabTitles, boolean hasVoicemailProvider)73   public DialtactsPagerAdapter(
74       Context context, FragmentManager fm, String[] tabTitles, boolean hasVoicemailProvider) {
75     super(fm);
76     useNewSpeedDialTab =
77         ConfigProviderBindings.get(context).getBoolean("enable_new_favorites_tab", false);
78     CallLogFramework callLogFramework = CallLogComponent.get(context).callLogFramework();
79     useNewCallLogTab = callLogFramework.isNewCallLogEnabled(context);
80     useNewContactsTab =
81         ConfigProviderBindings.get(context).getBoolean("enable_new_contacts_tab", false);
82     this.tabTitles = tabTitles;
83     hasActiveVoicemailProvider = hasVoicemailProvider;
84     fragments.addAll(Collections.nCopies(TAB_COUNT_WITH_VOICEMAIL, null));
85   }
86 
87   @Override
getItemId(int position)88   public long getItemId(int position) {
89     return getRtlPosition(position);
90   }
91 
92   @Override
getItem(int position)93   public Fragment getItem(int position) {
94     LogUtil.d("ViewPagerAdapter.getItem", "position: %d", position);
95     switch (getRtlPosition(position)) {
96       case TAB_INDEX_SPEED_DIAL:
97         if (useNewSpeedDialTab) {
98           if (speedDialFragment == null) {
99             speedDialFragment = SpeedDialFragment.newInstance();
100           }
101           return speedDialFragment;
102         } else {
103           if (oldSpeedDialFragment == null) {
104             oldSpeedDialFragment = new OldSpeedDialFragment();
105           }
106           return oldSpeedDialFragment;
107         }
108       case TAB_INDEX_HISTORY:
109         if (useNewCallLogTab) {
110           if (newCallLogFragment == null) {
111             newCallLogFragment = new NewCallLogFragment();
112           }
113           return newCallLogFragment;
114         } else {
115           if (callLogFragment == null) {
116             callLogFragment = new CallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL);
117           }
118           return callLogFragment;
119         }
120       case TAB_INDEX_ALL_CONTACTS:
121         if (useNewContactsTab) {
122           if (contactsFragment == null) {
123             contactsFragment = new ContactsFragment();
124           }
125           return contactsFragment;
126         } else {
127           if (oldContactsFragment == null) {
128             oldContactsFragment = new AllContactsFragment();
129           }
130           return oldContactsFragment;
131         }
132       case TAB_INDEX_VOICEMAIL:
133         if (voicemailFragment == null) {
134           voicemailFragment = new VisualVoicemailCallLogFragment();
135           LogUtil.v(
136               "ViewPagerAdapter.getItem",
137               "new VisualVoicemailCallLogFragment: %s",
138               voicemailFragment);
139         }
140         return voicemailFragment;
141       default:
142         throw Assert.createIllegalStateFailException("No fragment at position " + position);
143     }
144   }
145 
146   @Override
instantiateItem(ViewGroup container, int position)147   public Fragment instantiateItem(ViewGroup container, int position) {
148     LogUtil.d("ViewPagerAdapter.instantiateItem", "position: %d", position);
149     // On rotation the FragmentManager handles rotation. Therefore getItem() isn't called.
150     // Copy the fragments that the FragmentManager finds so that we can store them in
151     // instance variables for later.
152     final Fragment fragment = (Fragment) super.instantiateItem(container, position);
153     if (fragment instanceof OldSpeedDialFragment) {
154       oldSpeedDialFragment = (OldSpeedDialFragment) fragment;
155     } else if (fragment instanceof SpeedDialFragment) {
156       speedDialFragment = (SpeedDialFragment) fragment;
157     } else if (fragment instanceof CallLogFragment && position == TAB_INDEX_HISTORY) {
158       callLogFragment = (CallLogFragment) fragment;
159     } else if (fragment instanceof NewCallLogFragment) {
160       newCallLogFragment = (NewCallLogFragment) fragment;
161     } else if (fragment instanceof ContactsFragment) {
162       contactsFragment = (ContactsFragment) fragment;
163     } else if (fragment instanceof AllContactsFragment) {
164       oldContactsFragment = (AllContactsFragment) fragment;
165     } else if (fragment instanceof CallLogFragment && position == TAB_INDEX_VOICEMAIL) {
166       voicemailFragment = (CallLogFragment) fragment;
167       LogUtil.v("ViewPagerAdapter.instantiateItem", voicemailFragment.toString());
168     }
169     fragments.set(position, fragment);
170     return fragment;
171   }
172 
173   /**
174    * When {@link android.support.v4.view.PagerAdapter#notifyDataSetChanged} is called, this method
175    * is called on all pages to determine whether they need to be recreated. When the voicemail tab
176    * is removed, the view needs to be recreated by returning POSITION_NONE. If notifyDataSetChanged
177    * is called for some other reason, the voicemail tab is recreated only if it is active. All other
178    * tabs do not need to be recreated and POSITION_UNCHANGED is returned.
179    */
180   @Override
getItemPosition(Object object)181   public int getItemPosition(Object object) {
182     return !hasActiveVoicemailProvider && fragments.indexOf(object) == TAB_INDEX_VOICEMAIL
183         ? POSITION_NONE
184         : POSITION_UNCHANGED;
185   }
186 
187   @Override
getCount()188   public int getCount() {
189     return hasActiveVoicemailProvider ? TAB_COUNT_WITH_VOICEMAIL : TAB_COUNT_DEFAULT;
190   }
191 
192   @Override
getPageTitle(@abIndex int position)193   public CharSequence getPageTitle(@TabIndex int position) {
194     return tabTitles[position];
195   }
196 
getRtlPosition(int position)197   public int getRtlPosition(int position) {
198     if (ViewUtil.isRtl()) {
199       return getCount() - 1 - position;
200     }
201     return position;
202   }
203 
removeVoicemailFragment(FragmentManager manager)204   public void removeVoicemailFragment(FragmentManager manager) {
205     if (voicemailFragment != null) {
206       manager.beginTransaction().remove(voicemailFragment).commitAllowingStateLoss();
207       voicemailFragment = null;
208     }
209   }
210 
hasActiveVoicemailProvider()211   public boolean hasActiveVoicemailProvider() {
212     return hasActiveVoicemailProvider;
213   }
214 
setHasActiveVoicemailProvider(boolean hasActiveVoicemailProvider)215   public void setHasActiveVoicemailProvider(boolean hasActiveVoicemailProvider) {
216     this.hasActiveVoicemailProvider = hasActiveVoicemailProvider;
217   }
218 }
219