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