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