예제 #1
0
 /**
  * Add call number info to call history database for international dialing feature !!!! need to
  * check okToLogThisCall is suitable for international dialing feature
  *
  * @param number The number for the call being logged.
  * @param start The start time of the call being logged.
  * @param duration The duration of the call being logged.
  * @param isSipCall whether sip call
  * @param slotId The slot id for the call being logged.
  */
 private void addCallHistoryAsync(
     String number, long start, long duration, boolean isSipCall, int slotId) {
   final boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(number, mApplication);
   if (!isEmergencyNumber
       && !mIsComing
       && mVtCall != CALL_TYPE_VIDEO
       && !isSipCall
       && duration >= CallNotifier.CALL_DURATION_THRESHOLD_FOR_CALL_HISTORY
       && slotId > -1) {
     String countryISO = CallOptionUtils.getCurrentCountryISO(PhoneGlobals.getInstance());
     try {
       new CallHistoryAsync()
           .addCall(
               new CallHistoryAsync.AddCallArgs(
                   PhoneGlobals.getInstance(),
                   number,
                   countryISO,
                   start,
                   slotId,
                   GeminiUtils.isGeminiSupport()));
     } catch (SQLiteDiskIOException e) {
       // TODO Auto-generated catch block
       Log.e(LOG_TAG, "Error!! - onDisconnect() Disk Full!");
       e.printStackTrace();
     }
   }
 }
예제 #2
0
  /**
   * getCallerInfo given a phone number and subscription, look up in the call-log database for the
   * matching caller id info.
   *
   * @param context the context used to get the ContentResolver
   * @param number the phone number used to lookup caller id
   * @param subId the subscription for checking for if voice mail number or not
   * @return the CallerInfo which contains the caller id for the given number. The returned
   *     CallerInfo is null if no number is supplied. If a matching number is not found, then a
   *     generic caller info is returned, with all relevant fields empty or null.
   */
  public static CallerInfo getCallerInfo(Context context, String number, int subId) {

    if (TextUtils.isEmpty(number)) {
      return null;
    }

    // Change the callerInfo number ONLY if it is an emergency number
    // or if it is the voicemail number.  If it is either, take a
    // shortcut and skip the query.
    if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
      return new CallerInfo().markAsEmergency(context);
    } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
      return new CallerInfo().markAsVoiceMail();
    }

    Uri contactUri =
        Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, Uri.encode(number));

    CallerInfo info = getCallerInfo(context, contactUri);
    info = doSecondaryLookupIfNecessary(context, number, info);

    // if no query results were returned with a viable number,
    // fill in the original number value we used to query with.
    if (TextUtils.isEmpty(info.phoneNumber)) {
      info.phoneNumber = number;
    }

    return info;
  }
예제 #3
0
  /** Logs a call to the call from the parameters passed in. */
  public void logCall(
      CallerInfo ci,
      String number,
      int presentation,
      int callType,
      long start,
      long duration,
      int slotId) {
    final boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(number, mApplication);

    // On some devices, to avoid accidental redialing of
    // emergency numbers, we *never* log emergency calls to
    // the Call Log.  (This behavior is set on a per-product
    // basis, based on carrier requirements.)
    final boolean okToLogEmergencyNumber =
        mApplication.getResources().getBoolean(R.bool.allow_emergency_numbers_in_call_log);

    // Don't log emergency numbers if the device doesn't allow it,
    boolean isOkToLogThisCall = !isEmergencyNumber || okToLogEmergencyNumber;

    if (isOkToLogThisCall) {
      if (DBG) {
        log(
            "sending Calllog entry: "
                + ci
                + ", "
                + PhoneUtils.toLogSafePhoneNumber(number)
                + ","
                + presentation
                + ", "
                + callType
                + ", "
                + start
                + ", "
                + duration);
      }

      /// M: For GEMINI or Other type call(Ex: sip call/video call) @{
      CallLogAsync.AddCallArgs args;
      if (mPhoneType == PhoneConstants.PHONE_TYPE_CDMA && mIsCdmaCallWaitingReject) {
        args =
            getCallArgsForCdmaCallWaitingReject(
                ci, number, presentation, callType, start, duration, slotId);
      } else {
        args = getCallArgs(ci, number, presentation, callType, start, duration, slotId);
      }
      /// @}

      try {
        mCallLog.addCall(args);
      } catch (SQLiteDiskIOException e) {
        // TODO Auto-generated catch block
        Log.e(LOG_TAG, "Error!! - logCall() Disk Full!");
        e.printStackTrace();
      }
    }
    reset();
  }
  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
  }
예제 #5
0
  /** Returns a mask of capabilities for the connection such as merge, hold, etc. */
  private int getCapabilitiesFor(Connection connection, Call call, boolean isForConference) {
    final boolean callIsActive = (call.getState() == Call.State.ACTIVE);
    final boolean callIsBackground = (call.getState() == Call.State.ONHOLD);
    final Phone phone = connection.getCall().getPhone();

    boolean canAddCall = false;
    boolean canMergeCall = false;
    boolean canSwapCall = false;
    boolean canRespondViaText = false;
    boolean canMute = false;
    boolean canAddParticipant = false;
    boolean canModifyCall = false;
    boolean voicePrivacy = false;
    final boolean supportHold;
    final boolean canHold;

    final boolean genericConf =
        isForConference
            && (connection.getCall().getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA);
    if (!MSimTelephonyManager.getDefault().isMultiSimEnabled()) {
      supportHold = PhoneUtils.okToSupportHold(mCallManager);
      canHold = (supportHold ? PhoneUtils.okToHoldCall(mCallManager) : false);

      // only applies to active calls
      if (callIsActive) {
        canMergeCall = PhoneUtils.okToMergeCalls(mCallManager);
        canSwapCall = PhoneUtils.okToSwapCalls(mCallManager);
      }
      canAddCall = PhoneUtils.okToAddCall(mCallManager);
    } else {
      final int subscription = call.getSubscription();
      supportHold = PhoneUtils.okToSupportHold(mCallManager, subscription);
      canHold = (supportHold ? PhoneUtils.okToHoldCall(mCallManager, subscription) : false);

      // only applies to active calls
      if (callIsActive) {
        canMergeCall = PhoneUtils.okToMergeCalls(mCallManager, subscription);
        canSwapCall = PhoneUtils.okToSwapCalls(mCallManager, subscription);
      }
      canAddCall = PhoneUtils.okToAddCall(mCallManager, subscription);
    }
    if (callIsActive || callIsBackground) {
      canModifyCall = PhoneUtils.isVTModifyAllowed(connection);
    }
    canAddParticipant = PhoneUtils.canAddParticipant(mCallManager) && canAddCall;

    // "Mute": only enabled when the foreground call is ACTIVE.
    // (It's meaningless while on hold, or while DIALING/ALERTING.)
    // It's also explicitly disabled during emergency calls or if
    // emergency callback mode (ECM) is active.
    boolean isEmergencyCall = false;
    if (connection != null) {
      isEmergencyCall =
          PhoneNumberUtils.isLocalEmergencyNumber(connection.getAddress(), phone.getContext());
    }
    boolean isECM = PhoneUtils.isPhoneInEcm(phone);
    if (isEmergencyCall || isECM) { // disable "Mute" item
      canMute = false;
    } else {
      canMute = callIsActive;
    }

    canRespondViaText = RejectWithTextMessageManager.allowRespondViaSmsForCall(call, connection);

    // special rules section!
    // CDMA always has Add
    if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
      canAddCall = true;
    }

    // Voice Privacy for CDMA
    if ((phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) && mVoicePrivacyState) {
      voicePrivacy = true;
    }

    int retval = 0x0;
    if (canHold) {
      retval |= Capabilities.HOLD;
    }
    if (supportHold) {
      retval |= Capabilities.SUPPORT_HOLD;
    }
    if (canAddCall) {
      retval |= Capabilities.ADD_CALL;
    }
    if (canMergeCall) {
      retval |= Capabilities.MERGE_CALLS;
    }
    if (canSwapCall) {
      retval |= Capabilities.SWAP_CALLS;
    }
    if (canRespondViaText) {
      retval |= Capabilities.RESPOND_VIA_TEXT;
    }
    if (canMute) {
      retval |= Capabilities.MUTE;
    }
    if (canAddParticipant) {
      retval |= Capabilities.ADD_PARTICIPANT;
    }
    if (genericConf) {
      retval |= Capabilities.GENERIC_CONFERENCE;
    }
    if (canModifyCall) {
      retval |= Capabilities.MODIFY_CALL;
    }
    if (voicePrivacy) {
      retval |= Capabilities.VOICE_PRIVACY;
    }
    return retval;
  }