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