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