00001 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). 00002 // All rights reserved. 00003 // This component and the accompanying materials are made available 00004 // under the terms of "Eclipse Public License v1.0" 00005 // which accompanies this distribution, and is available 00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html". 00007 // 00008 // Initial Contributors: 00009 // Nokia Corporation - initial contribution. 00010 // 00011 // Contributors: 00012 // 00013 // Description: 00014 // 00015 00016 #include "CMainMenu.h" 00017 #include <simtsy.h> 00018 00025 CMainMenu* CMainMenu::NewLC(CConsoleBase& aConsole) 00026 { 00027 CMainMenu* self = new(ELeave) CMainMenu(aConsole); 00028 CleanupStack::PushL(self); 00029 self->ConstructL(); 00030 return self; 00031 } 00032 00038 CMainMenu::CMainMenu(CConsoleBase& aConsole) 00039 : CBaseMenuAsync(aConsole) 00040 { 00041 iCallWaitingOn = EFalse; 00042 iRinging = EFalse; 00043 iThenAnswer = EFalse; 00044 } 00045 00049 void CMainMenu::ConstructL() 00050 { 00051 CBaseMenuAsync::ConstructL(); 00052 iPhoneId = CPhoneId::NewL(this); 00053 iNetworkName = CCurrentNetworkName::NewL(this); 00054 iOperatorName = COperatorName::NewL(this); 00055 iNetworkInfo = CCurrentNetworkInfo::NewL(this); 00056 00057 iFlightModeInfo = CFlightModeInfo::NewL(this); 00058 iNetworkRegInfo = CNetworkRegInfo::NewL(this); 00059 iDialCall = CDialCall::NewL(this); 00060 iLineStatus = CLineStatus::NewL(this); 00061 00062 iHangup = CHangup::NewL(this); 00063 iHold = CHold::NewL(this); 00064 iResume = CResume::NewL(this); 00065 00066 iSwap = CSwap::NewL(this); 00067 00068 iGetLockInfo = CGetLockInfo::NewL(this); 00069 iCallWaiting = CCallWaitingStatus::NewL(this); 00070 iAnswerIncomingCall = CAnswerIncomingCall::NewL(this); 00071 } 00072 00076 CMainMenu::~CMainMenu() 00077 { 00078 delete iTelephony; 00079 delete iPhoneId; 00080 00081 delete iNetworkName; 00082 delete iNetworkInfo; 00083 delete iOperatorName; 00084 00085 delete iDialCall; 00086 delete iHangup; 00087 delete iHold; 00088 delete iSwap; 00089 delete iResume; 00090 00091 delete iFlightModeInfo; 00092 delete iNetworkRegInfo; 00093 00094 delete iGetLockInfo; 00095 delete iCallWaiting; 00096 delete iAnswerIncomingCall; 00097 00098 delete iLineStatus; 00099 delete iCallStatus; 00100 delete iCallStatus2; 00101 } 00102 00109 void CMainMenu::ExecComplete(TTelISVExampleType aDerivedType) 00110 { 00111 if (IsActive()) 00112 { 00113 Cancel(); 00114 } 00115 if ( iState==ESetNotifier 00116 || aDerivedType == KLineStatus 00117 || aDerivedType == KHold) 00118 { 00119 switch(aDerivedType) 00120 { 00121 case KLineStatus: 00122 iLastOperation = iLineStatus; 00123 break; 00124 case KFlightModeInfo: 00125 iLastOperation = iFlightModeInfo; 00126 break; 00127 case KNetworkRegInfo: 00128 iLastOperation = iNetworkRegInfo; 00129 break; 00130 case KDialCall: 00131 iLastOperation = iDialCall; 00132 break; 00133 case KHold: 00134 iLastOperation = iHold; 00135 break; 00136 case KResume: 00137 iLastOperation = iResume; 00138 break; 00139 case KSwap: 00140 iLastOperation = iSwap; 00141 break; 00142 case KHangup: 00143 iLastOperation = iHangup; 00144 break; 00145 case KNetworkInfo: 00146 iLastOperation = iNetworkInfo; 00147 break; 00148 case KNetworkName: 00149 iLastOperation = iNetworkName; 00150 break; 00151 case KOperatorName: 00152 iLastOperation = iOperatorName; 00153 break; 00154 case KLockInfo: 00155 iLastOperation = iGetLockInfo; 00156 break; 00157 case KCallWaitingStatus: 00158 iLastOperation = iCallWaiting; 00159 break; 00160 case KAnswerIncomingCall: 00161 iLastOperation = iAnswerIncomingCall; 00162 break; 00163 case KNotType: 00164 case KPhoneId: 00165 case KSubscriberId: 00166 case KBatteryInfo: 00167 case KSignalInfo: 00168 case KGetIndicator: 00169 case KCallInfo: 00170 case KCallStatus: 00171 case KDynamicCaps: 00172 case KSendDTMF: 00173 case KCallForwardingStatus: 00174 case KCallBarringStatus: 00175 case KIdentityServiceStatus: 00176 default: 00177 break; 00178 } 00179 TRAPD(errNotify, iLastOperation->RequestNotificationL()); 00180 if (errNotify != KErrNone) 00181 { 00182 iConsole->Printf(_L("Notification Request for TTelISVExampleType")); 00183 iConsole->Printf(_L("%d left with error code "), aDerivedType); 00184 iConsole->Printf(_L("%d\n"), errNotify); 00185 return; 00186 }; 00187 // Check the type of iLastOperation to see what it has been cast to 00188 switch(iLastOperation->GetExampleType()) 00189 { 00190 case KFlightModeInfo: 00191 iState = EGetNetworkRegStatus; 00192 iLastOperation = iNetworkRegInfo; 00193 SetActive(); 00194 CompleteOwnRequest(KErrNone); 00195 break; 00196 case KLineStatus: 00197 iRinging = ETrue; 00198 PrintCorrectMenu(GetCurrentDynamicCaps()); 00199 GetInput(); 00200 break; 00201 case KAnswerIncomingCall: 00202 if (iCallStatus == NULL) 00203 { 00204 iCallId = reinterpret_cast<CAnswerIncomingCall*> 00205 (iAnswerIncomingCall)->iCallId; 00206 TRAPD(err, iCallStatus = CCallStatus::NewL(this, iCallId)); 00207 if (err != KErrNone) 00208 { 00209 iConsole->Printf(_L("CallStatus1 construction left ")); 00210 iConsole->Printf(_L("with error code %d\n"), err); 00211 return; 00212 } 00213 iLastCallStatus = iCallStatus; 00214 } 00215 else 00216 { 00217 iCallId2 = reinterpret_cast<CAnswerIncomingCall*> 00218 (iAnswerIncomingCall)->iCallId; 00219 TRAPD(err, iCallStatus2 = CCallStatus::NewL(this, iCallId2)); 00220 if (err != KErrNone) 00221 { 00222 iConsole->Printf(_L("CallStatus2 construction left ")); 00223 iConsole->Printf(_L("with error code %d\n"), err); 00224 return; 00225 } 00226 iLastCallStatus = iCallStatus2; 00227 } 00228 iState = EGetCallStatus; 00229 iLastOperation = iLastCallStatus; 00230 SetActive(); 00231 CompleteOwnRequest(KErrNone); 00232 break; 00233 case KDialCall: 00234 if (iCallStatus == NULL) 00235 { 00236 iCallId = reinterpret_cast<CDialCall*> 00237 (iDialCall)->iCallId; 00238 TRAPD(err, iCallStatus = CCallStatus::NewL(this, iCallId)); 00239 if (err != KErrNone) 00240 { 00241 iConsole->Printf(_L("CallStatus1 construction left ")); 00242 iConsole->Printf(_L("with error code %d\n"), err); 00243 return; 00244 } 00245 00246 iLastCallStatus = iCallStatus; 00247 } 00248 else 00249 { 00250 iCallId2 = reinterpret_cast<CDialCall*> 00251 (iDialCall)->iCallId; 00252 TRAPD(err, iCallStatus2 = CCallStatus::NewL(this, iCallId2)); 00253 if (err != KErrNone) 00254 { 00255 iConsole->Printf(_L("CallStatus2 construction left ")); 00256 iConsole->Printf(_L("with error code %d\n"), err); 00257 return; 00258 } 00259 iLastCallStatus = iCallStatus2; 00260 } 00261 iState = EGetCallStatus; 00262 iLastOperation = iLastCallStatus; 00263 SetActive(); 00264 CompleteOwnRequest(KErrNone); 00265 break; 00266 case KCallStatus: 00267 case KResume: 00268 PrintCorrectMenu(GetCurrentDynamicCaps()); 00269 GetInput(); 00270 break; 00271 case KSwap: 00272 if (iLastCallStatus == iCallStatus) 00273 { 00274 iLastCallStatus = iCallStatus2; 00275 } 00276 else 00277 { 00278 iLastCallStatus = iCallStatus; 00279 } 00280 PrintCorrectMenu(GetCurrentDynamicCaps()); 00281 GetInput(); 00282 break; 00283 case KHangup: 00284 // Do nothing; all operations on hangup event are handled by the 00285 // call status notification. In this way remote party hangups can be 00286 // detected. 00287 break; 00288 case KHold: 00289 if (iThenAnswer) 00290 { 00291 iThenAnswer = EFalse; 00292 iState = EAnswerIncomingCall; 00293 iLastOperation = iAnswerIncomingCall; 00294 SetActive(); 00295 CompleteOwnRequest(KErrNone); 00296 } 00297 else 00298 { 00299 PrintCorrectMenu(GetCurrentDynamicCaps()); 00300 GetInput(); 00301 } 00302 break; 00303 case KNetworkInfo: 00304 iState = EGetNetworkName; 00305 iLastOperation = iNetworkName; 00306 SetActive(); 00307 CompleteOwnRequest(KErrNone); 00308 break; 00309 case KNetworkName: 00310 iState = EGetOperatorName; 00311 iLastOperation = iOperatorName; 00312 SetActive(); 00313 CompleteOwnRequest(KErrNone); 00314 break; 00315 case KOperatorName: 00316 iState = ECallWaiting; 00317 iLastOperation = iCallWaiting; 00318 SetActive(); 00319 CompleteOwnRequest(KErrNone); 00320 break; 00321 case KLockInfo: 00322 iState = EGetLineStatus; 00323 iLastOperation = iLineStatus; 00324 SetActive(); 00325 CompleteOwnRequest(KErrNone); 00326 break; 00327 case KCallWaitingStatus: 00328 iCallWaitingOn = ETrue; 00329 iState = EGetLockInfo; 00330 iLastOperation = iGetLockInfo; 00331 SetActive(); 00332 CompleteOwnRequest(KErrNone); 00333 break; 00334 default: 00335 00336 break; 00337 } 00338 } 00339 else if(aDerivedType == KPhoneId) 00340 { 00341 iLastOperation = iFlightModeInfo; 00342 SetActive(); 00343 CompleteOwnRequest(KErrNone); 00344 } 00345 } 00346 00353 void CMainMenu::ExecNotify(TTelISVExampleType aDerivedType) 00354 { 00355 if (IsActive()) 00356 { 00357 Cancel(); 00358 } 00359 switch(aDerivedType) 00360 { 00361 case KNetworkRegInfo: 00362 { 00363 TRAPD(err, iNetworkRegInfo->RequestNotificationL()); 00364 if (err != KErrNone) 00365 { 00366 iConsole->Printf(_L("%d\n"),err); 00367 return; 00368 } 00369 iState = EGetNetworkInfo; 00370 iLastOperation = iNetworkInfo; 00371 SetActive(); 00372 CompleteOwnRequest(KErrNone); 00373 break; 00374 } 00375 case KLineStatus: 00376 { 00377 TRAPD(err, iLineStatus->RequestNotificationL()); 00378 if (err != KErrNone) 00379 { 00380 iConsole->Printf(_L("Request left with error code ")); 00381 iConsole->Printf(_L("%d\n"),err); 00382 return; 00383 } PrintCorrectMenu(GetCurrentDynamicCaps()); 00384 GetInput(); 00385 break; 00386 } 00387 case KCallStatus: 00388 if (iLastCallStatus == iCallStatus) 00389 { 00390 // Delete the previous object call status object which has now been 00391 // hung up. 00392 delete iLastCallStatus; 00393 iCallStatus = NULL; 00394 iLastCallStatus = iCallStatus2; 00395 } 00396 else 00397 { 00398 delete iLastCallStatus; 00399 iCallStatus2 = NULL; 00400 iLastCallStatus = iCallStatus; 00401 } 00402 if (iLineStatus->IsActive()) 00403 { 00404 iLineStatus->Cancel(); 00405 } 00406 iState = EGetLineStatus; 00407 iLastOperation = iLineStatus; 00408 SetActive(); 00409 CompleteOwnRequest(KErrNone); 00410 break; 00411 case KCallWaitingStatus: 00412 iCallWaitingOn = EFalse; 00413 iState = EGetLockInfo; 00414 iLastOperation = iGetLockInfo; 00415 SetActive(); 00416 CompleteOwnRequest(KErrNone); 00417 break; 00418 case KNotType: 00419 case KPhoneId: 00420 case KSubscriberId: 00421 case KBatteryInfo: 00422 case KSignalInfo: 00423 case KGetIndicator: 00424 case KLockInfo: 00425 case KNetworkInfo: 00426 case KNetworkName: 00427 case KOperatorName: 00428 case KCallInfo: 00429 case KFlightModeInfo: 00430 case KAnswerIncomingCall: 00431 case KDialCall: 00432 case KDynamicCaps: 00433 case KHold: 00434 case KResume: 00435 case KSwap: 00436 case KSendDTMF: 00437 case KHangup: 00438 case KCallForwardingStatus: 00439 case KCallBarringStatus: 00440 case KIdentityServiceStatus: 00441 default: 00442 break; 00443 } 00444 } 00445 00449 void CMainMenu::RunL() 00450 { 00451 switch(iState) 00452 { 00453 case EStart: 00454 iState = EGetFlightModeInfo; 00455 iLastOperation = iPhoneId; 00456 TRAPD(errPhone, iLastOperation->StartRequestL()); 00457 if (errPhone != KErrNone) 00458 { 00459 iConsole->Printf(_L("Request left with error code ")); 00460 iConsole->Printf(_L("%d\n"), errPhone); 00461 return; 00462 }; 00463 break; 00464 case EEnd: 00465 if (iLineStatus->IsActive()) 00466 { 00467 iLineStatus->Cancel(); 00468 } 00469 if (iNetworkRegInfo->IsActive()) 00470 { 00471 iNetworkRegInfo->Cancel(); 00472 } 00473 if (iNetworkInfo->IsActive()) 00474 { 00475 iNetworkInfo->Cancel(); 00476 } 00477 if (iFlightModeInfo->IsActive()) 00478 { 00479 iFlightModeInfo->Cancel(); 00480 } 00481 CActiveScheduler::Stop(); 00482 break; 00483 case EAnswerIncomingCall: 00484 case ECallWaiting: 00485 case EGetLockInfo: 00486 case EGetNetworkInfo: 00487 case EGetNetworkName: 00488 case EGetOperatorName: 00489 case EGetFlightModeInfo: 00490 case EGetNetworkRegStatus: 00491 case EGetLineStatus: 00492 case EGetCallStatus: 00493 iState = ESetNotifier; 00494 TRAPD(err, iLastOperation->StartRequestL()); 00495 if (err != KErrNone) 00496 { 00497 iConsole->Printf(_L("Request left with error code ")); 00498 iConsole->Printf(_L("%d\n"), err); 00499 return; 00500 } 00501 break; 00502 case EHold: 00503 case EResume: 00504 case EHangup: 00505 CTelephony::TCallId temp; 00506 if (iLastCallStatus == iCallStatus) 00507 { 00508 temp = iCallId; 00509 } 00510 else 00511 { 00512 temp = iCallId2; 00513 } 00514 iState = ESetNotifier; 00515 TRAPD(errArg, iLastOperation->StartRequestL(temp)); 00516 if (errArg != KErrNone) 00517 { 00518 iConsole->Printf(_L("Request left with error code ")); 00519 iConsole->Printf(_L("%d\n"), errArg); 00520 return; 00521 } 00522 break; 00523 case ESwap: 00524 iState = ESetNotifier; 00525 TRAPD(errSwap, iLastOperation->StartRequestL(iCallId, iCallId2)); 00526 if (errSwap != KErrNone) 00527 { 00528 iConsole->Printf(_L("Request left with error code ")); 00529 iConsole->Printf(_L("%d\n"), errSwap); 00530 return; 00531 } 00532 break; 00533 case EDialCall: 00534 iState = ESetNotifier; 00535 TRAPD(errNum, iLastOperation->StartRequestL(KTheNumber)); 00536 if (errNum != KErrNone) 00537 { 00538 iConsole->Printf(_L("Request left with error code ")); 00539 iConsole->Printf(_L("%d\n"), errNum); 00540 return; 00541 } 00542 break; 00543 case EWaitingForKeyPress: 00544 { 00545 CTelephony::TCallCapsV1 CallCapsV1 = GetCurrentDynamicCaps(); 00546 TUint32 crtlCaps = CallCapsV1.iControlCaps; 00547 TInt c = iConsole->KeyCode(); 00548 switch(c) 00549 { 00550 // Exit 00551 case 'E': 00552 case 'e': 00553 // cancel notifications 00554 if (iCallStatus != NULL) 00555 { 00556 iCallStatus->Cancel(); 00557 } 00558 if (iCallStatus2 != NULL) 00559 { 00560 iCallStatus2->Cancel(); 00561 } 00562 iLineStatus->Cancel(); 00563 iFlightModeInfo->Cancel(); 00564 iNetworkRegInfo->Cancel(); 00565 iNetworkInfo->Cancel(); 00566 iGetLockInfo->Cancel(); 00567 CActiveScheduler::Stop(); 00568 break; 00569 // Hangup active call 00570 case EKeyEscape: 00571 if (iLastCallStatus != NULL) 00572 { 00573 iState = EHangup; 00574 iLastOperation = iHangup; 00575 SetActive(); 00576 CompleteOwnRequest(KErrNone); 00577 } 00578 else 00579 { 00580 GetInput(); 00581 } 00582 break; 00583 // Swap active and on hold calls 00584 case 'S': 00585 case 's': 00586 if (crtlCaps & CTelephony::KCapsSwap 00587 && iCallStatus != NULL 00588 && iCallStatus2 !=NULL) 00589 { 00590 iState = ESwap; 00591 iLastOperation = iSwap; 00592 SetActive(); 00593 CompleteOwnRequest(KErrNone); 00594 } 00595 else 00596 { 00597 GetInput(); 00598 } 00599 break; 00600 // Make another call 00601 case 'D': 00602 case 'd': 00603 if (iLastCallStatus == NULL 00604 || crtlCaps & CTelephony::KCapsResume 00605 && !iRinging) 00606 { 00607 iConsole->ClearScreen(); 00608 iConsole->Printf(_L("Dialling Call\n")); 00609 iState = EDialCall; 00610 iLastOperation = iDialCall; 00611 SetActive(); 00612 CompleteOwnRequest(KErrNone); 00613 } 00614 else 00615 { 00616 GetInput(); 00617 } 00618 break; 00619 // Put call on hold 00620 case 'H': 00621 case 'h': 00622 if (crtlCaps & CTelephony::KCapsHold) 00623 { 00624 iState = EHold; 00625 iLastOperation = iHold; 00626 SetActive(); 00627 CompleteOwnRequest(KErrNone); 00628 } 00629 else 00630 { 00631 GetInput(); 00632 } 00633 break; 00634 // Resume on hold call 00635 case 'R': 00636 case 'r': 00637 if (crtlCaps & CTelephony::KCapsResume 00638 && iLastCallStatus != NULL ) 00639 { 00640 iState = EResume; 00641 iLastOperation = iResume; 00642 SetActive(); 00643 CompleteOwnRequest(KErrNone); 00644 } 00645 else 00646 { 00647 GetInput(); 00648 } 00649 break; 00650 // Answer incoming call 00651 case 'a': 00652 case 'A': 00653 if (iCallWaiting && iLastCallStatus != NULL 00654 && crtlCaps & CTelephony::KCapsResume) 00655 { 00656 iRinging = EFalse; 00657 iState = EAnswerIncomingCall; 00658 iLastOperation = iAnswerIncomingCall; 00659 SetActive(); 00660 CompleteOwnRequest(KErrNone); 00661 break; 00662 } 00663 else if(iCallWaiting 00664 && iLastCallStatus != NULL 00665 && crtlCaps & CTelephony::KCapsHold) 00666 { 00667 iRinging = EFalse; 00668 iThenAnswer = ETrue; 00669 iState = EHold; 00670 iLastOperation = iHold; 00671 SetActive(); 00672 CompleteOwnRequest(KErrNone); 00673 } 00674 else 00675 { 00676 GetInput(); 00677 } 00678 break; 00679 // Simulate incoming call 00680 case 'i': 00681 case 'I': 00682 if(iCallWaiting 00683 && iLastCallStatus != NULL 00684 && (crtlCaps & CTelephony::KCapsResume || 00685 crtlCaps & CTelephony::KCapsHold)) 00686 { 00687 TInt ret = RProperty::Set(KUidPSSimTsyCategory, 00688 KPSSimTsyIncomingVoiceCall, 00689 0); 00690 if(ret!=KErrNone) 00691 { 00692 iConsole->Printf(_L("Set failed : %d\n"),ret); 00693 } 00694 break; 00695 } 00696 default: 00697 GetInput(); 00698 } 00699 } 00700 break; 00701 default: 00702 break; 00703 } 00704 } 00705 00709 CTelephony::TCallCapsV1 CMainMenu::GetCurrentDynamicCaps() 00710 { 00711 CTelephony::TCallId temp; 00712 CTelephony::TCallCapsV1 callCapsV1; 00713 CTelephony::TCallCapsV1Pckg callCapsV1Pckg(callCapsV1); 00714 if (iLastCallStatus == iCallStatus) 00715 { 00716 temp = iCallId; 00717 } 00718 else 00719 { 00720 temp = iCallId2; 00721 } 00722 // Retrieves the dynamic call capabilities for calls you dialled or answered with CTelephony 00723 iTelephony->GetCallDynamicCaps(temp, callCapsV1Pckg); 00724 return callCapsV1; 00725 } 00726 00732 void CMainMenu::PrintCorrectMenu(CTelephony::TCallCapsV1 aCallCapsV1) 00733 { 00734 iConsole->ClearScreen(); 00735 iConsole->Printf(KMenuMsg); 00736 if (iRinging) 00737 { 00738 iConsole->Printf(_L("There is an incoming call\n")); 00739 iConsole->Printf(_L("How would you like to proceed?\n")); 00740 if (aCallCapsV1.iControlCaps & CTelephony::KCapsHold) 00741 { 00742 iConsole->Printf(KHoldMsg); 00743 iConsole->Printf(KAnswerMsg); 00744 iConsole->Printf(KHangupMsg); 00745 } 00746 else 00747 { 00748 iConsole->Printf(KResumeMsg); 00749 iConsole->Printf(KAnswerMsg); 00750 iConsole->Printf(KHangupMsg); 00751 } 00752 } 00753 else 00754 { 00755 if (iLastCallStatus == NULL) 00756 { 00757 iConsole->Printf(KDialMsg); 00758 } 00759 else if (aCallCapsV1.iControlCaps & CTelephony::KCapsSwap 00760 && iCallStatus != NULL 00761 && iCallStatus2 != NULL) 00762 { 00763 iConsole->Printf(KSwapMsg); 00764 iConsole->Printf(KHangupMsg); 00765 } 00766 else if (aCallCapsV1.iControlCaps & CTelephony::KCapsHold) 00767 { 00768 iConsole->Printf(KHoldMsg); 00769 iConsole->Printf(KIncomingMsg); 00770 iConsole->Printf(KHangupMsg); 00771 } 00772 else if (aCallCapsV1.iControlCaps & CTelephony::KCapsResume) 00773 { 00774 iConsole->Printf(KResumeMsg); 00775 iConsole->Printf(KDialMsg); 00776 iConsole->Printf(KIncomingMsg); 00777 iConsole->Printf(KHangupMsg); 00778 } 00779 } 00780 } 00781 00785 void CMainMenu::GetInput() 00786 { 00787 iConsole->Read(iStatus); 00788 iState = EWaitingForKeyPress; 00789 SetActive(); 00790 } 00791 00795 void CMainMenu::DoCancel() 00796 { 00797 if(iState == EStart) 00798 { 00799 CompleteOwnRequest(KErrCancel); 00800 } 00801 else 00802 { 00803 iConsole->ReadCancel(); 00804 } 00805 }
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.