原创不得转载,你转载了请别去掉我的名字:W歹匕示申W

否则举报你思想强奸!

1:搜索菜单按钮:

---- search_shortcut_make_video_call Matches (155 in 155 files) ----
DialerPhoneNumberListAdapter.java (y:\linux\android\packages\apps\dialer\src\com\android\dialer\list):                text = resources.getString(R.string.search_shortcut_make_video_call);
Strings.xml (y:\linux\android\packages\apps\dialer\res\values):    Make video call
查看菜单功能:
            case SHORTCUT_MAKE_VIDEO_CALL:
                text = resources.getString(R.string.search_shortcut_make_video_call);
                drawableId = R.drawable.ic_videocam;
                break;
                
2:搜索SHORTCUT_MAKE_VIDEO_CALL调用
---- SHORTCUT_MAKE_VIDEO_CALL Matches (5 in 4 files) ----
SearchFragment.java (y:\linux\android\packages\apps\dialer\src\com\android\dialer\list):            case DialerPhoneNumberListAdapter.SHORTCUT_MAKE_VIDEO_CALL:
搜索号码获取:
            case DialerPhoneNumberListAdapter.SHORTCUT_MAKE_VIDEO_CALL:
                number = TextUtils.isEmpty(mAddToContactNumber) ?
                        adapter.getQueryString() : mAddToContactNumber;
                listener = getOnPhoneNumberPickerListener();
                if (listener != null && !checkForProhibitedPhoneNumber(number)) {
                    listener.onCallNumberDirectly(number, true /* isVideoCall */);
                }
                break;
2.1:查看mAddToContactNumber:
   public void setAddToContactNumber(String addToContactNumber) {
        mAddToContactNumber = addToContactNumber;
    }
    搜索setAddToContactNumber:
        @Override
    public void onDialpadQueryChanged(String query) {
        if (mSmartDialSearchFragment != null) {
            mSmartDialSearchFragment.setAddToContactNumber(query);
        }
        搜索onDialpadQueryChanged调用:
            public interface OnDialpadQueryChangedListener {
        void onDialpadQueryChanged(String query);
    }
    搜索接口:OnDialpadQueryChangedListener
    private OnDialpadQueryChangedListener mDialpadQueryListener;
    搜索mDialpadQueryListener
           if (mDialpadQueryListener != null) {
            mDialpadQueryListener.onDialpadQueryChanged(mDigits.getText().toString());----拨号号码获取
        }
        本文件搜索mDigits
    2.2 :查看getOnPhoneNumberPickerListener:
    ---- getOnPhoneNumberPickerListener Matches (3 in 2 files) ----
PhoneNumberPickerFragment.java (y:\linux\android\packages\apps\contactscommon\src\com\android\contacts\common\list):    public OnPhoneNumberPickerActionListener getOnPhoneNumberPickerListener() {


        public OnPhoneNumberPickerActionListener getOnPhoneNumberPickerListener() {
        return mListener;
    }
查看OnPhoneNumberPickerActionListener监听器
   /**
    * Calls the specified phone number audio call.
    */
   void onCallNumberDirectly(String phoneNumber);
搜索onCallNumberDirectly
DialtactsActivity.java (y:\linux\android\packages\apps\dialer\src\com\android\dialer):    public void onCallNumberDirectly(String phoneNumber) {
   @Override
   public void onCallNumberDirectly(String phoneNumber) {
       onCallNumberDirectly(phoneNumber, false /* isVideoCall */);
   }
本文搜索onCallNumberDirectly
   @Override
   public void onCallNumberDirectly(String phoneNumber, boolean isVideoCall) {----------拨打视频电话,仔细分析判断
   查看:DialerUtils.startActivityWithErrorToast(this, intent);
   public static void startActivityWithErrorToast(Context context, Intent intent) {
       startActivityWithErrorToast(context, intent, R.string.activity_not_available);
   }
   查看: startActivityWithErrorToast
这里补充小知识:context instanceof Activity:他是java里面的二元运算符,判断左边的对象是否是右边类的实例。假如是的话,返回true;假如不是的话,返回false。
    public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) {
        try {
            if ((IntentUtil.CALL_ACTION.equals(intent.getAction())
                            && context instanceof Activity)) {
                // All dialer-initiated calls should pass the touch point to the InCallUI
                Point touchPoint = TouchPointManager.getInstance().getPoint();
                if (touchPoint.x != 0 || touchPoint.y != 0) {
                    Bundle extras = new Bundle();
                    extras.putParcelable(TouchPointManager.TOUCH_POINT, touchPoint);
                    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
                }
                final TelecomManager tm =
                        (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
                tm.placeCall(intent.getData(), intent.getExtras());---发生服务播出号码,服务启动跳转到正在拨号界面
            } else {
                context.startActivity(intent);-----返回的是拨号界面
            }
        } catch (ActivityNotFoundException e) {
            Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();----异常提示,异常类型msgId提示语,
        }
    }
    2.3搜索服务:TelecomManager, placeCall的函数
    TelecomManager.java (y:\linux\android\frameworks\base\telecomm\java\android\telecom):    public void placeCall(Uri address, Bundle extras) {
TelecomServiceImpl.java (y:\linux\android\packages\services\telecomm\src\com\android\server\telecom):        public void placeCall(Uri handle, Bundle extras, String callingPackage) {
查看TelecomServiceImpl.java服务类功能placeCall的函数
        @Override
        public void placeCall(Uri handle, Bundle extras, String callingPackage) {
final Intent intent = new Intent(Intent.ACTION_CALL, handle);
intent.putExtras(extras);
new UserCallIntentProcessor(mContext, userHandle).processIntent(intent,
callingPackage, hasCallAppOp && hasCallPermission);
查看UserCallIntentProcessor类的processIntent方法
public void processIntent(Intent intent, String callingPackageName,
--》processOutgoingCallIntent--》sendBroadcastToReceiver--》
   private boolean sendBroadcastToReceiver(Intent intent) {
       intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
       intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
       intent.setClass(mContext, PrimaryCallReceiver.class);
       Log.d(this, "Sending broadcast as user to CallReceiver");
       mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
       return true;
   }
前面N个return,没有打出去电话的自己打印LOG看跑了哪。
查看sendBroadcastToReceiver(intent);服务的发送。。。。。。。。。
    private boolean sendBroadcastToReceiver(Intent intent) {
        intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        intent.setClass(mContext, PrimaryCallReceiver.class);
        Log.d(this, "Sending broadcast as user to CallReceiver");
        mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
        return true;
    }继续查看PrimaryCallReceiver.class
public class PrimaryCallReceiver extends BroadcastReceiver implements TelecomSystem.Component {
    @Override
    public void onReceive(Context context, Intent intent) {
        synchronized (getTelecomSystem().getLock()) {
            getTelecomSystem().getCallIntentProcessor().processIntent(intent);
        }
    }继续查看getCallIntentProcessor
        public CallIntentProcessor getCallIntentProcessor() {
        return mCallIntentProcessor;
    }继续本文搜索mCallIntentProcessor
    mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager);
    继续查看CallIntentProcessor类中的processIntent
        public void processIntent(Intent intent) {
        final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);
        Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall);----------isUnknownCall打印LOG=false


        Trace.beginSection("processNewCallCallIntent");
        if (isUnknownCall) {
            processUnknownCallIntent(mCallsManager, intent);
        } else {
            processOutgoingCallIntent(mContext, mCallsManager, intent);-------进入这里
        }继续查看processOutgoingCallIntent方法
        注意看LOG打印分析方法中跑的位置
        LOG打印:
06-30 11:59:17.547 I/Telecom (13438): CallIntentProcessor: onReceive - isUnknownCall: false
06-30 11:59:17.548 D/Telecom (13438): Class: isSkipSchemaParsing = false
06-30 11:59:17.548 D/Telecom (13438): Class: isConferenceUri = false
06-30 11:59:17.548 D/Telecom (13438): Class: isAddparticipant = false
06-30 11:59:17.549 D/Telecom (13438): Class: callDomain = 0
06-30 11:59:17.549 D/Telecom (13438): Class: processOutgoingCallIntent callPull = false
06-30 11:59:17.550 I/Telecom (13438): Class:  processOutgoingCallIntent handle = tel:%2B917021095908,scheme = tel, uriString = +917021095908, isSkipSchemaParsing = false, isAddParticipant = false, isCallPull = false
        最终走入:
        发送到呼叫管理器,以确保InCallUI广播返回之前被拉开序幕:
        // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
        Call call = callsManager.startOutgoingCall(handle, phoneAccountHandle, clientExtras);
        继续查看startOutgoingCall
            Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras) {
            针对IMS的conf URI力tel架构/跳过模式调用来避免SIP帐号的选择:
            // Force tel scheme for ims conf uri/skip schema calls to avoid selection of sip accounts
        String scheme = (isSkipSchemaOrConfUri? PhoneAccount.SCHEME_TEL: handle.getScheme());
            注意LOG打印的3个值:
            06-30 11:59:42.140 D/Telecom (13438): CallsManager: startOutgoingCall :: isAddParticipant=false isSkipSchemaOrConfUri=false scheme=tel
            再看下面代码:
                    List accounts = null;
        if (VideoProfile.isVideo(call.getVideoState())) {
            accounts = mPhoneAccountRegistrar.getVideoCallCapablePhoneAccounts(scheme, false);
        } else {
            accounts = mPhoneAccountRegistrar.getCallCapablePhoneAccounts(scheme, false);
        }


        Log.v(this, "startOutgoingCall found accounts = " + accounts);
        打印结果:
        06-30 11:59:42.141 V/Telecom (13438): CallsManager: startOutgoingCall found accounts = [ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, [902ba3cda1883801594b6e1b452790cc53948fda], UserHandle{0}]
继续下看,很多拨出电话前的判断和处理:
       boolean isPotentialInCallMMICode = isPotentialInCallMMICode(handle);
//不支持任何更多的实时呼叫。我们的选择是移动通话持有,断开
//一个电话,或者干脆取消这个召唤。
        // Do not support any more live calls.  Our options are to move a call to hold, disconnect
        // a call, or cancel this call altogether.
        if (!isPotentialInCallMMICode && !makeRoomForOutgoingCall(call, call.isEmergencyCall())) {
            // just cancel at this point.
            Log.i(this, "No remaining room for outgoing call: %s", call);
            if (mCalls.contains(call)) {
                // This call can already exist if it is a reused call,
                // See {@link #getNewOutgoingCall}.
                call.disconnect();------------------------条件符合就挂断电话,不让拨出去。
            }
            return null;
        }
        继续下看:
                boolean needsAccountSelection = phoneAccountHandle == null && accounts.size() > 1 &&
                !call.isEmergencyCall();


        if (needsAccountSelection) {-------------需要帐户选择
            // This is the state where the user is expected to select an account
            call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");
            // Create our own instance to modify (since extras may be Bundle.EMPTY)
            extras = new Bundle(extras);
            extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, accounts);
        } else {
            call.setState(
                    CallState.CONNECTING,
                    phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
        }
        继续下看,低电量处理:
                Bundle callExtras = new Bundle();
        收拾低电量信息它是提供给InCallUI作进一步处理:        
        //pack low battery information for it to be available to InCallUI for further processing
        callExtras.putBoolean(QtiCallConstants.LOW_BATTERY_EXTRA_KEY,
                TelephonyUtil.isLowBattery(mContext));
        call.setExtras(callExtras);
        跳转查看TelephonyUtil.isLowBattery:
            static boolean isLowBattery(Context context) {
        if(!isCarrierOneSupported()) {
            return false;
        }


        Intent batteryStatus = context.registerReceiver(null,
                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));


        final int batteryLevel = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
        //determine whether device is under low battery or not based on battery level
        return (batteryLevel <= (context.getResources().getInteger(
                com.android.internal.R.integer.config_lowBatteryWarningLevel)));--------低电量提示等级config_lowBatteryWarningLevel
    }
    返回上一步继续查看:
            // Do not add the call if it is a potential MMI code.
            如果它是一个潜在的MMI代码不要添加呼叫。
        if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) {
            call.addListener(this);
        } else if (!mCalls.contains(call)) {
            // We check if mCalls already contains the call because we could potentially be reusing
            // a call which was previously added (See {@link #getNewOutgoingCall}).
//我们检查,如果mCalls已经包含了电话,因为我们可能被重用
//这是以前添加的调用(见{@link#getNewOutgoingCall})。            
            addCall(call);
        }
        return call;
        查看addCall方法:
            private void addCall(Call call) {
        Trace.beginSection("addCall");-------------------跟踪打印LOG
        Log.v(this, "addCall(%s)", call);----------------LOG打印
                打印:
        06-30 11:59:17.637 V/Telecom (13438): CallsManager: addCall([147747198, CONNECTING, null, tel:%2B917021095908, A, childs(0), has_parent(false), [[Capabilities:]], false, ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, [902ba3cda1883801594b6e1b452790cc53948fda], UserHandle{0}])
        call.addListener(this);
        mCalls.add(call);
updateCallsManagerState();
继续查看updateCallsManagerState方法
private void updateCallsManagerState() {
        updateForegroundCall();
        updateCanAddCall();
    }继续查看updateForegroundCall
    // TODO: Foreground-ness needs to be explicitly set. No call, regardless
            // of its state will be foreground by default and instead the connection service should
            // be notified when its calls enter and exit foreground state. Foreground will mean that
            // the call should play audio and listen to microphone if it wants.
// TODO:前景岬需要明确设置。没有呼叫,无论
//其状态会被默认前景和替代的连接服务应
//当其呼叫进入和退出前台状态//通知。前景将意味着
//调用应该播放音频和收听麦克风如果它想。
       if (TelephonyManager.getDefault().getMultiSimConfiguration()
                == TelephonyManager.MultiSimVariants.DSDA)
//如果活动子没有任何来电,然后再考虑在所有潜艇电话,
//这曾经打电话激活集作为前景的呼叫。给予更多的优先
//超过当前呼叫振铃的LCH子电话。                
            // if active sub doesn't have any calls, then consider calls on all subs,
            // which ever call is active set that as foreground call. give more priority
            // to ringing call on LCH sub over active call.
            if (newForegroundCall == null) {
                newForegroundCall = getFirstCallWithState(CallState.RINGING);
                if (newForegroundCall == null) {
                    newForegroundCall = getFirstCallWithState(CallState.ACTIVE);
                }
            }
            for (Call call : mCalls) {
                // Only top-level calls can be in foreground只有顶级的呼叫可以在前台
                if (call.getParentCall() != null) {
                    continue;
                }


                // Active calls have priority.活动呼叫享有优先权。
                if (call.isActive()) {
                    newForegroundCall = call;
                    break;
                }


                // If only call in call list is held call it's also a foreground call如果只在通话清单通话被保持调用它也是一个前台电话
                if (getNumTopLevelCalls() == 1 && call.getState() == CallState.ON_HOLD) {
                    newForegroundCall = call;
                }


                if ((call.isAlive() && call.getState() != CallState.ON_HOLD)
                     || call.getState() == CallState.RINGING) {
                    newForegroundCall = call;
                    // Don't break in case there's an active call that has priority.不要在案件不破有一个活跃的呼叫优先。
                }
            }
            / *在当按下主动保留按键,其中有2个呼叫的情况下,
*调用,作为一个中间状态,我们就必须在之前举行的状态两个呼叫
*后台调用移动到活动状态。在这样的一个中间阶段
*更新newForegroundCall为null出现问题的原因放弃音频
*焦点。跳过更新与空在这种情况下,前台打电话。 * /
        /* In the case where there are 2 calls, when the Hold button is pressed for active
         * call, as an intermediate state we would have both calls in held state before
         * the background call is moved to active state. In such an intermediate stage
         * updating the newForegroundCall to null causes issues with abandoning audio
         * focus. Skip updating the foreground call with null in such cases. */
        if (newForegroundCall == null && getFirstCallWithState(CallState.ON_HOLD) != null) {
            Log.v(this, "Skip updating foreground call in intermediate stage");
            newForegroundCall = mForegroundCall;
        }
        
        if (newForegroundCall != mForegroundCall) {
            Log.v(this, "Updating foreground call, %s -> %s.", mForegroundCall, newForegroundCall);
            打印:
06-30 11:59:52.705 V/Telecom (13438): CallsManager: Updating foreground call, [147747198, ON_HOLD, com.android.phone/com.android.services.telephony.TelephonyConnectionService, tel:%2B917021095908, A, childs(0), has_parent(false), [[Capabilities: CAPABILITY_HOLD CAPABILITY_SUPPORT_HOLD CAPABILITY_MUTE CAPABILITY_SUPPORTS_VT_REMOTE_RX CAPABILITY_SUPPORTS_VT_REMOTE_TX CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE CAPABILITY_HIGH_DEF_AUDIO]], false, ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, [902ba3cda1883801594b6e1b452790cc53948fda], UserHandle{0}] -> [174614848, DIALING, com.android.phone/com.android.services.telephony.TelephonyConnectionService, tel:7021263897, A, childs(0), has_parent(false), [[Capabilities: CAPABILITY_SUPPORT_HOLD CAPABILITY_MUTE]], false, ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, [902ba3cda1883801594b6e1b452790cc53948fda], UserHandle{0}].
其中有前台电话和后台电话,mForegroundCall:7021095908被保持了ON_HOLD,newForegroundCall:7021263897被推到前台拨号DIALING
            Call oldForegroundCall = mForegroundCall;
            mForegroundCall = newForegroundCall;


            for (CallsManagerListener listener : mListeners) {
                if (Log.SYSTRACE_DEBUG) {
                    Trace.beginSection(listener.getClass().toString() + " updateForegroundCall");
                }
                listener.onForegroundCallChanged(oldForegroundCall, mForegroundCall);
                if (Log.SYSTRACE_DEBUG) {
                    Trace.endSection();
                }
            }
        }
        跳出这个函数返回上一部,继续查看下一步要走的函数:updateCanAddCall
    private void updateCanAddCall() {
        boolean newCanAddCall = canAddCall();
        if (newCanAddCall != mCanAddCall) {
            mCanAddCall = newCanAddCall;
            for (CallsManagerListener listener : mListeners) {
                if (Log.SYSTRACE_DEBUG) {
                    Trace.beginSection(listener.getClass().toString() + " updateCanAddCall");
                }
                listener.onCanAddCallChanged(mCanAddCall);
                if (Log.SYSTRACE_DEBUG) {
                    Trace.endSection();
                }
            }
        }
    }继续查看CallsManagerListener的onCanAddCallChanged方法,算了,不看了,谁看自己看吧,累

更多相关文章

  1. android 永远锁屏解决方法
  2. android软键盘把页面挤上去的解决方法
  3. 解决EditText不显示光标的三种方法(总结)
  4. JS判断Android、iOS或浏览器的多种方法(四种方法)
  5. Android View onMeasure 方法
  6. Android Studio 3.0以后打包修改文件名方法
  7. 【Android】android开发过程遇到的问题以及解决方法总结

随机推荐

  1. 安卓布局知识点
  2. 特朗普打压微信,苹果不好受
  3. Android(安卓)SDK Platform 4.4.2【离线
  4. Android多线程--HandlerThread用法
  5. IntentTest
  6. 获取mic音量大小
  7. android在线播放mp4/3gp
  8. 一行代码引来的安全漏洞就让我们丢失了整
  9. android禁止状态栏下拉
  10. introduction to JAVA-based open-source