1 /* 2 * Copyright (c) 2011 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.internal.telephony.cdma; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.content.Context; 21 import android.os.AsyncResult; 22 import android.os.Build; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.os.Registrant; 26 import android.os.RegistrantList; 27 import android.provider.Settings; 28 29 import com.android.internal.telephony.CommandsInterface; 30 import com.android.internal.telephony.Phone; 31 import com.android.telephony.Rlog; 32 33 import java.util.concurrent.atomic.AtomicInteger; 34 35 /** 36 * Class that handles the CDMA subscription source changed events from RIL 37 */ 38 public class CdmaSubscriptionSourceManager extends Handler { 39 static final String LOG_TAG = "CdmaSSM"; 40 private static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 1; 41 private static final int EVENT_GET_CDMA_SUBSCRIPTION_SOURCE = 2; 42 private static final int EVENT_RADIO_ON = 3; 43 private static final int EVENT_SUBSCRIPTION_STATUS_CHANGED = 4; 44 45 // To know subscription is activated 46 private static final int SUBSCRIPTION_ACTIVATED = 1; 47 48 public static final int SUBSCRIPTION_SOURCE_UNKNOWN = -1; 49 public static final int SUBSCRIPTION_FROM_RUIM = 0; /* CDMA subscription from RUIM */ 50 public static final int SUBSCRIPTION_FROM_NV = 1; /* CDMA subscription from NV */ 51 52 private static CdmaSubscriptionSourceManager sInstance; 53 private static final Object sReferenceCountMonitor = new Object(); 54 private static int sReferenceCount = 0; 55 56 // ***** Instance Variables 57 private CommandsInterface mCi; 58 private RegistrantList mCdmaSubscriptionSourceChangedRegistrants = new RegistrantList(); 59 60 // Type of CDMA subscription source 61 private AtomicInteger mCdmaSubscriptionSource = 62 new AtomicInteger(Phone.PREFERRED_CDMA_SUBSCRIPTION); 63 64 // Constructor CdmaSubscriptionSourceManager(Context context, CommandsInterface ci)65 private CdmaSubscriptionSourceManager(Context context, CommandsInterface ci) { 66 mCi = ci; 67 mCi.registerForCdmaSubscriptionChanged(this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); 68 mCi.registerForOn(this, EVENT_RADIO_ON, null); 69 int subscriptionSource = getDefault(context); 70 log("cdmaSSM constructor: " + subscriptionSource); 71 mCdmaSubscriptionSource.set(subscriptionSource); 72 mCi.registerForSubscriptionStatusChanged(this, EVENT_SUBSCRIPTION_STATUS_CHANGED, null); 73 } 74 75 /** 76 * This function creates a single instance of this class 77 * 78 * @return object of type CdmaSubscriptionSourceManager 79 */ 80 @UnsupportedAppUsage getInstance(Context context, CommandsInterface ci, Handler h, int what, Object obj)81 public static CdmaSubscriptionSourceManager getInstance(Context context, 82 CommandsInterface ci, Handler h, int what, Object obj) { 83 synchronized (sReferenceCountMonitor) { 84 if (null == sInstance) { 85 sInstance = new CdmaSubscriptionSourceManager(context, ci); 86 } 87 CdmaSubscriptionSourceManager.sReferenceCount++; 88 } 89 sInstance.registerForCdmaSubscriptionSourceChanged(h, what, obj); 90 return sInstance; 91 } 92 93 /** 94 * Unregisters for the registered event with RIL 95 */ dispose(Handler h)96 public void dispose(Handler h) { 97 mCdmaSubscriptionSourceChangedRegistrants.remove(h); 98 synchronized (sReferenceCountMonitor) { 99 sReferenceCount--; 100 if (sReferenceCount <= 0) { 101 mCi.unregisterForCdmaSubscriptionChanged(this); 102 mCi.unregisterForOn(this); 103 mCi.unregisterForSubscriptionStatusChanged(this); 104 sInstance = null; 105 } 106 } 107 } 108 109 /* 110 * (non-Javadoc) 111 * @see android.os.Handler#handleMessage(android.os.Message) 112 */ 113 @Override handleMessage(Message msg)114 public void handleMessage(Message msg) { 115 AsyncResult ar; 116 switch (msg.what) { 117 case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED: 118 case EVENT_GET_CDMA_SUBSCRIPTION_SOURCE: 119 { 120 log("CDMA_SUBSCRIPTION_SOURCE event = " + msg.what); 121 ar = (AsyncResult) msg.obj; 122 handleGetCdmaSubscriptionSource(ar); 123 } 124 break; 125 case EVENT_RADIO_ON: { 126 mCi.getCdmaSubscriptionSource(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_SOURCE)); 127 } 128 break; 129 case EVENT_SUBSCRIPTION_STATUS_CHANGED: { 130 log("EVENT_SUBSCRIPTION_STATUS_CHANGED"); 131 ar = (AsyncResult)msg.obj; 132 if (ar.exception == null) { 133 int actStatus = ((int[])ar.result)[0]; 134 log("actStatus = " + actStatus); 135 if (actStatus == SUBSCRIPTION_ACTIVATED) { // Subscription Activated 136 // In case of multi-SIM, framework should wait for the subscription ready 137 // to send any request to RIL. Otherwise it will return failure. 138 Rlog.v(LOG_TAG,"get Cdma Subscription Source"); 139 mCi.getCdmaSubscriptionSource( 140 obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_SOURCE)); 141 } 142 } else { 143 logw("EVENT_SUBSCRIPTION_STATUS_CHANGED, Exception:" + ar.exception); 144 } 145 } 146 break; 147 default: 148 super.handleMessage(msg); 149 } 150 } 151 152 /** 153 * Returns the current CDMA subscription source value 154 * @return CDMA subscription source value 155 */ 156 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getCdmaSubscriptionSource()157 public int getCdmaSubscriptionSource() { 158 log("getcdmasubscriptionSource: " + mCdmaSubscriptionSource.get()); 159 return mCdmaSubscriptionSource.get(); 160 } 161 162 /** 163 * Gets the default CDMA subscription source 164 * 165 * @return Default CDMA subscription source from Settings DB if present. 166 */ getDefault(Context context)167 public static int getDefault(Context context) { 168 // Get the default value from the Settings 169 int subscriptionSource = Settings.Global.getInt(context.getContentResolver(), 170 Settings.Global.CDMA_SUBSCRIPTION_MODE, Phone.PREFERRED_CDMA_SUBSCRIPTION); 171 Rlog.d(LOG_TAG, "subscriptionSource from settings: " + subscriptionSource); 172 return subscriptionSource; 173 } 174 175 /** 176 * Clients automatically register for CDMA subscription source changed event 177 * when they get an instance of this object. 178 */ registerForCdmaSubscriptionSourceChanged(Handler h, int what, Object obj)179 private void registerForCdmaSubscriptionSourceChanged(Handler h, int what, Object obj) { 180 Registrant r = new Registrant (h, what, obj); 181 mCdmaSubscriptionSourceChangedRegistrants.add(r); 182 } 183 184 /** 185 * Handles the call to get the subscription source 186 * 187 * @param ar AsyncResult object that contains the result of get CDMA 188 * subscription source call 189 */ handleGetCdmaSubscriptionSource(AsyncResult ar)190 private void handleGetCdmaSubscriptionSource(AsyncResult ar) { 191 if ((ar.exception == null) && (ar.result != null)) { 192 int newSubscriptionSource = ((int[]) ar.result)[0]; 193 194 if (newSubscriptionSource != mCdmaSubscriptionSource.get()) { 195 log("Subscription Source Changed : " + mCdmaSubscriptionSource + " >> " 196 + newSubscriptionSource); 197 mCdmaSubscriptionSource.set(newSubscriptionSource); 198 199 // Notify registrants of the new CDMA subscription source 200 mCdmaSubscriptionSourceChangedRegistrants.notifyRegistrants(new AsyncResult(null, 201 null, null)); 202 } 203 } else { 204 // GET_CDMA_SUBSCRIPTION is returning Failure. Probably because modem created GSM Phone. 205 logw("Unable to get CDMA Subscription Source, Exception: " + ar.exception 206 + ", result: " + ar.result); 207 } 208 } 209 log(String s)210 private void log(String s) { 211 Rlog.d(LOG_TAG, s); 212 } 213 logw(String s)214 private void logw(String s) { 215 Rlog.w(LOG_TAG, s); 216 } 217 218 } 219