原创不得转载,你转载了请别去掉我的名字: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. ubuntu 使用android studio 查看android(android-5.1.0_r3)源码
  2. 怎样查看apk须要支持的Android版本号
  3. 【Android】Broadcast控制音乐暂停继续等
  4. 在Android中查看和管理sqlite数据库
  5. 【Android】Broadcast控制音乐暂停继续等
  6. 【Android】Broadcast控制音乐暂停继续等
  7. Android(安卓)adb.exe程序启动不起来,如何处理
  8. Android:adb常用命令汇总
  9. Android(安卓)无法查看外部依赖jar的源码的问题

随机推荐

  1. Android(安卓)WebView 加载网页遇到的问
  2. android写入任意路径中
  3. Android(安卓)ProgressDialog设置透明程
  4. android调用本地录制程序获取录制文件路
  5. Android(安卓)通过CANVAS旋转 绘制文字
  6. Android基于TitleBar页面导航实现
  7. Android(安卓)Demos 示例BitmapMesh中部
  8. android 用到的技巧集
  9. Android的support v4中的Fragment的一个B
  10. Android中短信拦截解决方案