Home | History | Annotate | Download | only in phone
      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.OperatorInfo;
     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 {
     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
    158     public void onCreate() {
    159         mState = QUERY_READY;
    160         mPhone = PhoneFactory.getDefaultPhone();
    161     }
    162 
    163     /**
    164      * Required for service implementation.
    165      */
    166     @Override
    167     public void onStart(Intent intent, int startId) {
    168     }
    169 
    170     /**
    171      * Handle the bind request.
    172      */
    173     @Override
    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      */
    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<OperatorInfo>) ar.result, exception);
    208                 } catch (RemoteException e) {
    209                 }
    210             }
    211 
    212             // finish up.
    213             mCallbacks.finishBroadcast();
    214         }
    215     }
    216 
    217     private static void log(String msg) {
    218         Log.d(LOG_TAG, msg);
    219     }
    220 }
    221