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