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