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 17package com.android.internal.telephony; 18 19import static android.telephony.SubscriptionManager.INVALID_PHONE_INDEX; 20import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 21 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.os.Handler; 27import android.os.Registrant; 28import android.os.RegistrantList; 29import android.os.RemoteException; 30import android.os.ServiceManager; 31import android.telephony.Rlog; 32import android.telephony.SubscriptionManager; 33import android.util.LocalLog; 34 35import com.android.internal.annotations.VisibleForTesting; 36import com.android.internal.telephony.ISub; 37import com.android.internal.telephony.IOnSubscriptionsChangedListener; 38import com.android.internal.telephony.ITelephonyRegistry; 39import com.android.internal.telephony.PhoneConstants; 40 41import java.io.FileDescriptor; 42import java.io.PrintWriter; 43import java.lang.IllegalArgumentException; 44 45/** 46 * Utility singleton to monitor subscription changes and help people act on them. 47 * Uses Registrant model to post messages to handlers. 48 * 49 */ 50public class SubscriptionMonitor { 51 52 private final RegistrantList mSubscriptionsChangedRegistrants[]; 53 private final RegistrantList mDefaultDataSubChangedRegistrants[]; 54 55 private final SubscriptionController mSubscriptionController; 56 private final Context mContext; 57 58 private final int mPhoneSubId[]; 59 private int mDefaultDataSubId; 60 private int mDefaultDataPhoneId; 61 62 private final Object mLock = new Object(); 63 64 private final static boolean VDBG = true; 65 private final static String LOG_TAG = "SubscriptionMonitor"; 66 67 private final static int MAX_LOGLINES = 100; 68 private final LocalLog mLocalLog = new LocalLog(MAX_LOGLINES); 69 70 public SubscriptionMonitor(ITelephonyRegistry tr, Context context, 71 SubscriptionController subscriptionController, int numPhones) { 72 try { 73 tr.addOnSubscriptionsChangedListener("SubscriptionMonitor", 74 mSubscriptionsChangedListener); 75 } catch (RemoteException e) { 76 } 77 78 mSubscriptionController = subscriptionController; 79 mContext = context; 80 81 mSubscriptionsChangedRegistrants = new RegistrantList[numPhones]; 82 mDefaultDataSubChangedRegistrants = new RegistrantList[numPhones]; 83 mPhoneSubId = new int[numPhones]; 84 85 mDefaultDataSubId = mSubscriptionController.getDefaultDataSubId(); 86 mDefaultDataPhoneId = mSubscriptionController.getPhoneId(mDefaultDataSubId); 87 88 for (int phoneId = 0; phoneId < numPhones; phoneId++) { 89 mSubscriptionsChangedRegistrants[phoneId] = new RegistrantList(); 90 mDefaultDataSubChangedRegistrants[phoneId] = new RegistrantList(); 91 mPhoneSubId[phoneId] = mSubscriptionController.getSubIdUsingPhoneId(phoneId); 92 } 93 94 mContext.registerReceiver(mDefaultDataSubscriptionChangedReceiver, 95 new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)); 96 } 97 98 @VisibleForTesting 99 public SubscriptionMonitor() { 100 mSubscriptionsChangedRegistrants = null; 101 mDefaultDataSubChangedRegistrants = null; 102 mSubscriptionController = null; 103 mContext = null; 104 mPhoneSubId = null; 105 } 106 107 private final IOnSubscriptionsChangedListener mSubscriptionsChangedListener = 108 new IOnSubscriptionsChangedListener.Stub() { 109 @Override 110 public void onSubscriptionsChanged() { 111 synchronized (mLock) { 112 int newDefaultDataPhoneId = INVALID_PHONE_INDEX; 113 for (int phoneId = 0; phoneId < mPhoneSubId.length; phoneId++) { 114 final int newSubId = mSubscriptionController.getSubIdUsingPhoneId(phoneId); 115 final int oldSubId = mPhoneSubId[phoneId]; 116 if (oldSubId != newSubId) { 117 log("Phone[" + phoneId + "] subId changed " + oldSubId + "->" + 118 newSubId + ", " + 119 mSubscriptionsChangedRegistrants[phoneId].size() + " registrants"); 120 mPhoneSubId[phoneId] = newSubId; 121 mSubscriptionsChangedRegistrants[phoneId].notifyRegistrants(); 122 123 // if the default isn't set, just move along.. 124 if (mDefaultDataSubId == INVALID_SUBSCRIPTION_ID) continue; 125 126 // check if this affects default data 127 if (newSubId == mDefaultDataSubId || oldSubId == mDefaultDataSubId) { 128 log("mDefaultDataSubId = " + mDefaultDataSubId + ", " + 129 mDefaultDataSubChangedRegistrants[phoneId].size() + 130 " registrants"); 131 mDefaultDataSubChangedRegistrants[phoneId].notifyRegistrants(); 132 } 133 } 134 if (newSubId == mDefaultDataSubId) { 135 newDefaultDataPhoneId = phoneId; 136 } 137 } 138 mDefaultDataPhoneId = newDefaultDataPhoneId; 139 } 140 } 141 }; 142 143 private final BroadcastReceiver mDefaultDataSubscriptionChangedReceiver = 144 new BroadcastReceiver() { 145 @Override 146 public void onReceive(Context context, Intent intent) { 147 final int newDefaultDataSubId = mSubscriptionController.getDefaultDataSubId(); 148 synchronized (mLock) { 149 if (mDefaultDataSubId != newDefaultDataSubId) { 150 log("Default changed " + mDefaultDataSubId + "->" + newDefaultDataSubId); 151 final int oldDefaultDataSubId = mDefaultDataSubId; 152 final int oldDefaultDataPhoneId = mDefaultDataPhoneId; 153 mDefaultDataSubId = newDefaultDataSubId; 154 155 int newDefaultDataPhoneId = 156 mSubscriptionController.getPhoneId(INVALID_SUBSCRIPTION_ID); 157 if (newDefaultDataSubId != INVALID_SUBSCRIPTION_ID) { 158 for (int phoneId = 0; phoneId < mPhoneSubId.length; phoneId++) { 159 if (mPhoneSubId[phoneId] == newDefaultDataSubId) { 160 newDefaultDataPhoneId = phoneId; 161 if (VDBG) log("newDefaultDataPhoneId=" + newDefaultDataPhoneId); 162 break; 163 } 164 } 165 } 166 if (newDefaultDataPhoneId != oldDefaultDataPhoneId) { 167 log("Default phoneId changed " + oldDefaultDataPhoneId + "->" + 168 newDefaultDataPhoneId + ", " + 169 (invalidPhoneId(oldDefaultDataPhoneId) ? 170 0 : 171 mDefaultDataSubChangedRegistrants[oldDefaultDataPhoneId].size()) + 172 "," + (invalidPhoneId(newDefaultDataPhoneId) ? 173 0 : 174 mDefaultDataSubChangedRegistrants[newDefaultDataPhoneId].size()) + 175 " registrants"); 176 mDefaultDataPhoneId = newDefaultDataPhoneId; 177 if (!invalidPhoneId(oldDefaultDataPhoneId)) { 178 mDefaultDataSubChangedRegistrants[oldDefaultDataPhoneId]. 179 notifyRegistrants(); 180 } 181 if (!invalidPhoneId(newDefaultDataPhoneId)) { 182 mDefaultDataSubChangedRegistrants[newDefaultDataPhoneId]. 183 notifyRegistrants(); 184 } 185 } 186 } 187 } 188 } 189 }; 190 191 public void registerForSubscriptionChanged(int phoneId, Handler h, int what, Object o) { 192 if (invalidPhoneId(phoneId)) { 193 throw new IllegalArgumentException("Invalid PhoneId"); 194 } 195 Registrant r = new Registrant(h, what, o); 196 mSubscriptionsChangedRegistrants[phoneId].add(r); 197 r.notifyRegistrant(); 198 } 199 200 public void unregisterForSubscriptionChanged(int phoneId, Handler h) { 201 if (invalidPhoneId(phoneId)) { 202 throw new IllegalArgumentException("Invalid PhoneId"); 203 } 204 mSubscriptionsChangedRegistrants[phoneId].remove(h); 205 } 206 207 public void registerForDefaultDataSubscriptionChanged(int phoneId, Handler h, int what, 208 Object o) { 209 if (invalidPhoneId(phoneId)) { 210 throw new IllegalArgumentException("Invalid PhoneId"); 211 } 212 Registrant r = new Registrant(h, what, o); 213 mDefaultDataSubChangedRegistrants[phoneId].add(r); 214 r.notifyRegistrant(); 215 } 216 217 public void unregisterForDefaultDataSubscriptionChanged(int phoneId, Handler h) { 218 if (invalidPhoneId(phoneId)) { 219 throw new IllegalArgumentException("Invalid PhoneId"); 220 } 221 mDefaultDataSubChangedRegistrants[phoneId].remove(h); 222 } 223 224 private boolean invalidPhoneId(int phoneId) { 225 if (phoneId >= 0 && phoneId < mPhoneSubId.length) return false; 226 return true; 227 } 228 229 private void log(String s) { 230 Rlog.d(LOG_TAG, s); 231 mLocalLog.log(s); 232 } 233 234 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 235 synchronized (mLock) { 236 mLocalLog.dump(fd, printWriter, args); 237 } 238 } 239} 240