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 
17 package com.android.settings.wifi.calling;
18 
19 import android.app.settings.SettingsEnums;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.Bundle;
23 import android.provider.Settings;
24 import android.telephony.SubscriptionInfo;
25 import android.telephony.SubscriptionManager;
26 import android.util.Log;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.view.ViewStub;
31 
32 import androidx.annotation.VisibleForTesting;
33 import androidx.fragment.app.Fragment;
34 import androidx.fragment.app.FragmentManager;
35 import androidx.fragment.app.FragmentPagerAdapter;
36 
37 import com.android.internal.util.CollectionUtils;
38 import com.android.settings.R;
39 import com.android.settings.SettingsPreferenceFragment;
40 import com.android.settings.network.ActiveSubscriptionsListener;
41 import com.android.settings.network.SubscriptionUtil;
42 import com.android.settings.network.ims.WifiCallingQueryImsState;
43 import com.android.settings.network.telephony.MobileNetworkUtils;
44 import com.android.settings.search.actionbar.SearchMenuController;
45 import com.android.settings.support.actionbar.HelpResourceProvider;
46 import com.android.settings.widget.RtlCompatibleViewPager;
47 import com.android.settings.widget.SlidingTabLayout;
48 
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collections;
52 import java.util.List;
53 
54 /**
55  * "Wi-Fi Calling settings" screen. This is the container fragment which holds
56  * {@link WifiCallingSettingsForSub} fragments.
57  */
58 public class WifiCallingSettings extends SettingsPreferenceFragment
59         implements HelpResourceProvider {
60     private static final String TAG = "WifiCallingSettings";
61     private int mConstructionSubId;
62     private List<SubscriptionInfo> mSil;
63     private ActiveSubscriptionsListener mSubscriptionChangeListener;
64     private static final int [] EMPTY_SUB_ID_LIST = new int[0];
65 
66     //UI objects
67     private RtlCompatibleViewPager mViewPager;
68     private WifiCallingViewPagerAdapter mPagerAdapter;
69     private SlidingTabLayout mTabLayout;
70 
71     private final class InternalViewPagerListener implements
72             RtlCompatibleViewPager.OnPageChangeListener {
73         @Override
onPageScrolled(int position, float positionOffset, int positionOffsetPixels)74         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
75             // Do nothing.
76         }
77 
78         @Override
onPageSelected(int position)79         public void onPageSelected(int position) {
80             updateTitleForCurrentSub();
81         }
82 
83         @Override
onPageScrollStateChanged(int state)84         public void onPageScrollStateChanged(int state) {
85             // Do nothing.
86         }
87     }
88 
89     @Override
getMetricsCategory()90     public int getMetricsCategory() {
91         return SettingsEnums.WIFI_CALLING;
92     }
93 
94     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)95     public View onCreateView(LayoutInflater inflater, ViewGroup container,
96             Bundle savedInstanceState) {
97         if (MobileNetworkUtils.isMobileNetworkUserRestricted(getActivity())) {
98             return new ViewStub(getActivity());
99         }
100         final View view = inflater.inflate(R.layout.wifi_calling_settings_tabs, container, false);
101 
102         mTabLayout = view.findViewById(R.id.sliding_tabs);
103         mViewPager = (RtlCompatibleViewPager) view.findViewById(R.id.view_pager);
104 
105         mPagerAdapter = new WifiCallingViewPagerAdapter(getChildFragmentManager(), mViewPager);
106         mViewPager.setAdapter(mPagerAdapter);
107         mViewPager.addOnPageChangeListener(new InternalViewPagerListener());
108         maybeSetViewForSubId();
109         return view;
110     }
111 
getConstructionSubId(Bundle bundle)112     private int getConstructionSubId(Bundle bundle) {
113         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
114 
115         Intent intent = getActivity().getIntent();
116         if (intent != null) {
117             subId = intent.getIntExtra(Settings.EXTRA_SUB_ID,
118                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
119         }
120         if ((subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) && (bundle != null)) {
121             subId = bundle.getInt(Settings.EXTRA_SUB_ID,
122                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
123         }
124         return subId;
125     }
126 
maybeSetViewForSubId()127     private void maybeSetViewForSubId() {
128         if (mSil == null) {
129             return;
130         }
131         int subId = mConstructionSubId;
132         if (SubscriptionManager.isValidSubscriptionId(subId)) {
133             for (SubscriptionInfo subInfo : mSil) {
134                 if (subId == subInfo.getSubscriptionId()) {
135                     mViewPager.setCurrentItem(mSil.indexOf(subInfo));
136                     break;
137                 }
138             }
139         }
140     }
141 
142     @Override
onCreate(Bundle icicle)143     public void onCreate(Bundle icicle) {
144         mConstructionSubId = getConstructionSubId(icicle);
145         super.onCreate(icicle);
146         if (MobileNetworkUtils.isMobileNetworkUserRestricted(getActivity())) {
147             finish();
148             return;
149         }
150         Log.d(TAG, "SubId=" + mConstructionSubId);
151 
152         if (mConstructionSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
153             // Only config Wfc if it's enabled by platform.
154             mSubscriptionChangeListener = getSubscriptionChangeListener(getContext());
155         }
156         mSil = updateSubList();
157     }
158 
159     @Override
onStart()160     public void onStart() {
161         super.onStart();
162 
163         if (mSil != null && mSil.size() > 1) {
164             mTabLayout.setViewPager(mViewPager);
165         } else {
166             mTabLayout.setVisibility(View.GONE);
167         }
168 
169         updateTitleForCurrentSub();
170 
171         if (mSubscriptionChangeListener != null) {
172             mSubscriptionChangeListener.start();
173         }
174     }
175 
176     @Override
onStop()177     public void onStop() {
178         if (mSubscriptionChangeListener != null) {
179             mSubscriptionChangeListener.stop();
180         }
181 
182         super.onStop();
183     }
184 
185     @Override
onSaveInstanceState(Bundle outState)186     public void onSaveInstanceState(Bundle outState) {
187         super.onSaveInstanceState(outState);
188         // keep subscription ID for recreation
189         outState.putInt(Settings.EXTRA_SUB_ID, mConstructionSubId);
190     }
191 
192     @Override
getHelpResource()193     public int getHelpResource() {
194         return R.string.help_uri_wifi_calling;
195     }
196 
197     @VisibleForTesting
198     final class WifiCallingViewPagerAdapter extends FragmentPagerAdapter {
199         private final RtlCompatibleViewPager mViewPager;
200 
WifiCallingViewPagerAdapter(FragmentManager fragmentManager, RtlCompatibleViewPager viewPager)201         public WifiCallingViewPagerAdapter(FragmentManager fragmentManager,
202                 RtlCompatibleViewPager viewPager) {
203             super(fragmentManager);
204             mViewPager = viewPager;
205         }
206 
207         @Override
getPageTitle(int position)208         public CharSequence getPageTitle(int position) {
209             return String.valueOf(SubscriptionUtil.getUniqueSubscriptionDisplayName(
210                     mSil.get(position), getContext()));
211         }
212 
213         @Override
getItem(int position)214         public Fragment getItem(int position) {
215             int subId = mSil.get(position).getSubscriptionId();
216             Log.d(TAG, "Adapter getItem " + position + " for subId=" + subId);
217             final Bundle args = new Bundle();
218             args.putBoolean(SearchMenuController.NEED_SEARCH_ICON_IN_ACTION_BAR, false);
219             args.putInt(WifiCallingSettingsForSub.FRAGMENT_BUNDLE_SUBID, subId);
220             final WifiCallingSettingsForSub fragment = new WifiCallingSettingsForSub();
221             fragment.setArguments(args);
222 
223             return fragment;
224         }
225 
226         @Override
instantiateItem(ViewGroup container, int position)227         public Object instantiateItem(ViewGroup container, int position) {
228             Log.d(TAG, "Adapter instantiateItem " + position);
229             return super.instantiateItem(container,
230                     mViewPager.getRtlAwareIndex(position));
231         }
232 
233         @Override
getCount()234         public int getCount() {
235             if (mSil == null) {
236                 Log.d(TAG, "Adapter getCount null mSil ");
237                 return 0;
238             } else {
239                 Log.d(TAG, "Adapter getCount " + mSil.size());
240                 return mSil.size();
241             }
242         }
243     }
244 
245     @VisibleForTesting
getSelectableSubscriptions(Context context)246     protected List<SubscriptionInfo> getSelectableSubscriptions(Context context) {
247         return SubscriptionUtil.getSelectableSubscriptionInfoList(context);
248     }
249 
updateSubList()250     private List<SubscriptionInfo> updateSubList() {
251         List<SubscriptionInfo> subInfoList = getSelectableSubscriptions(getContext());
252 
253         if (subInfoList == null) {
254             return Collections.emptyList();
255         }
256         List<SubscriptionInfo> selectedList = new ArrayList<SubscriptionInfo>();
257         for (SubscriptionInfo subInfo : subInfoList) {
258             int subId = subInfo.getSubscriptionId();
259             try {
260                 if (MobileNetworkUtils.isWifiCallingEnabled(
261                         getContext(),
262                         subId,
263                         queryImsState(subId))) {
264                     selectedList.add(subInfo);
265                 }
266             } catch (Exception exception) {}
267         }
268         return selectedList;
269     }
270 
updateTitleForCurrentSub()271     private void updateTitleForCurrentSub() {
272         if (CollectionUtils.size(mSil) > 1) {
273             final int subId = mSil.get(mViewPager.getCurrentItem()).getSubscriptionId();
274             final String title = SubscriptionManager.getResourcesForSubId(getContext(), subId)
275                     .getString(R.string.wifi_calling_settings_title);
276             getActivity().getActionBar().setTitle(title);
277         }
278     }
279 
280     @VisibleForTesting
queryImsState(int subId)281     protected WifiCallingQueryImsState queryImsState(int subId) {
282         return new WifiCallingQueryImsState(getContext(), subId);
283     }
284 
285     @VisibleForTesting
getSubscriptionChangeListener(Context context)286     protected ActiveSubscriptionsListener getSubscriptionChangeListener(Context context) {
287         return new ActiveSubscriptionsListener(context.getMainLooper(), context) {
288             public void onChanged() {
289                 onSubscriptionChange(context);
290             }
291         };
292     }
293 
294     protected void onSubscriptionChange(Context context) {
295         if (mSubscriptionChangeListener == null) {
296             return;
297         }
298         int [] previousSubIdList = subscriptionIdList(mSil);
299         List<SubscriptionInfo> updateList = updateSubList();
300         int [] currentSubIdList = subscriptionIdList(updateList);
301 
302         if (currentSubIdList.length > 0) {
303             // only keep fragment when any provisioned subscription is available
304             if (previousSubIdList.length == 0) {
305                 // initial loading of list
306                 mSil = updateList;
307                 return;
308             }
309             if (previousSubIdList.length == currentSubIdList.length) {
310                 // same number of subscriptions
311                 if ( (!containsSubId(previousSubIdList, mConstructionSubId))
312                         // original request not yet appears in list
313                         || containsSubId(currentSubIdList, mConstructionSubId) )
314                         // original request appears in list
315                 {
316                     mSil = updateList;
317                     return;
318                 }
319             }
320         }
321         Log.d(TAG, "Closed subId=" + mConstructionSubId
322                 + " due to subscription change: " + Arrays.toString(previousSubIdList)
323                 + " -> " + Arrays.toString(currentSubIdList));
324 
325         // close this fragment when no provisioned subscriptions available
326         if (mSubscriptionChangeListener != null) {
327             mSubscriptionChangeListener.stop();
328             mSubscriptionChangeListener = null;
329         }
330 
331         // close this fragment
332         finishFragment();
333     }
334 
335     protected int [] subscriptionIdList(List<SubscriptionInfo> subInfoList) {
336         return (subInfoList == null) ? EMPTY_SUB_ID_LIST :
337                 subInfoList.stream().mapToInt(subInfo -> (subInfo == null) ?
338                 SubscriptionManager.INVALID_SUBSCRIPTION_ID : subInfo.getSubscriptionId())
339                 .toArray();
340     }
341 
342     protected boolean containsSubId(int [] subIdArray, int subIdLookUp) {
343         return Arrays.stream(subIdArray).anyMatch(subId -> (subId == subIdLookUp));
344     }
345 }
346