Home | History | Annotate | Download | only in dataconnection
      1 /*
      2 * Copyright (C) 2011-2014 MediaTek Inc.
      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.internal.telephony.dataconnection;
     18 
     19 import com.android.internal.util.AsyncChannel;
     20 import com.android.internal.util.Protocol;
     21 import com.android.internal.util.State;
     22 import com.android.internal.util.StateMachine;
     23 
     24 import com.android.internal.telephony.Phone;
     25 import com.android.internal.telephony.PhoneConstants;
     26 import com.android.internal.telephony.PhoneBase;
     27 import com.android.internal.telephony.PhoneProxy;
     28 
     29 import android.os.AsyncResult;
     30 import android.os.Handler;
     31 import android.os.Message;
     32 import android.os.Registrant;
     33 import android.os.RegistrantList;
     34 import android.text.TextUtils;
     35 
     36 import android.util.Log;
     37 
     38 import java.util.HashSet;
     39 import java.util.Iterator;
     40 
     41 public class DcSwitchState extends StateMachine {
     42     private static final boolean DBG = true;
     43     private static final boolean VDBG = false;
     44     private static final String LOG_TAG = "DcSwitchState";
     45 
     46     // ***** Event codes for driving the state machine
     47     private static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER + 0x00001000;
     48     private static final int EVENT_CONNECT = BASE + 0;
     49     private static final int EVENT_DISCONNECT = BASE + 1;
     50     private static final int EVENT_CLEANUP_ALL = BASE + 2;
     51     private static final int EVENT_CONNECTED = BASE + 3;
     52     private static final int EVENT_DETACH_DONE = BASE + 4;
     53     private static final int EVENT_TO_IDLE_DIRECTLY = BASE + 5;
     54     private static final int EVENT_TO_ACTING_DIRECTLY = BASE + 6;
     55 
     56     private int mId;
     57     private Phone mPhone;
     58     private AsyncChannel mAc;
     59     private RegistrantList mIdleRegistrants = new RegistrantList();
     60     private HashSet<String> mApnTypes = new HashSet<String>();
     61 
     62     private IdleState     mIdleState = new IdleState();
     63     private ActingState   mActingState = new ActingState();
     64     private ActedState    mActedState = new ActedState();
     65     private DeactingState mDeactingState = new DeactingState();
     66     private DefaultState  mDefaultState = new DefaultState();
     67 
     68     protected DcSwitchState(Phone phone, String name, int id) {
     69         super(name);
     70         if (DBG) log("DcSwitchState constructor E");
     71         mPhone = phone;
     72         mId = id;
     73 
     74         addState(mDefaultState);
     75         addState(mIdleState, mDefaultState);
     76         addState(mActingState, mDefaultState);
     77         addState(mActedState, mDefaultState);
     78         addState(mDeactingState, mDefaultState);
     79         setInitialState(mIdleState);
     80 
     81         if (DBG) log("DcSwitchState constructor X");
     82     }
     83 
     84     private int setupConnection(String type) {
     85         mApnTypes.add(type);
     86         log("DcSwitchState:setupConnection type = " + type);
     87 //        return mPhone.enableApnType(type); TODO
     88         return PhoneConstants.APN_REQUEST_STARTED;
     89     }
     90 
     91     private int teardownConnection(String type) {
     92         mApnTypes.remove(type);
     93         if (mApnTypes.isEmpty()) {
     94             log("No APN is using, then clean up all");
     95             // Since last type is removed from mApnTypes and will not be disabled in requestDataIdle()
     96 //            mPhone.disableApnType(type); TODO
     97             requestDataIdle();
     98             transitionTo(mDeactingState);
     99             return PhoneConstants.APN_REQUEST_STARTED;
    100         } else {
    101 //            return mPhone.disableApnType(type); TODO
    102             return PhoneConstants.APN_REQUEST_STARTED;
    103         }
    104     }
    105 
    106     private void requestDataIdle() {
    107         if (DBG) log("requestDataIdle is triggered");
    108         Iterator<String> itrType = mApnTypes.iterator();
    109         while (itrType.hasNext()) {
    110 //            mPhone.disableApnType(itrType.next()); TODO
    111         }
    112         mApnTypes.clear();
    113         PhoneBase pb = (PhoneBase)((PhoneProxy)mPhone).getActivePhone();
    114         pb.mCi.setDataAllowed(false, obtainMessage(EVENT_DETACH_DONE));
    115     }
    116 
    117     public void notifyDataConnection(int phoneId, String state, String reason,
    118             String apnName, String apnType, boolean unavailable) {
    119         if (phoneId == mId &&
    120                 TextUtils.equals(state, PhoneConstants.DataState.CONNECTED.toString())) {
    121             sendMessage(obtainMessage(EVENT_CONNECTED));
    122         }
    123     }
    124 
    125     public void cleanupAllConnection() {
    126         sendMessage(obtainMessage(EVENT_CLEANUP_ALL));
    127     }
    128 
    129     public void registerForIdle(Handler h, int what, Object obj) {
    130         Registrant r = new Registrant(h, what, obj);
    131         mIdleRegistrants.add(r);
    132     }
    133 
    134     public void unregisterForIdle(Handler h) {
    135         mIdleRegistrants.remove(h);
    136     }
    137 
    138     public void transitToIdleState() {
    139         sendMessage(obtainMessage(EVENT_TO_IDLE_DIRECTLY));
    140     }
    141 
    142     public void transitToActingState() {
    143         sendMessage(obtainMessage(EVENT_TO_ACTING_DIRECTLY));
    144     }
    145 
    146     private class IdleState extends State {
    147         @Override
    148         public void enter() {
    149             mIdleRegistrants.notifyRegistrants();
    150         }
    151 
    152         @Override
    153         public boolean processMessage(Message msg) {
    154             boolean retVal;
    155 
    156             switch (msg.what) {
    157                 case DcSwitchAsyncChannel.REQ_CONNECT:
    158                 case EVENT_CONNECT: {
    159                     String type = (String)msg.obj;
    160                     if (DBG) {
    161                         log("IdleState: REQ_CONNECT/EVENT_CONNECT(" +
    162                             msg.what + ") type=" + type);
    163                     }
    164 
    165                     PhoneBase pb = (PhoneBase)((PhoneProxy)mPhone).getActivePhone();
    166                     pb.mCi.setDataAllowed(true, null);
    167 
    168                     int result = setupConnection(type);
    169                     if (msg.what == DcSwitchAsyncChannel.REQ_CONNECT) {
    170                             mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_CONNECT, result);
    171                     }
    172                     transitionTo(mActingState);
    173                     retVal = HANDLED;
    174                     break;
    175                 }
    176                 case DcSwitchAsyncChannel.REQ_DISCONNECT: {
    177                     String type = (String)msg.obj;
    178                     if (DBG) {
    179                         log("IdleState: DcSwitchAsyncChannel.REQ_DISCONNECT type=" + type);
    180                     }
    181                     mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_DISCONNECT,
    182                         PhoneConstants.APN_ALREADY_INACTIVE);
    183                     retVal = HANDLED;
    184                     break;
    185                 }
    186                 case EVENT_CLEANUP_ALL: {
    187                     if (DBG) {
    188                         log("IdleState: EVENT_CLEANUP_ALL" );
    189                     }
    190                     requestDataIdle();
    191                     retVal = HANDLED;
    192                     break;
    193                 }
    194                 case EVENT_CONNECTED: {
    195                     if (DBG) {
    196                         log("IdleState: Receive invalid event EVENT_CONNECTED!");
    197                     }
    198                     retVal = HANDLED;
    199                     break;
    200                 }
    201                 default:
    202                     if (VDBG) {
    203                         log("IdleState: nothandled msg.what=0x" +
    204                                 Integer.toHexString(msg.what));
    205                     }
    206                     retVal = NOT_HANDLED;
    207                     break;
    208             }
    209             return retVal;
    210         }
    211     }
    212 
    213     private class ActingState extends State {
    214         @Override
    215         public boolean processMessage(Message msg) {
    216             boolean retVal;
    217 
    218             switch (msg.what) {
    219                 case DcSwitchAsyncChannel.REQ_CONNECT:
    220                 case EVENT_CONNECT: {
    221                     String type = (String)msg.obj;
    222                     if (DBG) {
    223                         log("ActingState: REQ_CONNECT/EVENT_CONNECT(" + msg.what +
    224                             ") type=" + type);
    225                     }
    226                     int result = setupConnection(type);
    227                     if (msg.what == DcSwitchAsyncChannel.REQ_CONNECT) {
    228                         mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_CONNECT, result);
    229                     }
    230                     retVal = HANDLED;
    231                     break;
    232                 }
    233                 case DcSwitchAsyncChannel.REQ_DISCONNECT: {
    234                     String type = (String)msg.obj;
    235                     if (DBG) {
    236                         log("ActingState: DcSwitchAsyncChannel.REQ_DISCONNECT type=" + type);
    237                     }
    238                     int result = teardownConnection(type);
    239                     mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_DISCONNECT, result);
    240                     retVal = HANDLED;
    241                     break;
    242                 }
    243                 case EVENT_CONNECTED: {
    244                     if (DBG) {
    245                         log("ActingState: EVENT_CONNECTED");
    246                     }
    247                     transitionTo(mActedState);
    248                     retVal = HANDLED;
    249                     break;
    250                 }
    251                 case EVENT_CLEANUP_ALL: {
    252                     if (DBG) {
    253                         log("ActingState: EVENT_CLEANUP_ALL" );
    254                     }
    255                     requestDataIdle();
    256                     transitionTo(mDeactingState);
    257                     retVal = HANDLED;
    258                     break;
    259                 }
    260                 default:
    261                     if (VDBG) {
    262                         log("ActingState: nothandled msg.what=0x" +
    263                                 Integer.toHexString(msg.what));
    264                     }
    265                     retVal = NOT_HANDLED;
    266                     break;
    267             }
    268             return retVal;
    269         }
    270     }
    271 
    272     private class ActedState extends State {
    273         @Override
    274         public boolean processMessage(Message msg) {
    275             boolean retVal;
    276 
    277             switch (msg.what) {
    278                 case DcSwitchAsyncChannel.REQ_CONNECT:
    279                 case EVENT_CONNECT: {
    280                     String type = (String)msg.obj;
    281                     if (DBG) {
    282                         log("ActedState: REQ_CONNECT/EVENT_CONNECT(" + msg.what + ") type=" + type);
    283                     }
    284                     int result = setupConnection(type);
    285                     if (msg.what == DcSwitchAsyncChannel.REQ_CONNECT) {
    286                         mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_CONNECT, result);
    287                     }
    288                     retVal = HANDLED;
    289                     break;
    290                 }
    291                 case DcSwitchAsyncChannel.REQ_DISCONNECT: {
    292                     String type = (String)msg.obj;
    293                     if (DBG) {
    294                         log("ActedState: DcSwitchAsyncChannel.REQ_DISCONNECT type=" + type);
    295                     }
    296                     int result = teardownConnection(type);
    297                     mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_DISCONNECT, result);
    298                     retVal = HANDLED;
    299                     break;
    300                 }
    301                 case EVENT_CONNECTED: {
    302                     if (DBG) {
    303                         log("ActedState: EVENT_CONNECTED");
    304                     }
    305                     retVal = HANDLED;
    306                     break;
    307                 }
    308                 case EVENT_CLEANUP_ALL: {
    309                     if (DBG) {
    310                         log("ActedState: EVENT_CLEANUP_ALL" );
    311                     }
    312                     requestDataIdle();
    313                     transitionTo(mDeactingState);
    314                     retVal = HANDLED;
    315                     break;
    316                 }
    317                 default:
    318                     if (VDBG) {
    319                         log("ActingState: nothandled msg.what=0x" +
    320                                 Integer.toHexString(msg.what));
    321                     }
    322                     retVal = NOT_HANDLED;
    323                     break;
    324             }
    325             return retVal;
    326         }
    327     }
    328 
    329     private class DeactingState extends State {
    330         @Override
    331         public boolean processMessage(Message msg) {
    332             boolean retVal;
    333 
    334             switch (msg.what) {
    335                 case DcSwitchAsyncChannel.REQ_CONNECT:
    336                 case EVENT_CONNECT: {
    337                     String type = (String)msg.obj;
    338                     if (DBG) {
    339                         log("DeactingState: REQ_CONNECT/EVENT_CONNECT(" +
    340                             msg.what + ") type=" + type + ", request is defered.");
    341                     }
    342                     deferMessage(obtainMessage(EVENT_CONNECT, type));
    343                     if (msg.what == DcSwitchAsyncChannel.REQ_CONNECT) {
    344                         mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_CONNECT,
    345                                 PhoneConstants.APN_REQUEST_STARTED);
    346                     }
    347                     retVal = HANDLED;
    348                     break;
    349                 }
    350                 case DcSwitchAsyncChannel.REQ_DISCONNECT: {
    351                     String type = (String)msg.obj;
    352                     if (DBG) {
    353                         log("DeactingState: DcSwitchAsyncChannel.REQ_DISCONNECT type=" + type);
    354                     }
    355                     mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_DISCONNECT,
    356                             PhoneConstants.APN_ALREADY_INACTIVE);
    357                     retVal = HANDLED;
    358                     break;
    359                 }
    360                 case EVENT_DETACH_DONE: {
    361                     if (DBG) {
    362                         log("DeactingState: EVENT_DETACH_DONE");
    363                     }
    364                     transitionTo(mIdleState);
    365                     retVal = HANDLED;
    366                     break;
    367                 }
    368                 case EVENT_CONNECTED: {
    369                     if (DBG) {
    370                         log("DeactingState: Receive invalid event EVENT_CONNECTED!");
    371                     }
    372                     retVal = HANDLED;
    373                     break;
    374                 }
    375                 case EVENT_CLEANUP_ALL: {
    376                     if (DBG) {
    377                         log("DeactingState: EVENT_CLEANUP_ALL, already deacting." );
    378                     }
    379                     retVal = HANDLED;
    380                     break;
    381                 }
    382                 default:
    383                     if (VDBG) {
    384                         log("DeactingState: nothandled msg.what=0x" +
    385                                 Integer.toHexString(msg.what));
    386                     }
    387                     retVal = NOT_HANDLED;
    388                     break;
    389             }
    390             return retVal;
    391         }
    392     }
    393 
    394     private class DefaultState extends State {
    395         @Override
    396         public boolean processMessage(Message msg) {
    397             AsyncResult ar;
    398 
    399             switch (msg.what) {
    400                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
    401                     if (mAc != null) {
    402                         if (VDBG) log("Disconnecting to previous connection mAc=" + mAc);
    403                         mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
    404                                 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
    405                     } else {
    406                         mAc = new AsyncChannel();
    407                         mAc.connected(null, getHandler(), msg.replyTo);
    408                         if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected");
    409                         mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
    410                                 AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
    411                     }
    412                     break;
    413                 }
    414                 case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
    415                     if (VDBG) log("CMD_CHANNEL_DISCONNECT");
    416                     mAc.disconnect();
    417                     break;
    418                 }
    419                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    420                     if (VDBG) log("CMD_CHANNEL_DISCONNECTED");
    421                     mAc = null;
    422                     break;
    423                 }
    424                 case DcSwitchAsyncChannel.REQ_IS_IDLE_STATE: {
    425                     boolean val = getCurrentState() == mIdleState;
    426                     if (VDBG) log("REQ_IS_IDLE_STATE  isIdle=" + val);
    427                     mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_IS_IDLE_STATE, val ? 1 : 0);
    428                     break;
    429                 }
    430                 case DcSwitchAsyncChannel.REQ_IS_IDLE_OR_DEACTING_STATE: {
    431                     boolean val = (getCurrentState() == mIdleState || getCurrentState() == mDeactingState);
    432                     if (VDBG) log("REQ_IS_IDLE_OR_DEACTING_STATE  isIdleDeacting=" + val);
    433                     mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_IS_IDLE_OR_DEACTING_STATE, val ? 1 : 0);
    434                     break;
    435                 }
    436                 case EVENT_TO_ACTING_DIRECTLY: {
    437                     log("Just transit to Acting state");
    438                     transitionTo(mActingState);
    439                     break;
    440                 }
    441                 case EVENT_TO_IDLE_DIRECTLY: {
    442                     log("Just transit to Idle state");
    443                     Iterator<String> itrType = mApnTypes.iterator();
    444                     while (itrType.hasNext()) {
    445 //                        mPhone.disableApnType(itrType.next()); TODO
    446                     }
    447                     mApnTypes.clear();
    448                     transitionTo(mIdleState);
    449                 }
    450                 default:
    451                     if (DBG) {
    452                         log("DefaultState: shouldn't happen but ignore msg.what=0x" +
    453                                 Integer.toHexString(msg.what));
    454                     }
    455                     break;
    456             }
    457             return HANDLED;
    458         }
    459     }
    460 
    461     protected void log(String s) {
    462         Log.d(LOG_TAG, "[" + getName() + "] " + s);
    463     }
    464 }
    465