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