• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.phone;
18 
19 import android.app.Service;
20 import android.content.Context;
21 import android.content.Intent;
22 import com.android.internal.telephony.OperatorInfo;
23 import android.os.AsyncResult;
24 import android.os.Binder;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Message;
28 import android.os.RemoteCallbackList;
29 import android.os.RemoteException;
30 import android.telephony.SubscriptionManager;
31 import com.android.internal.telephony.Phone;
32 import com.android.internal.telephony.PhoneFactory;
33 import android.util.Log;
34 
35 import java.util.ArrayList;
36 
37 /**
38  * Service code used to assist in querying the network for service
39  * availability.
40  */
41 public class NetworkQueryService extends Service {
42     // debug data
43     private static final String LOG_TAG = "NetworkQuery";
44     private static final boolean DBG = true;
45 
46     // static events
47     private static final int EVENT_NETWORK_SCAN_COMPLETED = 100;
48 
49     // static states indicating the query status of the service
50     private static final int QUERY_READY = -1;
51     private static final int QUERY_IS_RUNNING = -2;
52 
53     // error statuses that will be retured in the callback.
54     public static final int QUERY_OK = 0;
55     public static final int QUERY_EXCEPTION = 1;
56 
57     /** state of the query service */
58     private int mState;
59 
60     /**
61      * Class for clients to access.  Because we know this service always
62      * runs in the same process as its clients, we don't need to deal with
63      * IPC.
64      */
65     public class LocalBinder extends Binder {
getService()66         INetworkQueryService getService() {
67             return mBinder;
68         }
69     }
70     private final IBinder mLocalBinder = new LocalBinder();
71 
72     /**
73      * Local handler to receive the network query compete callback
74      * from the RIL.
75      */
76     Handler mHandler = new Handler() {
77         @Override
78         public void handleMessage(Message msg) {
79             switch (msg.what) {
80                 // if the scan is complete, broadcast the results.
81                 // to all registerd callbacks.
82                 case EVENT_NETWORK_SCAN_COMPLETED:
83                     if (DBG) log("scan completed, broadcasting results");
84                     broadcastQueryResults((AsyncResult) msg.obj);
85                     break;
86             }
87         }
88     };
89 
90     /**
91      * List of callback objects, also used to synchronize access to
92      * itself and to changes in state.
93      */
94     final RemoteCallbackList<INetworkQueryServiceCallback> mCallbacks =
95         new RemoteCallbackList<INetworkQueryServiceCallback> ();
96 
97     /**
98      * Implementation of the INetworkQueryService interface.
99      */
100     private final INetworkQueryService.Stub mBinder = new INetworkQueryService.Stub() {
101 
102         /**
103          * Starts a query with a INetworkQueryServiceCallback object if
104          * one has not been started yet.  Ignore the new query request
105          * if the query has been started already.  Either way, place the
106          * callback object in the queue to be notified upon request
107          * completion.
108          */
109         public void startNetworkQuery(INetworkQueryServiceCallback cb, int phoneId) {
110             if (cb != null) {
111                 // register the callback to the list of callbacks.
112                 synchronized (mCallbacks) {
113                     mCallbacks.register(cb);
114                     if (DBG) log("registering callback " + cb.getClass().toString());
115 
116                     switch (mState) {
117                         case QUERY_READY:
118                             // TODO: we may want to install a timeout here in case we
119                             // do not get a timely response from the RIL.
120                             Phone phone = PhoneFactory.getPhone(phoneId);
121                             if (phone != null) {
122                                 phone.getAvailableNetworks(
123                                         mHandler.obtainMessage(EVENT_NETWORK_SCAN_COMPLETED));
124                                 mState = QUERY_IS_RUNNING;
125                                 if (DBG) log("starting new query");
126                             } else {
127                                 if (DBG) {
128                                     log("phone is null");
129                                 }
130                             }
131                             break;
132 
133                         // do nothing if we're currently busy.
134                         case QUERY_IS_RUNNING:
135                             if (DBG) log("query already in progress");
136                             break;
137                         default:
138                     }
139                 }
140             }
141         }
142 
143         /**
144          * Stops a query with a INetworkQueryServiceCallback object as
145          * a token.
146          */
147         public void stopNetworkQuery(INetworkQueryServiceCallback cb) {
148             // currently we just unregister the callback, since there is
149             // no way to tell the RIL to terminate the query request.
150             // This means that the RIL may still be busy after the stop
151             // request was made, but the state tracking logic ensures
152             // that the delay will only last for 1 request even with
153             // repeated button presses in the NetworkSetting activity.
154             unregisterCallback(cb);
155         }
156 
157         /**
158          * Unregisters the callback without impacting an underlying query.
159          */
160         public void unregisterCallback(INetworkQueryServiceCallback cb) {
161             if (cb != null) {
162                 synchronized (mCallbacks) {
163                     if (DBG) log("unregistering callback " + cb.getClass().toString());
164                     mCallbacks.unregister(cb);
165                 }
166             }
167         }
168     };
169 
170     @Override
onCreate()171     public void onCreate() {
172         mState = QUERY_READY;
173     }
174 
175     /**
176      * Required for service implementation.
177      */
178     @Override
onStart(Intent intent, int startId)179     public void onStart(Intent intent, int startId) {
180     }
181 
182     /**
183      * Handle the bind request.
184      */
185     @Override
onBind(Intent intent)186     public IBinder onBind(Intent intent) {
187         // TODO: Currently, return only the LocalBinder instance.  If we
188         // end up requiring support for a remote binder, we will need to
189         // return mBinder as well, depending upon the intent.
190         if (DBG) log("binding service implementation");
191         return mLocalBinder;
192     }
193 
194     /**
195      * Broadcast the results from the query to all registered callback
196      * objects.
197      */
broadcastQueryResults(AsyncResult ar)198     private void broadcastQueryResults (AsyncResult ar) {
199         // reset the state.
200         synchronized (mCallbacks) {
201             mState = QUERY_READY;
202 
203             // see if we need to do any work.
204             if (ar == null) {
205                 if (DBG) log("AsyncResult is null.");
206                 return;
207             }
208 
209             // TODO: we may need greater accuracy here, but for now, just a
210             // simple status integer will suffice.
211             int exception = (ar.exception == null) ? QUERY_OK : QUERY_EXCEPTION;
212             if (DBG) log("AsyncResult has exception " + exception);
213 
214             // Make the calls to all the registered callbacks.
215             for (int i = (mCallbacks.beginBroadcast() - 1); i >= 0; i--) {
216                 INetworkQueryServiceCallback cb = mCallbacks.getBroadcastItem(i);
217                 if (DBG) log("broadcasting results to " + cb.getClass().toString());
218                 try {
219                     cb.onQueryComplete((ArrayList<OperatorInfo>) ar.result, exception);
220                 } catch (RemoteException e) {
221                 }
222             }
223 
224             // finish up.
225             mCallbacks.finishBroadcast();
226         }
227     }
228 
log(String msg)229     private static void log(String msg) {
230         Log.d(LOG_TAG, msg);
231     }
232 }
233