/** * Handles the user canceling the popup, either by touching outside the popup or by pressing * Back. */ @Override public void onCancel(DialogInterface dialog) { if (DBG) log("RespondViaSmsCancelListener.onCancel()..."); dismissPopup(); final PhoneConstants.State state = PhoneApp.getInstance().mCM.getState(); if (state == PhoneConstants.State.IDLE) { // This means the incoming call is already hung up when the user chooses not to // use "Respond via SMS" feature. Let's just exit the whole in-call screen. PhoneApp.getInstance().dismissCallScreen(); } else { // If the user cancels the popup, this presumably means that // they didn't actually mean to bring up the "Respond via SMS" // UI in the first place (and instead want to go back to the // state where they can either answer or reject the call.) // So restart the ringer and bring back the regular incoming // call UI. // This will have no effect if the incoming call isn't still ringing. PhoneApp.getInstance().notifier.restartRinger(); // We hid the GlowPadView widget way back in // InCallTouchUi.onTrigger(), when the user first selected // the "SMS" trigger. // // To bring it back, just force the entire InCallScreen to // update itself based on the current telephony state. // (Assuming the incoming call is still ringing, this will // cause the incoming call widget to reappear.) mInCallScreen.requestUpdateScreen(); } }
/** Handles the user selecting an item from the popup. */ @Override public void onItemClick( AdapterView<?> parent, // The ListView View view, // The TextView that was clicked int position, long id) { if (DBG) log("RespondViaSmsItemClickListener.onItemClick(" + position + ")..."); String message = (String) parent.getItemAtPosition(position); if (VDBG) log("- message: '" + message + "'"); // The "Custom" choice is a special case. // (For now, it's guaranteed to be the last item.) if (position == (parent.getCount() - 1)) { // Take the user to the standard SMS compose UI. launchSmsCompose(mPhoneNumber); } else { // Send the selected message immediately with no user interaction. sendText(mPhoneNumber, message); // ...and show a brief confirmation to the user (since // otherwise it's hard to be sure that anything actually // happened.) final Resources res = mInCallScreen.getResources(); String formatString = res.getString(R.string.respond_via_sms_confirmation_format); String confirmationMsg = String.format(formatString, mPhoneNumber); Toast.makeText(mInCallScreen, confirmationMsg, Toast.LENGTH_LONG).show(); // TODO: If the device is locked, this toast won't actually ever // be visible! (That's because we're about to dismiss the call // screen, which means that the device will return to the // keyguard. But toasts aren't visible on top of the keyguard.) // Possible fixes: // (1) Is it possible to allow a specific Toast to be visible // on top of the keyguard? // (2) Artifically delay the dismissCallScreen() call by 3 // seconds to allow the toast to be seen? // (3) Don't use a toast at all; instead use a transient state // of the InCallScreen (perhaps via the InCallUiState // progressIndication feature), and have that state be // visible for 3 seconds before calling dismissCallScreen(). } // At this point the user is done dealing with the incoming call, so // there's no reason to keep it around. (It's also confusing for // the "incoming call" icon in the status bar to still be visible.) // So reject the call now. mInCallScreen.hangupRingingCall(); dismissPopup(); final PhoneConstants.State state = PhoneApp.getInstance().mCM.getState(); if (state == PhoneConstants.State.IDLE) { // There's no other phone call to interact. Exit the entire in-call screen. PhoneApp.getInstance().dismissCallScreen(); } else { // The user is still in the middle of other phone calls, so we should keep the // in-call screen. mInCallScreen.requestUpdateScreen(); } }
/** * cleanup any undismissed ota dialogs so the InCallScreen UI can be shown * * @return void */ private void otaCleanup() { PhoneApp app = PhoneApp.getInstance(); boolean isOtaCallActive = false; if (TelephonyCapabilities.supportsOtasp(app.phone)) { boolean activateState = (app.cdmaOtaScreenState.otaScreenState == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION); boolean dialogState = (app.cdmaOtaScreenState.otaScreenState == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_SUCCESS_FAILURE_DLG); if (activateState || dialogState) { // The OTASP sequence is active, but either (1) the call // hasn't started yet, or (2) the call has ended and we're // showing the success/failure screen. In either of these // cases it's OK to make a new outgoing call, but we need // to take down any OTASP-related UI first. if (dialogState) app.dismissOtaDialogs(); app.clearOtaState(); app.clearInCallScreenMode(); } } }
/** Private constructor; @see init() */ private PhoneInterfaceManager(PhoneApp app, Phone phone) { mApp = app; mPhone = phone; mCM = PhoneApp.getInstance().mCM; mMainThreadHandler = new MainThreadHandler(); Log.d(LOG_TAG, " Registering for UNSOL OEM HOOK Responses to deliver external apps"); mPhone.setOnUnsolOemHookExtApp(mMainThreadHandler, EVENT_UNSOL_OEM_HOOK_EXT_APP, null); publish(); }
@Override public void onCreate() { super.onCreate(); mAdapter = BluetoothAdapter.getDefaultAdapter(); mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); mBtHandsfree = PhoneApp.getInstance().getBluetoothHandsfree(); mAg = new BluetoothAudioGateway(mAdapter); IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); filter.addAction(BluetoothDevice.ACTION_UUID); registerReceiver(mBluetoothReceiver, filter); IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE); if (b == null) { throw new RuntimeException("Bluetooth service not available"); } mBluetoothService = IBluetooth.Stub.asInterface(b); mRemoteHeadsets = new HashMap<BluetoothDevice, BluetoothRemoteHeadset>(); }
/** * Handles the user canceling the popup, either by touching outside the popup or by pressing * Back. */ public void onCancel(DialogInterface dialog) { if (DBG) log("RespondViaSmsCancelListener.onCancel()..."); // If the user cancels the popup, this presumably means that // they didn't actually mean to bring up the "Respond via SMS" // UI in the first place (and instead want to go back to the // state where they can either answer or reject the call.) // So restart the ringer and bring back the regular incoming // call UI. // This will have no effect if the incoming call isn't still ringing. PhoneApp.getInstance().notifier.restartRinger(); // We hid the MultiWaveView widget way back in // InCallTouchUi.onTrigger(), when the user first selected // the "SMS" trigger. // // To bring it back, just force the entire InCallScreen to // update itself based on the current telephony state. // (Assuming the incoming call is still ringing, this will // cause the incoming call widget to reappear.) mInCallScreen.requestUpdateScreen(); }
/** * Check if ota call is active * * @return True if ota call is still active False if ota call is not active */ private boolean isOtaActive() { PhoneApp app = PhoneApp.getInstance(); boolean isOtaCallActive = false; if (TelephonyCapabilities.supportsOtasp(app.phone)) { // TODO: Need cleaner way to check if OTA is active. // Also, this check seems to be broken in one obscure case: if // you interrupt an OTASP call by pressing Back then Skip, // otaScreenState somehow gets left in either PROGRESS or // LISTENING. if ((app.cdmaOtaScreenState.otaScreenState == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_PROGRESS) || (app.cdmaOtaScreenState.otaScreenState == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_LISTENING)) { isOtaCallActive = true; // The actual OTASP call is active. Don't allow new // outgoing calls at all from this state. Log.w(TAG, "OTASP call is active"); } } return isOtaCallActive; }
private void processIntent(Intent intent) { String action = intent.getAction(); intent.putExtra(SUBSCRIPTION_KEY, mSubscription); Log.d(TAG, "outGoingcallBroadCaster action is" + action); String number = PhoneNumberUtils.getNumberFromIntent(intent, this); Log.d(TAG, " number from Intent : " + number); // Check the number, don't convert for sip uri // TODO put uriNumber under PhoneNumberUtils if (number != null) { if (!PhoneNumberUtils.isUriNumber(number)) { number = PhoneNumberUtils.convertKeypadLettersToDigits(number); number = PhoneNumberUtils.stripSeparators(number); } } // If true, this flag will indicate that the current call is a special kind // of call (most likely an emergency number) that 3rd parties aren't allowed // to intercept or affect in any way. (In that case, we start the call // immediately rather than going through the NEW_OUTGOING_CALL sequence.) boolean callNow; if (getClass().getName().equals(intent.getComponent().getClassName())) { // If we were launched directly from the OutgoingCallBroadcaster, // not one of its more privileged aliases, then make sure that // only the non-privileged actions are allowed. if (!Intent.ACTION_CALL.equals(intent.getAction())) { Log.w(TAG, "Attempt to deliver non-CALL action; forcing to CALL"); intent.setAction(Intent.ACTION_CALL); } } // Check whether or not this is an emergency number, in order to // enforce the restriction that only the CALL_PRIVILEGED and // CALL_EMERGENCY intents are allowed to make emergency calls. // // (Note that the ACTION_CALL check below depends on the result of // isPotentialLocalEmergencyNumber() rather than just plain // isLocalEmergencyNumber(), to be 100% certain that we *don't* // allow 3rd party apps to make emergency calls by passing in an // "invalid" number like "9111234" that isn't technically an // emergency number but might still result in an emergency call // with some networks.) final boolean isExactEmergencyNumber = (number != null) && PhoneNumberUtils.isLocalEmergencyNumber(number, this); final boolean isPotentialEmergencyNumber = (number != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, this); if (VDBG) { Log.v(TAG, "- Checking restrictions for number '" + number + "':"); Log.v(TAG, " isExactEmergencyNumber = " + isExactEmergencyNumber); Log.v(TAG, " isPotentialEmergencyNumber = " + isPotentialEmergencyNumber); } /* Change CALL_PRIVILEGED into CALL or CALL_EMERGENCY as needed. */ // TODO: This code is redundant with some code in InCallScreen: refactor. if (Intent.ACTION_CALL_PRIVILEGED.equals(action)) { // We're handling a CALL_PRIVILEGED intent, so we know this request came // from a trusted source (like the built-in dialer.) So even a number // that's *potentially* an emergency number can safely be promoted to // CALL_EMERGENCY (since we *should* allow you to dial "91112345" from // the dialer if you really want to.) action = isPotentialEmergencyNumber ? Intent.ACTION_CALL_EMERGENCY : Intent.ACTION_CALL; if (DBG) Log.v(TAG, "- updating action from CALL_PRIVILEGED to " + action); intent.setAction(action); } if (Intent.ACTION_CALL.equals(action)) { if (isPotentialEmergencyNumber) { Log.w( TAG, "Cannot call potential emergency number '" + number + "' with CALL Intent " + intent + "."); Log.i(TAG, "Launching default dialer instead..."); Intent invokeFrameworkDialer = new Intent(); // TwelveKeyDialer is in a tab so we really want // DialtactsActivity. Build the intent 'manually' to // use the java resolver to find the dialer class (as // opposed to a Context which look up known android // packages only) invokeFrameworkDialer.setClassName( "com.android.contacts", "com.android.contacts.DialtactsActivity"); invokeFrameworkDialer.setAction(Intent.ACTION_DIAL); invokeFrameworkDialer.setData(intent.getData()); invokeFrameworkDialer.putExtra(SUBSCRIPTION_KEY, mSubscription); if (DBG) Log.v(TAG, "onCreate(): calling startActivity for Dialer: " + invokeFrameworkDialer); startActivity(invokeFrameworkDialer); finish(); return; } intent.putExtra(SUBSCRIPTION_KEY, mSubscription); Log.d(TAG, "for non emergency call,sub is :" + mSubscription); callNow = false; } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) { // ACTION_CALL_EMERGENCY case: this is either a CALL_PRIVILEGED // intent that we just turned into a CALL_EMERGENCY intent (see // above), or else it really is an CALL_EMERGENCY intent that // came directly from some other app (e.g. the EmergencyDialer // activity built in to the Phone app.) // Make sure it's at least *possible* that this is really an // emergency number. if (!isPotentialEmergencyNumber) { Log.w( TAG, "Cannot call non-potential-emergency number " + number + " with EMERGENCY_CALL Intent " + intent + "."); finish(); return; } int sub = PhoneApp.getInstance().getVoiceSubscriptionInService(); intent.putExtra(SUBSCRIPTION_KEY, sub); Log.d(TAG, "Attempting emergency call on sub :" + sub); callNow = true; } else { Log.e(TAG, "Unhandled Intent " + intent + "."); finish(); return; } // Make sure the screen is turned on. This is probably the right // thing to do, and more importantly it works around an issue in the // activity manager where we will not launch activities consistently // when the screen is off (since it is trying to keep them paused // and has... issues). // // Also, this ensures the device stays awake while doing the following // broadcast; technically we should be holding a wake lock here // as well. PhoneApp.getInstance().wakeUpScreen(); /* If number is null, we're probably trying to call a non-existent voicemail number, * send an empty flash or something else is fishy. Whatever the problem, there's no * number, so there's no point in allowing apps to modify the number. */ if (number == null || TextUtils.isEmpty(number)) { if (intent.getBooleanExtra(EXTRA_SEND_EMPTY_FLASH, false)) { Log.i(TAG, "onCreate: SEND_EMPTY_FLASH..."); PhoneUtils.sendEmptyFlash(PhoneApp.getInstance().getPhone()); finish(); return; } else { Log.i(TAG, "onCreate: null or empty number, setting callNow=true..."); callNow = true; intent.putExtra(SUBSCRIPTION_KEY, mSubscription); } } if (callNow) { // This is a special kind of call (most likely an emergency number) // that 3rd parties aren't allowed to intercept or affect in any way. // So initiate the outgoing call immediately. if (DBG) Log.v(TAG, "onCreate(): callNow case! Calling placeCall(): " + intent); // Initiate the outgoing call, and simultaneously launch the // InCallScreen to display the in-call UI: PhoneApp.getInstance().callController.placeCall(intent); // Note we do *not* "return" here, but instead continue and // send the ACTION_NEW_OUTGOING_CALL broadcast like for any // other outgoing call. (But when the broadcast finally // reaches the OutgoingCallReceiver, we'll know not to // initiate the call again because of the presence of the // EXTRA_ALREADY_CALLED extra.) } // For now, SIP calls will be processed directly without a // NEW_OUTGOING_CALL broadcast. // // TODO: In the future, though, 3rd party apps *should* be allowed to // intercept outgoing calls to SIP addresses as well. To do this, we should // (1) update the NEW_OUTGOING_CALL intent documentation to explain this // case, and (2) pass the outgoing SIP address by *not* overloading the // EXTRA_PHONE_NUMBER extra, but instead using a new separate extra to hold // the outgoing SIP address. (Be sure to document whether it's a URI or just // a plain address, whether it could be a tel: URI, etc.) Uri uri = intent.getData(); String scheme = uri.getScheme(); if (Constants.SCHEME_SIP.equals(scheme) || PhoneNumberUtils.isUriNumber(number)) { startSipCallOptionHandler(this, intent, uri, number); finish(); return; // TODO: if there's ever a way for SIP calls to trigger a // "callNow=true" case (see above), we'll need to handle that // case here too (most likely by just doing nothing at all.) } final String callOrigin = intent.getStringExtra(PhoneApp.EXTRA_CALL_ORIGIN); if (callOrigin != null) { if (DBG) Log.v(TAG, "Call origin is passed (" + callOrigin + ")"); PhoneApp.getInstance().setLatestActiveCallOrigin(callOrigin); } else { if (DBG) Log.v(TAG, "Call origin is not passed. Reset current one."); PhoneApp.getInstance().setLatestActiveCallOrigin(null); } Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL); if (number != null) { broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number); } PhoneUtils.checkAndCopyPhoneProviderExtras(intent, broadcastIntent); broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow); broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, uri.toString()); broadcastIntent.putExtra(SUBSCRIPTION_KEY, mSubscription); if (DBG) Log.v(TAG, "Broadcasting intent: " + broadcastIntent + "."); sendOrderedBroadcast( broadcastIntent, PERMISSION, new OutgoingCallReceiver(), null, // scheduler Activity.RESULT_OK, // initialCode number, // initialData: initial value for the result data null); // initialExtras }
@Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); // This method is the single point of entry for the CALL intent, // which is used (by built-in apps like Contacts / Dialer, as well // as 3rd-party apps) to initiate an outgoing voice call. // // We also handle two related intents which are only used internally: // CALL_PRIVILEGED (which can come from built-in apps like contacts / // voice dialer / bluetooth), and CALL_EMERGENCY (from the // EmergencyDialer that's reachable from the lockscreen.) // // The exact behavior depends on the intent's data: // // - The most typical is a tel: URI, which we handle by starting the // NEW_OUTGOING_CALL broadcast. That broadcast eventually triggeres // the sequence OutgoingCallReceiver -> SipCallOptionHandler -> // InCallScreen. // // - Or, with a sip: URI we skip the NEW_OUTGOING_CALL broadcast and // go directly to SipCallOptionHandler, which then leads to the // InCallScreen. // // - voicemail: URIs take the same path as regular tel: URIs. // // Other special cases: // // - Outgoing calls are totally disallowed on non-voice-capable // devices (see handleNonVoiceCapable()). // // - A CALL intent with the EXTRA_SEND_EMPTY_FLASH extra (and // presumably no data at all) means "send an empty flash" (which // is only meaningful on CDMA devices while a call is already // active.) Intent intent = getIntent(); final Configuration configuration = getResources().getConfiguration(); if (DBG) Log.v(TAG, "onCreate: this = " + this + ", icicle = " + icicle); if (DBG) Log.v(TAG, " - getIntent() = " + intent); if (DBG) Log.v(TAG, " - configuration = " + configuration); if (icicle != null) { // A non-null icicle means that this activity is being // re-initialized after previously being shut down. // // In practice this happens very rarely (because the lifetime // of this activity is so short!), but it *can* happen if the // framework detects a configuration change at exactly the // right moment; see bug 2202413. // // In this case, do nothing. Our onCreate() method has already // run once (with icicle==null the first time), which means // that the NEW_OUTGOING_CALL broadcast for this new call has // already been sent. Log.i( TAG, "onCreate: non-null icicle! " + "Bailing out, not sending NEW_OUTGOING_CALL broadcast..."); // No need to finish() here, since the OutgoingCallReceiver from // our original instance will do that. (It'll actually call // finish() on our original instance, which apparently works fine // even though the ActivityManager has already shut that instance // down. And note that if we *do* call finish() here, that just // results in an "ActivityManager: Duplicate finish request" // warning when the OutgoingCallReceiver runs.) return; } // Outgoing phone calls are only allowed on "voice-capable" devices. if (!PhoneApp.sVoiceCapable) { handleNonVoiceCapable(intent); // No need to finish() here; handleNonVoiceCapable() will do // that if necessary. return; } /* * Clean up any undismissed ota dialogs. If ota call is active outgoing * calls will be blocked in OutgoingCallReceiver */ otaCleanup(); boolean promptEnabled = MSimPhoneFactory.isPromptEnabled(); String number = PhoneNumberUtils.getNumberFromIntent(intent, this); if (TelephonyManager.getDefault().isMultiSimEnabled() && promptEnabled && (activeSubCount() > 1) && (!isIntentFromBluetooth(intent)) && (!isSIPCall(number, intent))) { Log.d(TAG, "Start multisimdialer activity and get the sub selected by user"); Intent intentMSim = new Intent(this, MSimDialerActivity.class); intentMSim.setData(intent.getData()); intentMSim.setAction(intent.getAction()); int requestCode = 1; startActivityForResult(intentMSim, requestCode); } else { mSubscription = intent.getIntExtra(SUBSCRIPTION_KEY, PhoneApp.getInstance().getVoiceSubscription()); Log.d(TAG, "subscription when there is (from Extra):" + mSubscription); processIntent(intent); } }
public void doReceive(Context context, Intent intent) { if (DBG) Log.v(TAG, "doReceive: " + intent); boolean alreadyCalled; String number; String originalUri; alreadyCalled = intent.getBooleanExtra(OutgoingCallBroadcaster.EXTRA_ALREADY_CALLED, false); if (alreadyCalled) { if (DBG) Log.v(TAG, "CALL already placed -- returning."); return; } // Once the NEW_OUTGOING_CALL broadcast is finished, the resultData // is used as the actual number to call. (If null, no call will be // placed.) number = getResultData(); if (VDBG) Log.v(TAG, "- got number from resultData: '" + number + "'"); final PhoneApp app = PhoneApp.getInstance(); if (isOtaActive()) { // OTASP call is active. Don't allow new outgoing calls at all Log.w(TAG, "OTASP call is active: disallowing a new outgoing call."); return; } if (number == null) { if (DBG) Log.v(TAG, "CALL cancelled (null number), returning..."); return; } else if (TelephonyCapabilities.supportsOtasp(app.phone) && (app.phone.getState() != Phone.State.IDLE) && (app.phone.isOtaSpNumber(number))) { if (DBG) Log.v(TAG, "Call is active, a 2nd OTA call cancelled -- returning."); return; } else if (PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, context)) { // Just like 3rd-party apps aren't allowed to place emergency // calls via the ACTION_CALL intent, we also don't allow 3rd // party apps to use the NEW_OUTGOING_CALL broadcast to rewrite // an outgoing call into an emergency number. Log.w(TAG, "Cannot modify outgoing call to emergency number " + number + "."); return; } originalUri = intent.getStringExtra(OutgoingCallBroadcaster.EXTRA_ORIGINAL_URI); if (originalUri == null) { Log.e(TAG, "Intent is missing EXTRA_ORIGINAL_URI -- returning."); return; } Uri uri = Uri.parse(originalUri); // We already called convertKeypadLettersToDigits() and // stripSeparators() way back in onCreate(), before we sent out the // NEW_OUTGOING_CALL broadcast. But we need to do it again here // too, since the number might have been modified/rewritten during // the broadcast (and may now contain letters or separators again.) number = PhoneNumberUtils.convertKeypadLettersToDigits(number); number = PhoneNumberUtils.stripSeparators(number); if (DBG) Log.v(TAG, "doReceive: proceeding with call..."); if (VDBG) Log.v(TAG, "- uri: " + uri); if (VDBG) Log.v(TAG, "- actual number to dial: '" + number + "'"); startSipCallOptionHandler(context, intent, uri, number); }
public boolean isSimPinEnabled() { enforceReadPermission(); return (PhoneApp.getInstance().isSimPinEnabled()); }
@Override protected void onCreate(Bundle icicle) { Log.i(TAG, "onCreate()... intent = " + getIntent()); super.onCreate(icicle); // Watch out: the intent action we get here should always be // ACTION_CALL_EMERGENCY, since the whole point of this activity // is for it to be launched using the same intent originally // passed to the InCallScreen, which will always be // ACTION_CALL_EMERGENCY when making an emergency call. // // If we ever get launched with any other action, especially if it's // "com.android.phone.InCallScreen.UNDEFINED" (as in bug 3094858), that // almost certainly indicates a logic bug in the InCallScreen. if (!Intent.ACTION_CALL_EMERGENCY.equals(getIntent().getAction())) { Log.w( TAG, "Unexpected intent action! Should be ACTION_CALL_EMERGENCY, " + "but instead got: " + getIntent().getAction()); } // setup the phone and get the retry count embedded in the intent. Phone phone = PhoneFactory.getDefaultPhone(); int retryCount = getIntent().getIntExtra(EMERGENCY_CALL_RETRY_KEY, INITIAL_ATTEMPT); // create a new message object. EmergencyCallInfo eci = new EmergencyCallInfo(); eci.phone = phone; eci.app = getApplication(); eci.dialog = constructDialog(retryCount); // The Intent we're going to fire off to retry the call is the // same one that got us here (except that we *don't* explicitly // specify this class as the component!) eci.intent = getIntent().setComponent(null); // And we'll be firing this Intent from the PhoneApp's context // (see the startActivity() calls above) so the // FLAG_ACTIVITY_NEW_TASK flag is required. eci.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (DBG) Log.d(TAG, "- initial eci.intent: " + eci.intent); // create the handler. if (sHandler == null) { sHandler = new EmergencyCallEventHandler(); } // If this is the initial attempt, we need to register for a radio state // change and turn the radio on. Otherwise, this is just a retry, and // we simply wait the alloted time before sending the request to try // the call again. // Note: The radio logic ITSELF will try its best to put the emergency // call through once the radio is turned on. The retry we have here // is in case it fails; the current constants we have include making // 6 attempts, with a 5 second delay between each. if (retryCount == INITIAL_ATTEMPT) { // place the number of pending retries in the intent. eci.intent.putExtra(EMERGENCY_CALL_RETRY_KEY, NUMBER_OF_RETRIES); int sub = PhoneApp.getInstance().getVoiceSubscriptionInService(); eci.intent.putExtra(SUBSCRIPTION, sub); Log.d(TAG, "Attempting emergency call on sub :" + sub); // turn the radio on and listen for it to complete. phone.registerForServiceStateChanged(sHandler, EVENT_SERVICE_STATE_CHANGED, eci); // If airplane mode is on, we turn it off the same way that the // Settings activity turns it off. if (Settings.System.getInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) > 0) { if (DBG) Log.d(TAG, "Turning off airplane mode..."); // Change the system setting Settings.System.putInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0); // Post the intent Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); intent.putExtra("state", false); sendBroadcast(intent); // Otherwise, for some strange reason the radio is just off, so // we just turn it back on. } else { if (DBG) Log.d(TAG, "Manually powering radio on..."); phone.setRadioPower(true); } } else { // decrement and store the number of retries. if (DBG) Log.d(TAG, "Retry attempt... retryCount = " + retryCount); eci.intent.putExtra(EMERGENCY_CALL_RETRY_KEY, (retryCount - 1)); // get the message and attach the data, then wait the alloted // time and send. Message m = sHandler.obtainMessage(EVENT_TIMEOUT_EMERGENCY_CALL); m.obj = eci; sHandler.sendMessageDelayed(m, TIME_BETWEEN_RETRIES_MS); } finish(); }
@Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); PhoneApp app = PhoneApp.getInstance(); addPreferencesFromResource(R.xml.msim_network_settings); mSubscription = getIntent().getIntExtra(SUBSCRIPTION_KEY, app.getDefaultSubscription()); log("Settings onCreate subscription =" + mSubscription); mPhone = app.getPhone(mSubscription); mHandler = new MyHandler(); // get UI object references PreferenceScreen prefSet = getPreferenceScreen(); mButtonPreferredNetworkMode = (ListPreference) prefSet.findPreference(BUTTON_PREFERED_NETWORK_MODE); boolean isLteOnCdma = mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE; if (getResources().getBoolean(R.bool.world_phone) == true) { if (SystemProperties.getBoolean("ro.monkey", false)) { prefSet.removePreference(mButtonPreferredNetworkMode); } else { // set the listener for the mButtonPreferredNetworkMode list // preference so we can issue change Preferred Network Mode. mButtonPreferredNetworkMode.setOnPreferenceChangeListener(this); // Get the networkMode from Settings.System and displays it int settingsNetworkMode = android.provider.Settings.Secure.getInt( mPhone.getContext().getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode)); mCdmaOptions = new CdmaOptions(this, prefSet, mPhone); mGsmUmtsOptions = new GsmUmtsOptions(this, prefSet, mSubscription); } } else { if (!isLteOnCdma) { prefSet.removePreference(mButtonPreferredNetworkMode); } int phoneType = mPhone.getPhoneType(); if (phoneType == Phone.PHONE_TYPE_CDMA) { mCdmaOptions = new CdmaOptions(this, prefSet, mPhone); if (isLteOnCdma) { mButtonPreferredNetworkMode.setOnPreferenceChangeListener(this); mButtonPreferredNetworkMode.setEntries(R.array.preferred_network_mode_choices_lte); mButtonPreferredNetworkMode.setEntryValues(R.array.preferred_network_mode_values_lte); int settingsNetworkMode = android.provider.Settings.Secure.getInt( mPhone.getContext().getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode)); } } else if (phoneType == Phone.PHONE_TYPE_GSM) { mGsmUmtsOptions = new GsmUmtsOptions(this, prefSet, mSubscription); } else { throw new IllegalStateException("Unexpected phone type: " + phoneType); } } }
@Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_SIM_LOCKED: // mIsSimPinEnabled = true; // // if (Config.LOGV) Log.v(LOG_TAG, "show sim unlock panel"); // SimPinUnlockPanel pinUnlockPanel = new SimPinUnlockPanel( // PhoneApp.getInstance()); // pinUnlockPanel.show(); break; case EVENT_SIM_ABSENT: // Don't need this now that the lock screen handles this case // if (Config.LOGV) Log.v(LOG_TAG, "show sim missing panel"); // SimMissingPanel missingPanel = new SimMissingPanel( // PhoneApp.getInstance()); // missingPanel.show(); break; case EVENT_SIM_NETWORK_LOCKED: if (getResources().getBoolean(R.bool.ignore_sim_network_locked_events)) { // Some products don't have the concept of a "SIM network lock" Log.i( LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; " + "not showing 'SIM network unlock' PIN entry screen"); } else { // Normal case: show the "SIM network unlock" PIN entry screen. // The user won't be able to do anything else until // they enter a valid SIM network PIN. Log.i(LOG_TAG, "show sim depersonal panel"); IccNetworkDepersonalizationPanel ndpPanel = new IccNetworkDepersonalizationPanel(PhoneApp.getInstance()); ndpPanel.show(); } break; case EVENT_UPDATE_INCALL_NOTIFICATION: // Tell the NotificationMgr to update the "ongoing // call" icon in the status bar, if necessary. // Currently, this is triggered by a bluetooth headset // state change (since the status bar icon needs to // turn blue when bluetooth is active.) NotificationMgr.getDefault().updateInCallNotification(); break; case EVENT_DATA_ROAMING_DISCONNECTED: NotificationMgr.getDefault().showDataDisconnectedRoaming(); break; case EVENT_DATA_ROAMING_OK: NotificationMgr.getDefault().hideDataDisconnectedRoaming(); break; case MMI_COMPLETE: onMMIComplete((AsyncResult) msg.obj); break; case MMI_CANCEL: PhoneUtils.cancelMmiCode(phone); break; case EVENT_WIRED_HEADSET_PLUG: // Since the presence of a wired headset or bluetooth affects the // speakerphone, update the "speaker" state. We ONLY want to do // this on the wired headset connect / disconnect events for now // though, so we're only triggering on EVENT_WIRED_HEADSET_PLUG. if (!isHeadsetPlugged() && (mBtHandsfree == null || !mBtHandsfree.isAudioOn())) { // is the state is "not connected", restore the speaker state. PhoneUtils.restoreSpeakerMode(getApplicationContext()); } NotificationMgr.getDefault().updateSpeakerNotification(); break; case EVENT_SIM_STATE_CHANGED: // Marks the event where the SIM goes into ready state. // Right now, this is only used for the PUK-unlocking // process. if (msg.obj.equals(IccCard.INTENT_VALUE_ICC_READY)) { // when the right event is triggered and there // are UI objects in the foreground, we close // them to display the lock panel. if (mPUKEntryActivity != null) { mPUKEntryActivity.finish(); mPUKEntryActivity = null; } if (mPUKEntryProgressDialog != null) { mPUKEntryProgressDialog.dismiss(); mPUKEntryProgressDialog = null; } } break; case EVENT_UNSOL_CDMA_INFO_RECORD: // TODO: handle message here; break; } }
/** * Public API to get SIMInfoWrapper instance * * @param context * @param isInsertSim * @return SIMInfoWrapper instance */ static SIMInfoWrapper getDefault() { if (sSIMInfoWrapper == null) sSIMInfoWrapper = new SIMInfoWrapper(PhoneApp.getInstance()); return sSIMInfoWrapper; }