Android Telephone

我们实现了通信能力:

第一、我们支持sip固话通信功能,是一个完整的电话程序。我们支持sip呼出、sip呼入,打开/关闭扬声器,调整自己说话音量、调整对方音量,调起拨号盘进行指令输出。

第二、axb双呼。流程就是我们调用后端的接口,然后后端调用运营商的接口,然后运营商通过中间号打电话过来,并且打电话给我们要打的那个号码,然后我们之间建立了通信。

第三、支持axb双呼的自动接听,支持使用我们的程序替代系统默认电话程序。

这里我们先主要说下,我们的程序替代系统默认电话程序。

首先需要将我们的APP声明成一个具有电话功能的程序,即让系统觉得我们应用和手机自带的电话程序是一种类型的程序。

那么如何声明呢:

我们需要一个Activity和一个Service,我们就命名成PhoneActivity和PhoneService吧。其中PhoneService需要继承InCallService。

并且我们需要在AndroidManifest.xml中进行注册,代码如下:

        <activity android:name=".PhoneActivity">
            <!--region provides ongoing call UI必须有,否则调不起设置默认电话-->
            <intent-filter>
                <action android:name="android.intent.action.DIAL"/>
                <action android:name="android.intent.action.VIEW"/>

                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>

                <data android:scheme="tel"/>
            </intent-filter>
            <!--end region-->

            <!--region provides dial UI-->
            <intent-filter>
                <action android:name="android.intent.action.DIAL"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
            <!--end region-->
        </activity>

        <service
            android:name=".PhoneService"
            android:permission="android.permission.BIND_INCALL_SERVICE">
            <meta-data
                android:name="android.telecom.IN_CALL_SERVICE_UI"
                android:value="true"/>
            <intent-filter>
                <action android:name="android.telecom.InCallService"/>
            </intent-filter>
        </service>

为什么要进行这样的注册呢?目的是使我们的程序具有电话程序特征。

PhoneService用于监听电话通信状态。比如说当有来电或者去电,onCallAdded方法会被回调,

当有接听或者挂断,我们可以通过onStateChanged监听到。

然后,当用户在设置中打开开关后,会弹出切换系统默认电话程序的系统弹框。代码如下:

package com.zdj.phone;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.telecom.TelecomManager;
import android.view.View;
import android.widget.ImageView;

import com.zdj.phone.core.PhoneManager;
import com.zdj.systemfuncationlibrary.SystemUtils;

public class PhoneMainActivity extends AppCompatActivity implements View.OnClickListener {
    private ImageView switch_default_phone_application;
    private SharedPreferences appInfoSP;
    private SharedPreferences.Editor appInfoSPEditor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_phone_main);

        switch_default_phone_application = findViewById(R.id.switch_default_phone_application);
        switch_default_phone_application.setOnClickListener(this);

        appInfoSP = getApplicationContext().getSharedPreferences(getPackageName() + "_appInfo", Context.MODE_PRIVATE);
        appInfoSPEditor = appInfoSP.edit();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (isDefaultPhoneApplication()) {
            switch_default_phone_application.setTag(true);
            switch_default_phone_application.setImageResource(R.drawable.switch_on);
        } else {
            switch_default_phone_application.setTag(false);
            switch_default_phone_application.setImageResource(R.drawable.switch_off);
        }
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.switch_default_phone_application) {
            switchDefaultPhoneApplication();
        }
    }

    private boolean isDefaultPhoneApplication() {
        TelecomManager telecomManager = (TelecomManager) getSystemService(TELECOM_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (telecomManager.getDefaultDialerPackage() != null) {
                String defaultDialerPackage = telecomManager.getDefaultDialerPackage();
                if (defaultDialerPackage.equals(getPackageName())) {
                    return true;
                } else {
                    appInfoSPEditor.putString("defaultDialerPackage", defaultDialerPackage).commit();
                }
            }
        }
        return false;
    }

    private void switchDefaultPhoneApplication() {
        if (!(boolean)switch_default_phone_application.getTag()) {
            PhoneManager.setDefaultDialerSetWindow(this, getPackageName());
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                if (("huawei".equals(android.os.Build.BRAND.toLowerCase()) || "honor".equals(android.os.Build.BRAND.toLowerCase()))
                        && !SystemUtils.isHarmonyOS()) {
                    Intent hwIntent = new Intent();
                    hwIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    hwIntent.setClassName("com.android.settings", "com.android.settings.Settings$PreferredListSettingActivity");
                    startActivity(hwIntent);
                } else {
                    startActivity(new Intent("android.settings.MANAGE_DEFAULT_APPS_SETTINGS"));
                }
            } else {
                PhoneManager.setDefaultDialerSetWindow(this, appInfoSP.getString("defaultDialerPackage", ""));
            }
        }
    }
}

当将我们的应用设置成系统默认电话程序后,来电和去电都将是走我们的程序了(即走我们写的逻辑,弹出我们的通话界面)

下面,我们再贴出三个很重要的类,依次分别为PhoneActivity、PhoneService、PhoneManager。

PhoneActivity:

package com.zdj.phone.core;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;

import com.zdj.phone.R;
import com.zdj.phone.widget.DialPadDialog;
import com.zdj.zdjuilibrary.dialog.NormalInteractionDialog;

import java.util.List;

/**
 * <pre>
 *     author : dejinzhang
 *     time : 2021/09/10
 *     desc : 使我们的应用成为一个电话程序必需的组件
 * </pre>
 */
public class PhoneActivity extends Activity {
    private static final int MY_PERMISSIONS_CALL_PHONE = 1;
    private DialPadDialog dialPadDialog;
    private TextView tv_input_numbers;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.activity_phone);
        tv_input_numbers = findViewById(R.id.tv_input_numbers);

        dialPadDialog = new DialPadDialog(this, R.style.NotDarkenAndFirstDialogAnimationStyle);
        dialPadDialog.setCanceledOnTouchOutside(false);
        dialPadDialog.setCallback(new DialPadDialog.Callback() {
            @Override
            public void call(List<Character> list) {
                if (checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(PhoneActivity.this, new String[]{Manifest.permission.CALL_PHONE}, MY_PERMISSIONS_CALL_PHONE);
                } else {
                    callDeal(list);
                }
            }

            @Override
            public void collapse() {}

            @Override
            public void refreshShow(List<Character> list) {
                if (list.size() > 0) {
                    StringBuilder stringBuilder = new StringBuilder();
                    for (int i = 0; i < list.size(); i++) {
                        stringBuilder.append(list.get(i));
                    }
                    tv_input_numbers.setText(stringBuilder);
                    tv_input_numbers.setVisibility(View.VISIBLE);
                } else {
                    tv_input_numbers.setVisibility(View.GONE);
                }
            }
        });

        Uri uri = getIntent().getData();
        if (uri != null) {
            String uriString = uri.toString();
            if (uriString != null && uriString.startsWith("tel:")) {
                String phoneNumber = uriString.substring("tel:".length());
                if (!TextUtils.isEmpty(phoneNumber)) {
                    char[] numbers = phoneNumber.toCharArray();
                    for (int i = 0; i < numbers.length; i++) {
                        dialPadDialog.getInputStringList().add(numbers[i]);
                    }
                    tv_input_numbers.setText(phoneNumber);
                    tv_input_numbers.setVisibility(View.VISIBLE);
                }
            }
        }

        dialPadDialog.show();
        findViewById(R.id.iv_dial_pad).setOnClickListener(v -> dialPadDialog.show());
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == MY_PERMISSIONS_CALL_PHONE) {
            if (!(grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                NormalInteractionDialog normalInteractionDialog = new NormalInteractionDialog(this, R.style.DialogNoAnimationStyle);
                normalInteractionDialog.init(true, false, null,
                        getString(R.string.call_permission_hint), getString(R.string.cancel), getString(R.string.go_open));
                normalInteractionDialog.show();
                normalInteractionDialog.setCallback(new NormalInteractionDialog.Callback() {
                    @Override
                    public void done() {
                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        intent.setData(Uri.fromParts("package", getPackageName(), null));
                        startActivity(intent);
                    }

                    @Override
                    public void cancel() {}
                });
            } else {
                callDeal(dialPadDialog.getInputStringList());
            }
        }
    }

    private void callDeal(List<Character> list) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            stringBuilder.append(list.get(i));
        }
        PhoneManager.call(this, stringBuilder.toString());
    }
}

PhoneService:

package com.zdj.phone.core;

import android.content.Intent;
import android.telecom.Call;
import android.telecom.InCallService;

import com.zdj.phone.Config;
import com.zdj.phone.ScreenActivity;
import com.zdj.systemfuncationlibrary.LogUtils;

/**
 * <pre>
 *     author : dejinzhang
 *     time : 2021/09/10
 *     desc : 服务
 * </pre>
 */
public class PhoneService extends InCallService {
    private static final String TAG = "PhoneService";

    @Override
    public void onCreate() {
        super.onCreate();
    }

    private Call.Callback callback = new Call.Callback() {
        @Override
        public void onStateChanged(Call call, int state) {
            super.onStateChanged(call, state);
            LogUtils.i(TAG, "state:" + state);
            if (state == Call.STATE_ACTIVE) {
                LogUtils.i(TAG, "----接听一个电话----" + call.toString());
                //在这里可以发送广播,通知通话界面变化
                Intent intent = new Intent();
                intent.setAction(ScreenActivity.CALL_NET_ING);
                sendBroadcast(intent);
            } else if (state == Call.STATE_DISCONNECTED) {
                LogUtils.i(TAG, "---挂断一个电话----" + call.toString());
                //在这里可以发送广播,通知通话界面变化
                Intent intent = new Intent();
                intent.setAction(ScreenActivity.CALL_NET_END);
                sendBroadcast(intent);
//                call.unregisterCallback(callback);  //其实这句代码也可以注释掉,因为当连接断开时,即电话挂断的时候,会在进入这个监听后,再回调onCallRemoved,我们在onCallRemoved中取消注册回调即可
            }/* else if (state == Call.STATE_CONNECTING) {
                LogUtils.i(TAG, "----呼叫,正在建立连接----" + call.toString());
                //我们也可以根据业务在这里执行相应动作。
            }*/
        }
    };

    @Override
    public void onCallAdded(Call call) {
        super.onCallAdded(call);
        LogUtils.i(TAG, "----添加一个电话----");
        call.registerCallback(callback);  //注册回调
        Call.Details details = call.getDetails();
        String phoneNumber = "";
        int state;
        if (details != null && details.getHandle() != null) {
            phoneNumber = details.getHandle().getSchemeSpecificPart();
        }
        state = call.getState();
        LogUtils.i(TAG, "phoneNumber:" + phoneNumber);
        LogUtils.i(TAG, "callState:" + state);
        Config.call = call;

        //在这里可以跳转到通话界面
        Intent intent = new Intent();
        intent.setClass(this, ScreenActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        intent.putExtra("phoneNum", phoneNumber);
        if (state == Call.STATE_RINGING) {
            intent.putExtra("from", ScreenActivity.NET_IN);
        } else if (state == Call.STATE_CONNECTING) {
            intent.putExtra("from", ScreenActivity.NET_OUT);
        }
        startActivity(intent);
    }

    @Override
    public void onCallRemoved(Call call) {
        super.onCallRemoved(call);
        LogUtils.i(TAG, "----移除一个电话----" + call.toString());
        call.unregisterCallback(callback);
    }
}

PhoneManager:

package com.zdj.phone.core;

import android.Manifest;
import android.app.Activity;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.telecom.Call;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;

import static android.content.Context.AUDIO_SERVICE;
import static android.content.Context.TELECOM_SERVICE;

/**
 * <pre>
 *     author : dejinzhang
 *     time : 2021/09/09
 *     desc : 电话管理器。该类中包含了对电话操作的各类方法:
 *            接听、挂断,以及弹出设置应用为系统默认电话程序(会弹出切换系统电话程序的系统弹框)的方法。
 * </pre>
 */
public class PhoneManager {
    /**
     * 设置应用为系统默认电话程序(会弹出切换系统默认电话程序的系统弹框)
     * 注意:
     * Android 10以上使用RoleManager
     * Android 6 ~ Android 9以上使用TelecomManager
     * Android 6以下不支持(因为Android 6以下call.answer call.disconnect等api不能用)
     * @param context  上下文
     * @param packageName  需要设置为系统默认电话程序的应用包名
     */
    public static void setDefaultDialerSetWindow(Context context, String packageName) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            RoleManager roleManager = context.getSystemService(RoleManager.class);
            if (roleManager != null) {
                Intent roleRequestIntent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
                ((Activity)context).startActivityForResult(roleRequestIntent, 999);
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            TelecomManager telecomManager = (TelecomManager) context.getSystemService(TELECOM_SERVICE);
            if (telecomManager != null) {
                Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
                intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName);
                context.startActivity(intent);
            }
        }
    }

    /**
     * 接听电话
     * @param call  call对象
     */
    public static void answer(Call call) {
        if (call != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                call.answer(VideoProfile.STATE_AUDIO_ONLY);
            }
        }
    }

    /**
     * 断开电话,包括来电时的拒接以及接听后的挂断
     * @param call  call对象
     */
    public static void hangup(Call call) {
        if (call != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                call.disconnect();
            }
        }
    }

    /**
     * 打电话
     * @param context  上下文
     * @param phoneNumber  所要拨打的号码
     */
    public static void call(Context context, String phoneNumber) {
        if (context.checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_CALL);
            intent.setData(Uri.parse("tel:" + phoneNumber));
            context.startActivity(intent);
        }
    }

    /**
     * 挂起
     * @param call  call对象
     */
    public static void hold(Call call) {
        if (call != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                call.hold();
            }
        }
    }

    /**
     * 取消挂起
     * @param call  call对象
     */
    public static void unHold(Call call) {
        if (call != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                call.unhold();
            }
        }
    }

    /**
     * 指示此 {@code Call} 播放双音多频信号 (DTMF) 音调。
     * @param call  call对象
     * @param digit  输入的指令数字
     */
    public static void playDtmfTone(Call call, char digit) {
        if (call != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                call.playDtmfTone(digit);
                call.stopDtmfTone();
            }
        }
    }

    /**
     * 打开/关闭扬声器
     * @param context  上下文
     * @param on  true 打开扬声器  false 关闭扬声器
     */
    public static void switchSpeaker(Context context, boolean on) {
        AudioManager audioManager = (AudioManager) context.getSystemService(AUDIO_SERVICE);
        if (audioManager != null) {
            audioManager.setSpeakerphoneOn(on);
            if (!on && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                audioManager.setMode(AudioManager.MODE_IN_CALL);
            }
        }
    }
}

关于PhoneManager,我们这里再简单介绍下,PhoneManager是一个包括了接听、挂断等很多操作的管理器。 

ok,接下来,我们就是还需要一个通话界面了,我们再贴出我们的通话界面对应的ScreenActivity以及activity_screen.xml。

ScreenActivity:

package com.zdj.phone;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.zdj.phone.adapter.DialPadAdapter;
import com.zdj.phone.core.PhoneManager;
import com.zdj.systemfuncationlibrary.LogUtils;
import com.zdj.systemfuncationlibrary.MatchUtils;
import com.zdj.systemfuncationlibrary.SystemUtils;
import com.zdj.systemfuncationlibrary.UiUtils;
import com.zdj.zdjuilibrary.popup_window.VolumePopupWindow;


/**
 * <pre>
 *     author : dejinzhang
 *     time : 2021/09/12
 *     desc : 通话界面
 * </pre>
 */
public class ScreenActivity extends Activity implements SensorEventListener {
    private static final String TAG = "ScreenActivity";
    public static final String CALL_NET_END = "call_net_end";
    public static final String CALL_NET_ING = "call_net_ing";
    public static final String NET_IN = "net_in";
    public static final String NET_OUT = "net_out";

    private TextView phoneNumTxt, phoneInfo, inputTxt, statusTxt,
            tv_tel_microphone, tv_tel_receiver, tv_on_speakerphone, tv_dial;
    private LinearLayout ll_no, ll_ok, ll_relevant_operate;
    private GridView gv_dial_pad;

    private VolumePopupWindow volumePopupWindow;  //调节音量的popupWindow

    private String phoneNum = "";
    private String phoneFrom = "";  //标记是呼出,还是呼入,即打电话还是接电话。"net_in"---呼入;"net_out"---呼出。
    private boolean isPhoneHide;  //是否对号码进行脱敏处理
    private boolean isSip;  //是否是sip固话
    private boolean isAxbTwoAutoAnswer;  //是否是axb双呼自动接听
    private boolean isHeadset;  //是否有耳机
    private boolean isRing;  //是否正在响铃
    private boolean isNetting;

    private TelephonyManager telephonyManager;  //电话管理器
    private AudioManager audioManager;  //声音管理器
//    private SensorManager sensorManager;  //传感器管理器
//    private Sensor mProximity;  //传感器实例
    private AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener;  //更新系统对音频焦点时要调用的回调的接口实例

    private static final int MY_PERMISSIONS_RECORD_AUDIO = 1;

    private final BroadcastReceiver mEndCallReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent == null) {
                return;
            }
            LogUtils.i(TAG, "intent.getAction()===" + intent.getAction());
            if (intent.getAction().equals("android.intent.action.PHONE_STATE")) {
                telephonyManager = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
                switch (telephonyManager.getCallState()) {
                    case TelephonyManager.CALL_STATE_RINGING:  //来电响铃
                        LogUtils.i(TAG, "---来电话了---");
                        break;
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        LogUtils.i(TAG, "---接听电话---");  //接听电话
                        Message message = Message.obtain();
                        message.what = 1;
                        message.obj = intent.getAction();
                        callbackHandler.sendMessage(message);
                        break;
                    case TelephonyManager.CALL_STATE_IDLE:  //挂断电话
                        LogUtils.i(TAG, "---挂断电话---");
                        Toast.makeText(ScreenActivity.this, getString(R.string.call_ended), Toast.LENGTH_SHORT).show();
                        break;
                }
            } else if (intent.getAction().equals("android.intent.action.HEADSET_PLUG")) {
                if (intent.hasExtra("state")) {
                    if (intent.getIntExtra("state", 0) == 0) {
                        isHeadset = false;
                    } else if (intent.getIntExtra("state", 0) == 1) {
                        isHeadset = true;
                        if (isRing) {
                            return;
                        }
                        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                            audioManager.setSpeakerphoneOn(false);
                            audioManager.setMode(AudioManager.MODE_IN_CALL);
                        } else {
                            audioManager.setSpeakerphoneOn(false);
                        }
                    }
                }
            } else {
                Message msg = Message.obtain();
                msg.what = 1;
                msg.obj = intent.getAction();
                callbackHandler.sendMessage(msg);
            }
        }
    };

    private final Handler callbackHandler = new CallbackHandler();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
//        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
//        mProximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
        mAudioFocusChangeListener = focusChange -> {
            if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
                LogUtils.i(TAG, "---失去焦点---");
            } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
                LogUtils.i(TAG, "---获得焦点---");
            }
        };
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_screen);

        if (getIntent().hasExtra("isPhoneHide")) {
            isPhoneHide = getIntent().getBooleanExtra("isPhoneHide", false);
        }

        if (getIntent().hasExtra("isAxbTwoAutoAnswer")) {
            isAxbTwoAutoAnswer = getIntent().getBooleanExtra("isAxbTwoAutoAnswer", false);
        }

        if (getIntent().hasExtra("from")) {
            phoneFrom = getIntent().getStringExtra("from");
        }

        initView();

        if (getIntent().hasExtra("phoneNum")) {
            phoneNum = getIntent().getStringExtra("phoneNum");
            if (!TextUtils.isEmpty(phoneNum)) {
                if (phoneNum.contains("sip:") && phoneNum.contains("@")) {
                    isSip = true;
                    phoneNum = phoneNum.substring(phoneNum.indexOf(":") + 1, phoneNum.indexOf("@"));
                    if (phoneFrom.equals(NET_IN)) {
                        //调用后端接口获取客户信息并显示在界面上。如果获取不到,表示来电不在库中,此时不显示即可。
                    }
                } else {
                    isSip = false;
                }
            } else {
                isSip = true;  //默认按sip来处理
                phoneNum = "未知号码";
            }
        }

        if (phoneFrom.equals(NET_IN)) {  //呼入
            isRing = true;
            audioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
            if (!isAxbTwoAutoAnswer) {
                ll_ok.setVisibility(View.VISIBLE);
                ll_no.setVisibility(View.VISIBLE);
                SystemUtils.playSound(this, R.raw.ring, true);  //播放铃声
                callStatus = 2;
            } else {
                ll_no.setVisibility(View.VISIBLE);
                PhoneManager.answer(Config.call);
                callStatus = 3;
                registerReceiver(mEndCallReceiver, new IntentFilter(CALL_NET_END));
                animationHandler.postDelayed(timeRunnable, 1000);
                ll_relevant_operate.setVisibility(View.VISIBLE);
                tv_tel_receiver.setVisibility(View.GONE);
                tv_tel_microphone.setVisibility(View.GONE);
            }
        } else if (phoneFrom.equals(NET_OUT)) {  //呼出
            audioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
            ll_no.setVisibility(View.VISIBLE);
            ll_relevant_operate.setVisibility(View.VISIBLE);
            callStatus = CONNECTING;
            if (!isSip) {
                tv_tel_receiver.setVisibility(View.GONE);
                tv_tel_microphone.setVisibility(View.GONE);
            }
        }
        StringBuilder stringBuilder = new StringBuilder();
        if (isPhoneHide) {
            if (!phoneNum.equals("未知号码")) {
                stringBuilder.append(UiUtils.desensitizePhoneNum(phoneNum));
            } else {
                stringBuilder.append(phoneNum);
            }
        } else {
            if (MatchUtils.isLegalMobilePhoneNum(phoneNum)) {
                stringBuilder.append(phoneNum.substring(0, 3)).append("-").append(phoneNum.substring(3, 7)).append("-").append(phoneNum.substring(7));
            } else if (phoneNum.startsWith("400") && phoneNum.length() == 10) {
                stringBuilder.append(phoneNum.substring(0, 3)).append("-").append(phoneNum.substring(3, 6)).append("-").append(phoneNum.substring(6));
            } else if (phoneNum.length() > 5) {
                if (phoneNum.startsWith("01") || phoneNum.startsWith("02")) {
                    stringBuilder.append(phoneNum.substring(0, 3)).append("-").append(phoneNum.substring(3));
                } else {
                    stringBuilder.append(phoneNum.substring(0, 4)).append("-").append(phoneNum.substring(4));
                }
            } else {
                stringBuilder.append(phoneNum);
            }
        }
        phoneNumTxt.setText(stringBuilder);

        if (!isAxbTwoAutoAnswer) {
            registerReceiver(mEndCallReceiver, new IntentFilter(CALL_NET_END));
            registerReceiver(mEndCallReceiver, new IntentFilter(CALL_NET_ING));
            if (isSip) {
                registerReceiver(mEndCallReceiver, new IntentFilter("android.intent.action.PHONE_STATE"));
                registerReceiver(mEndCallReceiver, new IntentFilter("android.intent.action.HEADSET_PLUG"));
            }
            animationHandler.postDelayed(timeRunnable, 1000);
        }

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, MY_PERMISSIONS_RECORD_AUDIO);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        /*//注册传感器
        if (sensorManager != null) {
            sensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
        }*/
        //如果是sip,这里要发送CALL_NET_END的广播
    }

    @Override
    protected void onPause() {
        super.onPause();
        /*//取消注册传感器
        if (sensorManager != null) {
            sensorManager.unregisterListener(this);
        }*/
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        try {
            unregisterReceiver(mEndCallReceiver);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (!isAxbTwoAutoAnswer) {
            animationHandler.removeCallbacks(timeRunnable);
        }
        currentTime = 0;
        audioManager.abandonAudioFocus(mAudioFocusChangeListener);  //释放焦点
        //如果是sip的话,这里要进行一些恢复操作
        super.onDestroy();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case MY_PERMISSIONS_RECORD_AUDIO:
                if (!(grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(this)
                            .setMessage(getString(R.string.microphone_permission_request_hint_text))
                            .setPositiveButton(getString(R.string.ok), (dialog, which) -> {
                                ActivityCompat.requestPermissions(ScreenActivity.this, new String[]{Manifest.permission.RECORD_AUDIO}, MY_PERMISSIONS_RECORD_AUDIO);
                            })
                            .setNegativeButton(getString(R.string.cancel), (dialog, which) -> {
                                if (isSip) {
                                    //调用sip的挂断接口
                                } else {
                                    PhoneManager.hangup(Config.call);
                                }
                            });
                    builder.create().show();
                }
                break;
        }
    }

    private void initView() {
        ll_no = findViewById(R.id.ll_no);
        ll_ok = findViewById(R.id.ll_ok);
        ImageView iv_no = findViewById(R.id.iv_no);
        ImageView iv_ok = findViewById(R.id.iv_ok);
        phoneNumTxt = findViewById(R.id.call_phone_num);
        phoneInfo = findViewById(R.id.phone_info);
        inputTxt = findViewById(R.id.input_text);
        statusTxt = findViewById(R.id.call_status);
        ll_relevant_operate = findViewById(R.id.ll_relevant_operate);
        tv_tel_microphone = findViewById(R.id.tv_tel_microphone);
        tv_tel_receiver = findViewById(R.id.tv_tel_receiver);
        tv_on_speakerphone = findViewById(R.id.tv_on_speakerphone);
        tv_dial = findViewById(R.id.tv_dial);
        gv_dial_pad = findViewById(R.id.gv_dial_pad);
        final DialPadAdapter dialPadAdapter = new DialPadAdapter(this, DialPadAdapter.SCREEN_UI);
        gv_dial_pad.setAdapter(dialPadAdapter);
        gv_dial_pad.setSelector(new ColorDrawable(Color.TRANSPARENT));
        gv_dial_pad.setOnItemClickListener((parent, view, position, id) -> {
            String str = dialPadAdapter.getList().get(position).getMainText();
            String existsText = inputTxt.getText().toString();
            StringBuilder stringBuilder = new StringBuilder();
            if (!TextUtils.isEmpty(existsText)) {
                stringBuilder.append(existsText);
            }
            stringBuilder.append(str);
            inputTxt.setText(stringBuilder);
            inputTxt.setVisibility(View.VISIBLE);
            if (isSip) {
                //调用sip的输入指令的接口
            } else {
                PhoneManager.playDtmfTone(Config.call, str.charAt(0));
            }
        });

        View.OnClickListener clickListener = v -> {
            if (v.getId() == R.id.tv_tel_microphone) {
                tv_tel_microphone.setTag(!((boolean) tv_tel_microphone.getTag()));
                tv_tel_microphone.setTextColor(((boolean) tv_tel_microphone.getTag()) ? Color.parseColor("#D6E3F4") : Color.parseColor("#62696C"));
                tv_tel_microphone.setCompoundDrawablesRelativeWithIntrinsicBounds(0, ((boolean) tv_tel_microphone.getTag()) ? R.drawable.tel_microphone_highlight : R.drawable.tel_microphone, 0, 0);
                if ((boolean)tv_tel_receiver.getTag()) {
                    tv_tel_receiver.setTag(false);
                    tv_tel_receiver.setTextColor(Color.parseColor("#62696C"));
                    tv_tel_receiver.setCompoundDrawablesRelativeWithIntrinsicBounds(0, R.drawable.tel_receiver, 0, 0);
                    if (volumePopupWindow != null) {
                        volumePopupWindow.dismiss();
                    }
                }
                if ((boolean) tv_tel_microphone.getTag()) {
                    showVolumePopupWindow(tv_tel_microphone);
                } else {
                    if (volumePopupWindow != null) {
                        volumePopupWindow.dismiss();
                    }
                }
            } else if (v.getId() == R.id.tv_tel_receiver) {
                tv_tel_receiver.setTag(!((boolean) tv_tel_receiver.getTag()));
                tv_tel_receiver.setTextColor(((boolean) tv_tel_receiver.getTag()) ? Color.parseColor("#D6E3F4") : Color.parseColor("#62696C"));
                tv_tel_receiver.setCompoundDrawablesRelativeWithIntrinsicBounds(0, ((boolean) tv_tel_receiver.getTag()) ? R.drawable.tel_receiver_highlight : R.drawable.tel_receiver, 0, 0);
                if ((boolean)tv_tel_microphone.getTag()) {
                    tv_tel_microphone.setTag(false);
                    tv_tel_microphone.setTextColor(Color.parseColor("#62696C"));
                    tv_tel_microphone.setCompoundDrawablesRelativeWithIntrinsicBounds(0, R.drawable.tel_microphone, 0, 0);
                    if (volumePopupWindow != null) {
                        volumePopupWindow.dismiss();
                    }
                }
                if ((boolean)tv_tel_receiver.getTag()) {
                    showVolumePopupWindow(tv_tel_receiver);
                } else {
                    if (volumePopupWindow != null) {
                        volumePopupWindow.dismiss();
                    }
                }
            } else if (v.getId() == R.id.tv_on_speakerphone) {
                tv_on_speakerphone.setTag(!((boolean) tv_on_speakerphone.getTag()));
                tv_on_speakerphone.setTextColor(((boolean) tv_on_speakerphone.getTag()) ? Color.parseColor("#D6E3F4") : Color.parseColor("#62696C"));
                tv_on_speakerphone.setCompoundDrawablesRelativeWithIntrinsicBounds(0, ((boolean) tv_on_speakerphone.getTag()) ? R.drawable.on_speakerphone_highlight : R.drawable.on_speakerphone, 0, 0);
                PhoneManager.switchSpeaker(ScreenActivity.this, (boolean)tv_on_speakerphone.getTag());
            } else if (v.getId() == R.id.tv_dial) {
                tv_dial.setTag(!((boolean)tv_dial.getTag()));
                if ((boolean)tv_dial.getTag()) {
                    gv_dial_pad.setVisibility(View.VISIBLE);
                } else {
                    gv_dial_pad.setVisibility(View.GONE);
                }
            }
        };
        tv_tel_microphone.setOnClickListener(clickListener);
        tv_tel_microphone.setTag(false);
        tv_tel_receiver.setOnClickListener(clickListener);
        tv_tel_receiver.setTag(false);
        tv_on_speakerphone.setOnClickListener(clickListener);
        tv_on_speakerphone.setTag(false);
        tv_dial.setOnClickListener(clickListener);
        tv_dial.setTag(false);

        //接听电话
        iv_ok.setOnClickListener(v -> {
            if (phoneFrom.equals(NET_IN)) {
                if (isSip) {
                    //调用sip的接听电话的接口
                    Intent intent = new Intent();
                    intent.setAction(ScreenActivity.CALL_NET_ING);
                    sendBroadcast(intent);
                    ll_relevant_operate.setVisibility(View.VISIBLE);
                } else {
                    PhoneManager.answer(Config.call);
                    ll_relevant_operate.setVisibility(View.VISIBLE);
                    tv_tel_receiver.setVisibility(View.GONE);
                    tv_tel_microphone.setVisibility(View.GONE);
                }
            }
        });
        //挂断电话
        iv_no.setOnClickListener(v -> {
            if (phoneFrom.equals(NET_IN) || phoneFrom.equals(NET_OUT)) {
                if (isSip) {
                    //调用sip的挂断电话的接口
                } else {
                    PhoneManager.hangup(Config.call);
                }
            }
        });
    }

    //未知
    private static final int UNKNOWN = 0;
    //正在呼叫
    private static final int CONNECTING = 1;
    //正在响铃(等待接听)
    private static final int RING = 2;
    //通话中
    private static final int CONNECTED = 3;
    private int callStatus = UNKNOWN;
    private int currentTime;
    private Runnable timeRunnable = new Runnable() {
        @Override
        public void run() {
            currentTime++;
            switch (callStatus) {
                case CONNECTING:
                    if (currentTime % 4 == 0) {
                        statusTxt.setText("正在呼叫");
                    } else if (currentTime % 4 == 1) {
                        statusTxt.setText(" 正在呼叫.");
                    } else if (currentTime % 4 == 2) {
                        statusTxt.setText("  正在呼叫..");
                    } else if (currentTime % 4 == 3) {
                        statusTxt.setText("   正在呼叫...");
                    }
                    break;
                case RING:
                    break;
                case CONNECTED:
                    statusTxt.setText(new StringBuilder().append(UiUtils.formatAA(currentTime / 60)).append(":").append(UiUtils.formatAA(currentTime % 60)));
                    break;
            }
            animationHandler.postDelayed(timeRunnable, 1000);
        }
    };
    private final Handler animationHandler = new Handler();

    /**
     * 注意:该方法目前不会被回调,因为通过传感器判断距离,进一步自动打开/关闭扬声器的功能,目前禁掉了,但是代码保留,需要用开放即可。
     * @param event
     */
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (isHeadset) {
            return;
        }
        float[] its = event.values;
        LogUtils.i(TAG, "its[0]:" + its[0]);
        if (!(boolean) tv_on_speakerphone.getTag()) {  //表示未手动打开扬声器
            if (its[0] == 0.0) {  //贴近手机
                PhoneManager.switchSpeaker(this, false);
                tv_on_speakerphone.setTextColor(Color.parseColor("#62696C"));
                tv_on_speakerphone.setCompoundDrawablesRelativeWithIntrinsicBounds(0, R.drawable.on_speakerphone, 0, 0);
                tv_on_speakerphone.setTag(false);
            } else {  //远离手机
                PhoneManager.switchSpeaker(this, true);
                tv_on_speakerphone.setTextColor(Color.parseColor("#D6E3F4"));
                tv_on_speakerphone.setCompoundDrawablesRelativeWithIntrinsicBounds(0, R.drawable.on_speakerphone_highlight, 0, 0);
                tv_on_speakerphone.setTag(true);
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}

    private void showVolumePopupWindow(final View targetView) {
        if (volumePopupWindow == null) {
            volumePopupWindow = new VolumePopupWindow(LayoutInflater.from(this).inflate(R.layout.popup_window_volume, null),
                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        volumePopupWindow.setCallback(progress -> {
            if (targetView.getId() == R.id.tv_tel_microphone) {
                //调用sip的接口调节话筒的音量
            } else if (targetView.getId() == R.id.tv_tel_receiver) {
                //调用sip的接口调节听筒的音量
            }
        });
        if (targetView.getId() == R.id.tv_tel_microphone) {
//            volumePopupWindow.initProgress();  //initProgress方法中的参数使用sip的接口获取
        } else if (targetView.getId() == R.id.tv_tel_receiver) {
//            volumePopupWindow.initProgress();  //initProgress方法中的参数使用sip的接口获取
        }
        int[] location = new int[2];
        targetView.getLocationOnScreen(location);
        int temp_width = (UiUtils.dpToPx(this, 80) - targetView.getWidth()) / 2;
        volumePopupWindow.showAtLocation(targetView, Gravity.NO_GRAVITY, location[0] - temp_width, location[1] - UiUtils.dpToPx(this, 90));
    }

    class CallbackHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            if (msg.what == 1) {
                String action = String.valueOf(msg.obj);
                if (action.equals(CALL_NET_ING)) {  //正在通话
                    if (isNetting) {
                        return;
                    }
                    isNetting = true;
                    isRing = false;
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                        audioManager.setSpeakerphoneOn(false);
                        audioManager.setMode(AudioManager.MODE_IN_CALL);
                    } else {
                        audioManager.setSpeakerphoneOn(false);
                    }
                    currentTime = 0;
                    callStatus = CONNECTED;
                    if (ll_ok != null) {
                        ll_ok.setVisibility(View.GONE);
                    }
                    if (ll_no != null) {
                        ll_no.setVisibility(View.VISIBLE);
                    }
                    SystemUtils.stopSound();  //停止播放铃声
                } else if (action.equals(CALL_NET_END)) {
                    if (ll_ok != null) {
                        ll_ok.setVisibility(View.GONE);
                    }
                    if (ll_no != null) {
                        ll_no.setVisibility(View.GONE);
                    }
                    isRing = false;
                    LogUtils.i(TAG, "---call_net_end---");
                    SystemUtils.stopSound();  //停止播放铃声
                    statusTxt.setText(getString(R.string.call_ended));
                    Toast.makeText(ScreenActivity.this, getString(R.string.call_ended), Toast.LENGTH_SHORT).show();
                    finish();
                } else if (action.equals("android.intent.action.PHONE_STATE")) {
                    //调用sip的挂断电话的接口
                }
            }
        }
    }
}

activity_screen.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#2f343a">

    <!--号码-->
    <TextView
        android:id="@+id/call_phone_num"
        android:layout_width="match_parent"
        android:layout_height="90dp"
        android:gravity="bottom|center_horizontal"
        android:text="@string/unknown_call"
        android:textColor="@color/white"
        android:textSize="32dp"/>

    <!--电话归属信息:比如客户名称、联系人姓名-->
    <TextView
        android:id="@+id/phone_info"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16dp"
        android:textColor="@color/white"
        android:layout_marginTop="10dp"
        android:lineSpacingExtra="5dp"
        android:gravity="center"
        android:visibility="gone"/>

    <!--用户输入的指令,比如拨打10086的时候调起软键盘输入1-->
    <TextView
        android:id="@+id/input_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="@color/white"
        android:textSize="18dp"
        android:layout_marginTop="10dp"
        android:visibility="gone"/>

    <!--通话状态,比如显示"正在呼叫"或者当前的通话时长等等-->
    <TextView
        android:id="@+id/call_status"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:gravity="center"
        android:textColor="@color/white"
        android:textSize="16dp"/>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1">

        <com.zdj.zdjuilibrary.view.RippleView
            android:id="@+id/layout_ripple"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ff2f343a"
            android:fitsSystemWindows="true"
            android:gravity="center">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/call_icon"/>
        </com.zdj.zdjuilibrary.view.RippleView>

        <GridView
            android:id="@+id/gv_dial_pad"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:verticalSpacing="10dp"
            android:horizontalSpacing="40dp"
            android:numColumns="3"
            android:layout_gravity="center"
            android:background="#ff2f343a"
            android:layout_marginLeft="30dp"
            android:layout_marginRight="30dp"
            android:visibility="gone"/>
    </FrameLayout>

    <LinearLayout
        android:id="@+id/ll_relevant_operate"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:background="#272e34"
        android:visibility="gone">

        <TextView
            android:id="@+id/tv_dial"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/dial"
            android:textSize="14dp"
            android:textColor="#62696c"
            android:drawablePadding="10dp"
            android:drawableTop="@drawable/dial_pad"
            android:gravity="center"/>

        <TextView
            android:id="@+id/tv_tel_microphone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/microphone"
            android:textSize="14dp"
            android:textColor="#62696C"
            android:drawablePadding="10dp"
            android:drawableTop="@drawable/tel_microphone"
            android:gravity="center"
            android:layout_marginLeft="70dp"/>

        <TextView
            android:id="@+id/tv_tel_receiver"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/earpiece"
            android:textSize="14dp"
            android:textColor="#62696c"
            android:drawablePadding="10dp"
            android:drawableTop="@drawable/tel_receiver"
            android:gravity="center"
            android:layout_marginLeft="70dp"/>

        <TextView
            android:id="@+id/tv_on_speakerphone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/speaker"
            android:textSize="14dp"
            android:textColor="#62696C"
            android:drawablePadding="10dp"
            android:drawableTop="@drawable/on_speakerphone"
            android:gravity="center"
            android:layout_marginLeft="70dp"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#272c32"
        android:orientation="horizontal">

        <LinearLayout
            android:id="@+id/ll_no"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="25dp"
            android:layout_marginBottom="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal"
            android:visibility="gone">

            <ImageView
                android:id="@+id/iv_no"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/hang_up"/>
        </LinearLayout>

        <LinearLayout
            android:id="@+id/ll_ok"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="25dp"
            android:layout_marginBottom="25dp"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal"
            android:visibility="gone">

            <ImageView
                android:id="@+id/iv_ok"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/answer"/>
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

ok,到此为止,我们就讲完了。

完整的代码,可以移步我的github:

https://github.com/ZhangDeJin/UiDemo/tree/master/phone

猜你喜欢

转载自blog.csdn.net/zdj_Develop/article/details/120288057