1 /*
2  * Copyright (C) 2019 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.car.dialer.ui;
18 
19 import android.content.Context;
20 import android.graphics.drawable.Drawable;
21 
22 import androidx.annotation.Nullable;
23 import androidx.annotation.StringDef;
24 import androidx.fragment.app.Fragment;
25 import androidx.fragment.app.FragmentManager;
26 
27 import com.android.car.dialer.R;
28 import com.android.car.dialer.ui.calllog.CallHistoryFragment;
29 import com.android.car.dialer.ui.common.OnItemClickedListener;
30 import com.android.car.dialer.ui.contact.ContactListFragment;
31 import com.android.car.dialer.ui.dialpad.DialpadFragment;
32 import com.android.car.dialer.ui.favorite.FavoriteFragment;
33 import com.android.car.ui.toolbar.Tab;
34 
35 import com.google.common.collect.ImmutableMap;
36 
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Map;
41 
42 /**
43  * Tab presenting fragments.
44  */
45 public class TelecomPageTab {
46 
47     /**
48      * Note: the strings must be consist with the items in string array tabs_config
49      */
50     @StringDef({
51             TelecomPageTab.Page.FAVORITES,
52             TelecomPageTab.Page.CALL_HISTORY,
53             TelecomPageTab.Page.CONTACTS,
54             TelecomPageTab.Page.DIAL_PAD
55     })
56     public @interface Page {
57         String FAVORITES = "FAVORITE";
58         String CALL_HISTORY = "CALL_HISTORY";
59         String CONTACTS = "CONTACTS";
60         String DIAL_PAD = "DIAL_PAD";
61     }
62 
63     private final Factory mFactory;
64     private Fragment mFragment;
65     private String mFragmentTag;
66     private boolean mWasFragmentRestored;
67     private final Tab mToolbarTab;
68 
TelecomPageTab(@ullable Drawable icon, @Nullable String text, @Nullable OnItemClickedListener<TelecomPageTab> listener, Factory factory)69     private TelecomPageTab(@Nullable Drawable icon, @Nullable String text,
70             @Nullable OnItemClickedListener<TelecomPageTab> listener, Factory factory) {
71         mFactory = factory;
72         mToolbarTab = Tab.builder()
73                 .setIcon(icon)
74                 .setText(text)
75                 .setSelectedListener(listener == null
76                         ? null
77                         : tab -> listener.onItemClicked(this))
78                 .build();
79     }
80 
getToolbarTab()81     public Tab getToolbarTab() {
82         return mToolbarTab;
83     }
84 
85     /**
86      * Either restore fragment from saved state or create new instance.
87      */
initFragment(FragmentManager fragmentManager, @Page String page, boolean shouldForceRecreateFragment)88     private void initFragment(FragmentManager fragmentManager, @Page String page,
89             boolean shouldForceRecreateFragment) {
90         mFragmentTag = makeFragmentTag(page);
91         mFragment = fragmentManager.findFragmentByTag(mFragmentTag);
92         if (mFragment == null || shouldForceRecreateFragment) {
93             mFragment = mFactory.createFragment(page);
94             mWasFragmentRestored = false;
95             return;
96         }
97         mWasFragmentRestored = true;
98     }
99 
100     /**
101      * Returns true if the fragment for this tab is restored from a saved state.
102      */
wasFragmentRestored()103     public boolean wasFragmentRestored() {
104         return mWasFragmentRestored;
105     }
106 
107     /**
108      * Returns the fragment for this tab.
109      */
getFragment()110     public Fragment getFragment() {
111         return mFragment;
112     }
113 
114     /**
115      * Returns the fragment tag for this tab.
116      */
getFragmentTag()117     public String getFragmentTag() {
118         return mFragmentTag;
119     }
120 
makeFragmentTag(@age String page)121     private String makeFragmentTag(@Page String page) {
122         return String.format("%s:%s", getClass().getSimpleName(), page);
123     }
124 
125     /**
126      * Responsible for creating the top tab items and their fragments.
127      */
128     public static class Factory {
129 
130         private static final ImmutableMap<String, Integer> TAB_LABELS =
131                 ImmutableMap.<String, Integer>builder()
132                         .put(Page.FAVORITES, R.string.favorites_title)
133                         .put(Page.CALL_HISTORY, R.string.call_history_title)
134                         .put(Page.CONTACTS, R.string.contacts_title)
135                         .put(Page.DIAL_PAD, R.string.dialpad_title)
136                         .build();
137 
138         private static final ImmutableMap<String, Integer> TAB_ICONS =
139                 ImmutableMap.<String, Integer>builder()
140                         .put(Page.FAVORITES, R.drawable.ic_favorite)
141                         .put(Page.CALL_HISTORY, R.drawable.ic_history)
142                         .put(Page.CONTACTS, R.drawable.ic_contact)
143                         .put(Page.DIAL_PAD, R.drawable.ic_dialpad)
144                         .build();
145 
146         private final FragmentManager mFragmentManager;
147         private final Map<String, Integer> mTabPageIndexMap;
148         private final String[] mTabConfig;
149         private final List<TelecomPageTab> mTabs = new ArrayList<>();
150         private final OnItemClickedListener<TelecomPageTab> mSelectedListener;
151 
Factory(Context context, OnItemClickedListener<TelecomPageTab> listener, FragmentManager fragmentManager)152         public Factory(Context context,
153                 OnItemClickedListener<TelecomPageTab> listener,
154                 FragmentManager fragmentManager) {
155             mFragmentManager = fragmentManager;
156             mSelectedListener = listener;
157 
158             mTabConfig = context.getResources().getStringArray(R.array.tabs_config);
159 
160             mTabPageIndexMap = new HashMap<>();
161             for (int i = 0; i < getTabCount(); i++) {
162                 mTabPageIndexMap.put(mTabConfig[i], i);
163             }
164         }
165 
createFragment(@age String page)166         private Fragment createFragment(@Page String page) {
167             switch (page) {
168                 case Page.FAVORITES:
169                     return FavoriteFragment.newInstance();
170                 case Page.CALL_HISTORY:
171                     return CallHistoryFragment.newInstance();
172                 case Page.CONTACTS:
173                     return ContactListFragment.newInstance();
174                 case Page.DIAL_PAD:
175                     return DialpadFragment.newPlaceCallDialpad();
176                 default:
177                     throw new UnsupportedOperationException("Tab is not supported.");
178             }
179         }
180 
181         /**
182          * Create the tab for the given {@param tabIndex}
183          */
recreateTabs(Context context, boolean forceInit)184         public List<TelecomPageTab> recreateTabs(Context context, boolean forceInit) {
185             mTabs.clear();
186             for (int i = 0; i < getTabCount(); i++) {
187                 String page = mTabConfig[i];
188                 TelecomPageTab telecomPageTab = new TelecomPageTab(
189                         context.getDrawable(TAB_ICONS.get(page)),
190                         context.getString(TAB_LABELS.get(page)),
191                         mSelectedListener,
192                         this);
193                 telecomPageTab.initFragment(mFragmentManager, page, forceInit);
194                 mTabs.add(telecomPageTab);
195             }
196             return mTabs;
197         }
198 
getTabCount()199         public int getTabCount() {
200             return mTabConfig.length;
201         }
202 
203         /**
204          * Returns the index for the given {@param page}
205          */
getTabIndex(@age String page)206         public int getTabIndex(@Page String page) {
207             return mTabPageIndexMap.getOrDefault(page, -1);
208         }
209 
210         /**
211          * Returns the {@link TelecomPageTab} at the given index
212          */
getTab(int index)213         public TelecomPageTab getTab(int index) {
214             return mTabs.get(index);
215         }
216     }
217 }
218