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