/* * Copyright (C) 2015 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.internal.telephony; import static android.telephony.SubscriptionManager.INVALID_PHONE_INDEX; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ISub; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.PhoneConstants; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.IllegalArgumentException; /** * Utility singleton to monitor subscription changes and help people act on them. * Uses Registrant model to post messages to handlers. * */ public class SubscriptionMonitor { private final RegistrantList mSubscriptionsChangedRegistrants[]; private final RegistrantList mDefaultDataSubChangedRegistrants[]; private final SubscriptionController mSubscriptionController; private final Context mContext; private final int mPhoneSubId[]; private int mDefaultDataSubId; private int mDefaultDataPhoneId; private final Object mLock = new Object(); private final static boolean VDBG = true; private final static String LOG_TAG = "SubscriptionMonitor"; private final static int MAX_LOGLINES = 100; private final LocalLog mLocalLog = new LocalLog(MAX_LOGLINES); public SubscriptionMonitor(ITelephonyRegistry tr, Context context, SubscriptionController subscriptionController, int numPhones) { try { tr.addOnSubscriptionsChangedListener("SubscriptionMonitor", mSubscriptionsChangedListener); } catch (RemoteException e) { } mSubscriptionController = subscriptionController; mContext = context; mSubscriptionsChangedRegistrants = new RegistrantList[numPhones]; mDefaultDataSubChangedRegistrants = new RegistrantList[numPhones]; mPhoneSubId = new int[numPhones]; mDefaultDataSubId = mSubscriptionController.getDefaultDataSubId(); mDefaultDataPhoneId = mSubscriptionController.getPhoneId(mDefaultDataSubId); for (int phoneId = 0; phoneId < numPhones; phoneId++) { mSubscriptionsChangedRegistrants[phoneId] = new RegistrantList(); mDefaultDataSubChangedRegistrants[phoneId] = new RegistrantList(); mPhoneSubId[phoneId] = mSubscriptionController.getSubIdUsingPhoneId(phoneId); } mContext.registerReceiver(mDefaultDataSubscriptionChangedReceiver, new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)); } @VisibleForTesting public SubscriptionMonitor() { mSubscriptionsChangedRegistrants = null; mDefaultDataSubChangedRegistrants = null; mSubscriptionController = null; mContext = null; mPhoneSubId = null; } private final IOnSubscriptionsChangedListener mSubscriptionsChangedListener = new IOnSubscriptionsChangedListener.Stub() { @Override public void onSubscriptionsChanged() { synchronized (mLock) { int newDefaultDataPhoneId = INVALID_PHONE_INDEX; for (int phoneId = 0; phoneId < mPhoneSubId.length; phoneId++) { final int newSubId = mSubscriptionController.getSubIdUsingPhoneId(phoneId); final int oldSubId = mPhoneSubId[phoneId]; if (oldSubId != newSubId) { log("Phone[" + phoneId + "] subId changed " + oldSubId + "->" + newSubId + ", " + mSubscriptionsChangedRegistrants[phoneId].size() + " registrants"); mPhoneSubId[phoneId] = newSubId; mSubscriptionsChangedRegistrants[phoneId].notifyRegistrants(); // if the default isn't set, just move along.. if (mDefaultDataSubId == INVALID_SUBSCRIPTION_ID) continue; // check if this affects default data if (newSubId == mDefaultDataSubId || oldSubId == mDefaultDataSubId) { log("mDefaultDataSubId = " + mDefaultDataSubId + ", " + mDefaultDataSubChangedRegistrants[phoneId].size() + " registrants"); mDefaultDataSubChangedRegistrants[phoneId].notifyRegistrants(); } } if (newSubId == mDefaultDataSubId) { newDefaultDataPhoneId = phoneId; } } mDefaultDataPhoneId = newDefaultDataPhoneId; } } }; private final BroadcastReceiver mDefaultDataSubscriptionChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final int newDefaultDataSubId = mSubscriptionController.getDefaultDataSubId(); synchronized (mLock) { if (mDefaultDataSubId != newDefaultDataSubId) { log("Default changed " + mDefaultDataSubId + "->" + newDefaultDataSubId); final int oldDefaultDataSubId = mDefaultDataSubId; final int oldDefaultDataPhoneId = mDefaultDataPhoneId; mDefaultDataSubId = newDefaultDataSubId; int newDefaultDataPhoneId = mSubscriptionController.getPhoneId(INVALID_SUBSCRIPTION_ID); if (newDefaultDataSubId != INVALID_SUBSCRIPTION_ID) { for (int phoneId = 0; phoneId < mPhoneSubId.length; phoneId++) { if (mPhoneSubId[phoneId] == newDefaultDataSubId) { newDefaultDataPhoneId = phoneId; if (VDBG) log("newDefaultDataPhoneId=" + newDefaultDataPhoneId); break; } } } if (newDefaultDataPhoneId != oldDefaultDataPhoneId) { log("Default phoneId changed " + oldDefaultDataPhoneId + "->" + newDefaultDataPhoneId + ", " + (invalidPhoneId(oldDefaultDataPhoneId) ? 0 : mDefaultDataSubChangedRegistrants[oldDefaultDataPhoneId].size()) + "," + (invalidPhoneId(newDefaultDataPhoneId) ? 0 : mDefaultDataSubChangedRegistrants[newDefaultDataPhoneId].size()) + " registrants"); mDefaultDataPhoneId = newDefaultDataPhoneId; if (!invalidPhoneId(oldDefaultDataPhoneId)) { mDefaultDataSubChangedRegistrants[oldDefaultDataPhoneId]. notifyRegistrants(); } if (!invalidPhoneId(newDefaultDataPhoneId)) { mDefaultDataSubChangedRegistrants[newDefaultDataPhoneId]. notifyRegistrants(); } } } } } }; public void registerForSubscriptionChanged(int phoneId, Handler h, int what, Object o) { if (invalidPhoneId(phoneId)) { throw new IllegalArgumentException("Invalid PhoneId"); } Registrant r = new Registrant(h, what, o); mSubscriptionsChangedRegistrants[phoneId].add(r); r.notifyRegistrant(); } public void unregisterForSubscriptionChanged(int phoneId, Handler h) { if (invalidPhoneId(phoneId)) { throw new IllegalArgumentException("Invalid PhoneId"); } mSubscriptionsChangedRegistrants[phoneId].remove(h); } public void registerForDefaultDataSubscriptionChanged(int phoneId, Handler h, int what, Object o) { if (invalidPhoneId(phoneId)) { throw new IllegalArgumentException("Invalid PhoneId"); } Registrant r = new Registrant(h, what, o); mDefaultDataSubChangedRegistrants[phoneId].add(r); r.notifyRegistrant(); } public void unregisterForDefaultDataSubscriptionChanged(int phoneId, Handler h) { if (invalidPhoneId(phoneId)) { throw new IllegalArgumentException("Invalid PhoneId"); } mDefaultDataSubChangedRegistrants[phoneId].remove(h); } private boolean invalidPhoneId(int phoneId) { if (phoneId >= 0 && phoneId < mPhoneSubId.length) return false; return true; } private void log(String s) { Rlog.d(LOG_TAG, s); mLocalLog.log(s); } public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { synchronized (mLock) { mLocalLog.dump(fd, printWriter, args); } } }