| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.ons; |
| |
| import static android.telephony.AvailableNetworkInfo.PRIORITY_HIGH; |
| import static android.telephony.AvailableNetworkInfo.PRIORITY_LOW; |
| |
| import android.app.PendingIntent; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.os.AsyncTask; |
| import android.os.Handler; |
| import android.os.HandlerThread; |
| import android.os.Message; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.telephony.CellInfo; |
| import android.telephony.CellInfoLte; |
| import android.telephony.Rlog; |
| import android.telephony.SignalStrength; |
| import android.telephony.SubscriptionInfo; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.text.TextUtils; |
| import android.telephony.AvailableNetworkInfo; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.internal.telephony.IUpdateAvailableNetworksCallback; |
| import com.android.internal.telephony.ISetOpportunisticDataCallback; |
| import com.android.internal.telephony.ISub; |
| |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.ArrayList; |
| |
| /** |
| * Profile selector class which will select the right profile based upon |
| * geographic information input and network scan results. |
| */ |
| public class ONSProfileSelector { |
| private static final String LOG_TAG = "ONSProfileSelector"; |
| private static final boolean DBG = true; |
| private final Object mLock = new Object(); |
| |
| private static final int INVALID_SEQUENCE_ID = -1; |
| private static final int START_SEQUENCE_ID = 1; |
| |
| /* message to indicate profile update */ |
| private static final int MSG_PROFILE_UPDATE = 1; |
| |
| /* message to indicate start of profile selection process */ |
| private static final int MSG_START_PROFILE_SELECTION = 2; |
| |
| private boolean mIsEnabled = false; |
| |
| @VisibleForTesting |
| protected Context mContext; |
| |
| @VisibleForTesting |
| protected TelephonyManager mTelephonyManager; |
| private TelephonyManager mSubscriptionBoundTelephonyManager; |
| |
| @VisibleForTesting |
| protected ONSNetworkScanCtlr mNetworkScanCtlr; |
| |
| @VisibleForTesting |
| protected SubscriptionManager mSubscriptionManager; |
| @VisibleForTesting |
| protected List<SubscriptionInfo> mOppSubscriptionInfos; |
| private ONSProfileSelectionCallback mProfileSelectionCallback; |
| private int mSequenceId; |
| private int mCurrentDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| private ArrayList<AvailableNetworkInfo> mAvailableNetworkInfos; |
| private IUpdateAvailableNetworksCallback mNetworkScanCallback; |
| |
| public static final String ACTION_SUB_SWITCH = |
| "android.intent.action.SUBSCRIPTION_SWITCH_REPLY"; |
| |
| HandlerThread mThread; |
| @VisibleForTesting |
| protected Handler mHandler; |
| |
| /** |
| * Broadcast receiver to receive intents |
| */ |
| @VisibleForTesting |
| protected final BroadcastReceiver mProfileSelectorBroadcastReceiver = |
| new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| int sequenceId; |
| int subId; |
| String action = intent.getAction(); |
| logDebug("ACTION_SUB_SWITCH : " + action); |
| if (!mIsEnabled || action == null) { |
| return; |
| } |
| |
| switch (action) { |
| case ACTION_SUB_SWITCH: |
| sequenceId = intent.getIntExtra("sequenceId", INVALID_SEQUENCE_ID); |
| subId = intent.getIntExtra("subId", |
| SubscriptionManager.INVALID_SUBSCRIPTION_ID); |
| logDebug("ACTION_SUB_SWITCH sequenceId: " + sequenceId |
| + " mSequenceId: " + mSequenceId); |
| if (sequenceId != mSequenceId) { |
| return; |
| } |
| |
| onSubSwitchComplete(subId); |
| break; |
| } |
| } |
| }; |
| |
| /** |
| * Network scan callback handler |
| */ |
| @VisibleForTesting |
| protected ONSNetworkScanCtlr.NetworkAvailableCallBack mNetworkAvailableCallBack = |
| new ONSNetworkScanCtlr.NetworkAvailableCallBack() { |
| @Override |
| public void onNetworkAvailability(List<CellInfo> results) { |
| int subId = retrieveBestSubscription(results); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| sendUpdateNetworksCallbackHelper(mNetworkScanCallback, |
| TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS); |
| mNetworkScanCallback = null; |
| return; |
| } |
| |
| /* stop scanning further */ |
| mNetworkScanCtlr.stopNetworkScan(); |
| handleNetworkScanResult(subId); |
| } |
| |
| @Override |
| public void onError(int error) { |
| log("Network scan failed with error " + error); |
| if (mIsEnabled && mAvailableNetworkInfos != null |
| && mAvailableNetworkInfos.size() > 0) { |
| handleNetworkScanResult(mAvailableNetworkInfos.get(0).getSubId()); |
| } else { |
| if (mNetworkScanCallback != null) { |
| sendUpdateNetworksCallbackHelper(mNetworkScanCallback, |
| TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS); |
| mNetworkScanCallback = null; |
| } |
| } |
| } |
| |
| private void handleNetworkScanResult(int subId) { |
| /* if subscription is already active, just enable modem */ |
| if (mSubscriptionManager.isActiveSubId(subId)) { |
| enableModem(subId, true); |
| mProfileSelectionCallback.onProfileSelectionDone(); |
| sendUpdateNetworksCallbackHelper(mNetworkScanCallback, |
| TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS); |
| mNetworkScanCallback = null; |
| } else { |
| logDebug("switch to sub:" + subId); |
| switchToSubscription(subId); |
| } |
| } |
| }; |
| |
| @VisibleForTesting |
| protected SubscriptionManager.OnOpportunisticSubscriptionsChangedListener |
| mProfileChangeListener = |
| new SubscriptionManager.OnOpportunisticSubscriptionsChangedListener() { |
| @Override |
| public void onOpportunisticSubscriptionsChanged() { |
| mHandler.sendEmptyMessage(MSG_PROFILE_UPDATE); |
| } |
| }; |
| |
| /** |
| * interface call back to confirm profile selection |
| */ |
| public interface ONSProfileSelectionCallback { |
| |
| /** |
| * interface call back to confirm profile selection |
| */ |
| void onProfileSelectionDone(); |
| } |
| |
| class SortSubInfo implements Comparator<SubscriptionInfo> |
| { |
| // Used for sorting in ascending order of sub id |
| public int compare(SubscriptionInfo a, SubscriptionInfo b) |
| { |
| return a.getSubscriptionId() - b.getSubscriptionId(); |
| } |
| } |
| |
| class SortAvailableNetworks implements Comparator<AvailableNetworkInfo> |
| { |
| // Used for sorting in ascending order of sub id |
| public int compare(AvailableNetworkInfo a, AvailableNetworkInfo b) |
| { |
| return a.getSubId() - b.getSubId(); |
| } |
| } |
| |
| class SortAvailableNetworksInPriority implements Comparator<AvailableNetworkInfo> |
| { |
| // Used for sorting in descending order of priority (ascending order of priority numbers) |
| public int compare(AvailableNetworkInfo a, AvailableNetworkInfo b) |
| { |
| return a.getPriority() - b.getPriority(); |
| } |
| } |
| |
| /** |
| * ONSProfileSelector constructor |
| * @param c context |
| * @param profileSelectionCallback callback to be called once selection is done |
| */ |
| public ONSProfileSelector(Context c, ONSProfileSelectionCallback profileSelectionCallback) { |
| init(c, profileSelectionCallback); |
| log("ONSProfileSelector init complete"); |
| } |
| |
| private int getSignalLevel(CellInfo cellInfo) { |
| if (cellInfo != null) { |
| return cellInfo.getCellSignalStrength().getLevel(); |
| } else { |
| return SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; |
| } |
| } |
| |
| private String getMcc(CellInfo cellInfo) { |
| String mcc = ""; |
| if (cellInfo instanceof CellInfoLte) { |
| mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMccString(); |
| } |
| |
| return mcc; |
| } |
| |
| private String getMnc(CellInfo cellInfo) { |
| String mnc = ""; |
| if (cellInfo instanceof CellInfoLte) { |
| mnc = ((CellInfoLte) cellInfo).getCellIdentity().getMncString(); |
| } |
| |
| return mnc; |
| } |
| |
| private int getSubIdUsingAvailableNetworks(String mcc, String mnc, int priorityLevel) { |
| String mccMnc = mcc + mnc; |
| for (AvailableNetworkInfo availableNetworkInfo : mAvailableNetworkInfos) { |
| if (availableNetworkInfo.getPriority() != priorityLevel) { |
| continue; |
| } |
| for (String availableMccMnc : availableNetworkInfo.getMccMncs()) { |
| if (TextUtils.equals(availableMccMnc, mccMnc)) { |
| return availableNetworkInfo.getSubId(); |
| } |
| } |
| } |
| |
| return SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| } |
| |
| public SubscriptionInfo getOpprotunisticSubInfo(int subId) { |
| if ((mOppSubscriptionInfos == null) || (mOppSubscriptionInfos.size() == 0)) { |
| return null; |
| } |
| for (SubscriptionInfo subscriptionInfo : mOppSubscriptionInfos) { |
| if (subscriptionInfo.getSubscriptionId() == subId) { |
| return subscriptionInfo; |
| } |
| } |
| return null; |
| } |
| |
| public boolean isOpprotunisticSub(int subId) { |
| if ((mOppSubscriptionInfos == null) || (mOppSubscriptionInfos.size() == 0)) { |
| return false; |
| } |
| for (SubscriptionInfo subscriptionInfo : mOppSubscriptionInfos) { |
| if (subscriptionInfo.getSubscriptionId() == subId) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public boolean hasOpprotunisticSub(List<AvailableNetworkInfo> availableNetworks) { |
| if ((availableNetworks == null) || (availableNetworks.size() == 0)) { |
| return false; |
| } |
| if ((mOppSubscriptionInfos == null) || (mOppSubscriptionInfos.size() == 0)) { |
| return false; |
| } |
| |
| for (AvailableNetworkInfo availableNetworkInfo : availableNetworks) { |
| if (!isOpprotunisticSub(availableNetworkInfo.getSubId())) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private boolean isAvtiveSub(int subId) { |
| return mSubscriptionManager.isActiveSubscriptionId(subId); |
| } |
| |
| private HashMap<Integer, IUpdateAvailableNetworksCallback> callbackStubs = new HashMap<>(); |
| |
| private void switchToSubscription(int subId) { |
| Intent callbackIntent = new Intent(ACTION_SUB_SWITCH); |
| callbackIntent.setClass(mContext, ONSProfileSelector.class); |
| callbackIntent.putExtra("sequenceId", getAndUpdateToken()); |
| callbackIntent.putExtra("subId", subId); |
| |
| PendingIntent replyIntent = PendingIntent.getService(mContext, |
| 1, callbackIntent, |
| Intent.FILL_IN_ACTION); |
| mSubscriptionManager.switchToSubscription(subId, replyIntent); |
| } |
| |
| private void onSubSwitchComplete(int subId) { |
| enableModem(subId, true); |
| mProfileSelectionCallback.onProfileSelectionDone(); |
| sendUpdateNetworksCallbackHelper(mNetworkScanCallback, |
| TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS); |
| } |
| |
| private int getAndUpdateToken() { |
| synchronized (mLock) { |
| return mSequenceId++; |
| } |
| } |
| |
| private ArrayList<AvailableNetworkInfo> getFilteredAvailableNetworks( |
| ArrayList<AvailableNetworkInfo> availableNetworks, |
| List<SubscriptionInfo> subscriptionInfoList) { |
| ArrayList<AvailableNetworkInfo> filteredAvailableNetworks = |
| new ArrayList<AvailableNetworkInfo>(); |
| |
| /* instead of checking each element of a list every element of the other, sort them in |
| the order of sub id and compare to improve the filtering performance. */ |
| Collections.sort(subscriptionInfoList, new SortSubInfo()); |
| Collections.sort(availableNetworks, new SortAvailableNetworks()); |
| int availableNetworksIndex = 0; |
| int subscriptionInfoListIndex = 0; |
| SubscriptionInfo subscriptionInfo; |
| AvailableNetworkInfo availableNetwork; |
| |
| while (availableNetworksIndex < availableNetworks.size() |
| && subscriptionInfoListIndex < subscriptionInfoList.size()) { |
| subscriptionInfo = subscriptionInfoList.get(subscriptionInfoListIndex); |
| availableNetwork = availableNetworks.get(availableNetworksIndex); |
| if (subscriptionInfo.getSubscriptionId() == availableNetwork.getSubId()) { |
| filteredAvailableNetworks.add(availableNetwork); |
| subscriptionInfoListIndex++; |
| availableNetworksIndex++; |
| } else if (subscriptionInfo.getSubscriptionId() < availableNetwork.getSubId()) { |
| subscriptionInfoListIndex++; |
| } else { |
| availableNetworksIndex++; |
| } |
| } |
| return filteredAvailableNetworks; |
| } |
| |
| private boolean isSame(ArrayList<AvailableNetworkInfo> availableNetworks1, |
| ArrayList<AvailableNetworkInfo> availableNetworks2) { |
| if ((availableNetworks1 == null) || (availableNetworks2 == null)) { |
| return false; |
| } |
| return new HashSet<>(availableNetworks1).equals(new HashSet<>(availableNetworks2)); |
| } |
| |
| private void sendUpdateNetworksCallbackHelper(IUpdateAvailableNetworksCallback callback, |
| int result) { |
| if (callback == null) return; |
| try { |
| callback.onComplete(result); |
| } catch (RemoteException exception) { |
| log("RemoteException " + exception); |
| } |
| } |
| |
| private void checkProfileUpdate(Object[] objects) { |
| ArrayList<AvailableNetworkInfo> availableNetworks = |
| (ArrayList<AvailableNetworkInfo>) objects[0]; |
| IUpdateAvailableNetworksCallback callbackStub = |
| (IUpdateAvailableNetworksCallback) objects[1]; |
| if (mOppSubscriptionInfos == null) { |
| logDebug("null subscription infos"); |
| return; |
| } |
| if (isSame(availableNetworks, mAvailableNetworkInfos)) { |
| return; |
| } |
| |
| stopProfileSelection(); |
| mIsEnabled = true; |
| mAvailableNetworkInfos = availableNetworks; |
| /* sort in the order of priority */ |
| Collections.sort(mAvailableNetworkInfos, new SortAvailableNetworksInPriority()); |
| logDebug("availableNetworks: " + availableNetworks); |
| |
| if (mOppSubscriptionInfos.size() > 0) { |
| logDebug("opportunistic subscriptions size " + mOppSubscriptionInfos.size()); |
| ArrayList<AvailableNetworkInfo> filteredAvailableNetworks = |
| getFilteredAvailableNetworks((ArrayList<AvailableNetworkInfo>)availableNetworks, |
| mOppSubscriptionInfos); |
| if ((filteredAvailableNetworks.size() == 1) |
| && ((filteredAvailableNetworks.get(0).getMccMncs() == null) |
| || (filteredAvailableNetworks.get(0).getMccMncs().size() == 0))) { |
| /* if subscription is not active, activate the sub */ |
| if (!mSubscriptionManager.isActiveSubId(filteredAvailableNetworks.get(0).getSubId())) { |
| mNetworkScanCallback = callbackStub; |
| switchToSubscription(filteredAvailableNetworks.get(0).getSubId()); |
| } else { |
| enableModem(filteredAvailableNetworks.get(0).getSubId(), true); |
| mProfileSelectionCallback.onProfileSelectionDone(); |
| sendUpdateNetworksCallbackHelper(callbackStub, |
| TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS); |
| } |
| } else { |
| mNetworkScanCallback = callbackStub; |
| /* start scan immediately */ |
| mNetworkScanCtlr.startFastNetworkScan(filteredAvailableNetworks); |
| } |
| } else if (mOppSubscriptionInfos.size() == 0) { |
| sendUpdateNetworksCallbackHelper(callbackStub, |
| TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS); |
| /* check if no profile */ |
| logDebug("stopping scan"); |
| mNetworkScanCtlr.stopNetworkScan(); |
| } |
| } |
| |
| private boolean isActiveSub(int subId) { |
| List<SubscriptionInfo> subscriptionInfos = |
| mSubscriptionManager.getActiveSubscriptionInfoList(false); |
| for (SubscriptionInfo subscriptionInfo : subscriptionInfos) { |
| if (subscriptionInfo.getSubscriptionId() == subId) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private int retrieveBestSubscription(List<CellInfo> results) { |
| /* sort the results according to signal strength level */ |
| Collections.sort(results, new Comparator<CellInfo>() { |
| @Override |
| public int compare(CellInfo cellInfo1, CellInfo cellInfo2) { |
| return getSignalLevel(cellInfo1) - getSignalLevel(cellInfo2); |
| } |
| }); |
| |
| for (int level = PRIORITY_HIGH; level < PRIORITY_LOW; level++) { |
| for (CellInfo result : results) { |
| /* get subscription id for the best network scan result */ |
| int subId = getSubIdUsingAvailableNetworks(getMcc(result), getMnc(result), level); |
| if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return subId; |
| } |
| } |
| } |
| |
| return SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| } |
| |
| private int getActiveOpportunisticSubId() { |
| List<SubscriptionInfo> subscriptionInfos = |
| mSubscriptionManager.getActiveSubscriptionInfoList(false); |
| for (SubscriptionInfo subscriptionInfo : subscriptionInfos) { |
| if (subscriptionInfo.isOpportunistic()) { |
| return subscriptionInfo.getSubscriptionId(); |
| } |
| } |
| |
| return SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| } |
| |
| private void disableOpportunisticModem() { |
| int subId = getActiveOpportunisticSubId(); |
| if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| enableModem(subId, false); |
| } |
| } |
| |
| private void enableModem(int subId, boolean enable) { |
| if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| int phoneId = SubscriptionManager.getPhoneId(subId); |
| mSubscriptionBoundTelephonyManager.enableModemForSlot(phoneId, enable); |
| } |
| } |
| |
| public boolean containsOpportunisticSubs(ArrayList<AvailableNetworkInfo> availableNetworks) { |
| if (mOppSubscriptionInfos == null) { |
| logDebug("received null subscription infos"); |
| return false; |
| } |
| |
| if (mOppSubscriptionInfos.size() > 0) { |
| logDebug("opportunistic subscriptions size " + mOppSubscriptionInfos.size()); |
| ArrayList<AvailableNetworkInfo> filteredAvailableNetworks = |
| getFilteredAvailableNetworks( |
| (ArrayList<AvailableNetworkInfo>)availableNetworks, mOppSubscriptionInfos); |
| if (filteredAvailableNetworks.size() > 0) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| public boolean isOpportunisticSubActive() { |
| if (mOppSubscriptionInfos == null) { |
| logDebug("received null subscription infos"); |
| return false; |
| } |
| |
| if (mOppSubscriptionInfos.size() > 0) { |
| logDebug("opportunistic subscriptions size " + mOppSubscriptionInfos.size()); |
| for (SubscriptionInfo subscriptionInfo : mOppSubscriptionInfos) { |
| if (mSubscriptionManager.isActiveSubId(subscriptionInfo.getSubscriptionId())) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| public void startProfileSelection(ArrayList<AvailableNetworkInfo> availableNetworks, |
| IUpdateAvailableNetworksCallback callbackStub) { |
| logDebug("startProfileSelection availableNetworks: " + availableNetworks); |
| if (availableNetworks == null || availableNetworks.size() == 0) { |
| return; |
| } |
| Object[] objects = new Object[]{availableNetworks, callbackStub}; |
| Message message = Message.obtain(mHandler, MSG_START_PROFILE_SELECTION, objects); |
| message.sendToTarget(); |
| } |
| |
| private void sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result) { |
| if (callback == null) return; |
| try { |
| callback.onComplete(result); |
| } catch (RemoteException exception) { |
| log("RemoteException " + exception); |
| } |
| } |
| |
| /** |
| * select opportunistic profile for data if passing a valid subId. |
| * @param subId : opportunistic subId or SubscriptionManager.DEFAULT_SUBSCRIPTION_ID if |
| * deselecting previously set preference. |
| */ |
| public void selectProfileForData(int subId, boolean needValidation, |
| ISetOpportunisticDataCallback callbackStub) { |
| if ((subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) |
| || (isOpprotunisticSub(subId) && isActiveSub(subId))) { |
| ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); |
| if (iSub == null) { |
| log("Could not get Subscription Service handle"); |
| sendSetOpptCallbackHelper(callbackStub, |
| TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED); |
| return; |
| } |
| try { |
| iSub.setPreferredDataSubscriptionId(subId, needValidation, callbackStub); |
| } catch (RemoteException ex) { |
| log("Could not connect to Subscription Service"); |
| sendSetOpptCallbackHelper(callbackStub, |
| TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED); |
| return; |
| } |
| mCurrentDataSubId = subId; |
| sendSetOpptCallbackHelper(callbackStub, TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS); |
| } else { |
| log("Inactive sub passed for preferred data " + subId); |
| sendSetOpptCallbackHelper(callbackStub, |
| TelephonyManager.SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER); |
| } |
| } |
| |
| public int getPreferredDataSubscriptionId() { |
| return mSubscriptionManager.getPreferredDataSubscriptionId(); |
| } |
| |
| /** |
| * stop profile selection procedure |
| */ |
| public void stopProfileSelection() { |
| if (mNetworkScanCallback != null) { |
| sendUpdateNetworksCallbackHelper(mNetworkScanCallback, |
| TelephonyManager.UPDATE_AVAILABLE_NETWORKS_ABORTED); |
| mNetworkScanCallback = null; |
| } |
| logDebug("stopProfileSelection"); |
| mNetworkScanCtlr.stopNetworkScan(); |
| disableOpportunisticModem(); |
| synchronized (mLock) { |
| mAvailableNetworkInfos = null; |
| mIsEnabled = false; |
| } |
| } |
| |
| @VisibleForTesting |
| protected void updateOpportunisticSubscriptions() { |
| synchronized (mLock) { |
| mOppSubscriptionInfos = mSubscriptionManager.getOpportunisticSubscriptions(); |
| } |
| } |
| |
| @VisibleForTesting |
| protected void init(Context c, ONSProfileSelectionCallback profileSelectionCallback) { |
| mContext = c; |
| mSequenceId = START_SEQUENCE_ID; |
| mProfileSelectionCallback = profileSelectionCallback; |
| mTelephonyManager = (TelephonyManager) |
| mContext.getSystemService(Context.TELEPHONY_SERVICE); |
| mSubscriptionBoundTelephonyManager = mTelephonyManager.createForSubscriptionId( |
| SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); |
| mSubscriptionManager = (SubscriptionManager) |
| mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); |
| mNetworkScanCtlr = new ONSNetworkScanCtlr(mContext, mSubscriptionBoundTelephonyManager, |
| mNetworkAvailableCallBack); |
| updateOpportunisticSubscriptions(); |
| mThread = new HandlerThread(LOG_TAG); |
| mThread.start(); |
| mHandler = new Handler(mThread.getLooper()) { |
| @Override |
| public void handleMessage(Message msg) { |
| switch (msg.what) { |
| case MSG_PROFILE_UPDATE: |
| synchronized (mLock) { |
| updateOpportunisticSubscriptions(); |
| } |
| break; |
| case MSG_START_PROFILE_SELECTION: |
| logDebug("Msg received for profile update"); |
| synchronized (mLock) { |
| checkProfileUpdate((Object[]) msg.obj); |
| } |
| break; |
| default: |
| log("invalid message"); |
| break; |
| } |
| } |
| }; |
| /* register for profile update events */ |
| mSubscriptionManager.addOnOpportunisticSubscriptionsChangedListener( |
| AsyncTask.SERIAL_EXECUTOR, mProfileChangeListener); |
| /* register for subscription switch intent */ |
| mContext.registerReceiver(mProfileSelectorBroadcastReceiver, |
| new IntentFilter(ACTION_SUB_SWITCH)); |
| } |
| |
| private void log(String msg) { |
| Rlog.d(LOG_TAG, msg); |
| } |
| |
| private void logDebug(String msg) { |
| if (DBG) { |
| Rlog.d(LOG_TAG, msg); |
| } |
| } |
| } |