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