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