TelephonyManager(전화관리자)


이 섹션 소개:

이 장은 Android 기본 입문 튜토리얼의 마지막 장입니다. 주로 몇 가지 지식 사항과 일부 누락 사항을 설명합니다. 지식 포인트를 보완하기 위해 이러한 분산된 지식 포인트에는 이 섹션의 전화 관리자 및 SMS 관리자와 같은 다양한 시스템 서비스의 사용이 포함됩니다. 바이브레이터, 알람시계, 배경화면 등, 센서 등! 그것은 엉망이고 모든 것입니다! 좋아요, 이번 섹션에서 우리가 배울 내용은 무엇인가요? 이름에서 알 수 있듯이 TelephonyManager입니다. 휴대폰 통화 상태를 관리하고 전화 정보(기기 정보, SIM 카드 정보 및 네트워크 정보), 전화 상태(통화 상태 서비스 상태, 신호 강도 상태 등)를 듣고 전화 다이얼러에 전화하여 전화를 걸 수 있습니다! 더 이상 고민하지 말고 이 섹션을 시작하겠습니다~

공식 API:TelephonyManager


1 TelephonyManager

TelephonyManager tManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);


2 . 사용 예


1) 다이얼러를 호출하여 전화번호

Uri uri=Uri.parse("tel:"+电话号码);    
Intent intent=new Intent(Intent.ACTION_DIAL,uri);    
startActivity(intent);

2) Sim 카드 정보 및 네트워크 정보 가져오기

렌더링 실행:

1.png

구현 코드:

레이아웃 파일:activity_main .xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_phone1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_phone2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_phone3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_phone4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_phone5"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_phone6"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_phone7"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_phone8"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/tv_phone9"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp" /></LinearLayout>

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private TextView tv_phone1;
    private TextView tv_phone2;
    private TextView tv_phone3;
    private TextView tv_phone4;
    private TextView tv_phone5;
    private TextView tv_phone6;
    private TextView tv_phone7;
    private TextView tv_phone8;
    private TextView tv_phone9;
    private TelephonyManager tManager;
    private String[] phoneType = {"未知","2G","3G","4G"};
    private String[] simState = {"状态未知","无SIM卡","被PIN加锁","被PUK加锁",
            "被NetWork PIN加锁","已准备好"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //①获得系统提供的TelphonyManager对象的实例
        tManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        bindViews();
    }

    private void bindViews() {
        tv_phone1 = (TextView) findViewById(R.id.tv_phone1);
        tv_phone2 = (TextView) findViewById(R.id.tv_phone2);
        tv_phone3 = (TextView) findViewById(R.id.tv_phone3);
        tv_phone4 = (TextView) findViewById(R.id.tv_phone4);
        tv_phone5 = (TextView) findViewById(R.id.tv_phone5);
        tv_phone6 = (TextView) findViewById(R.id.tv_phone6);
        tv_phone7 = (TextView) findViewById(R.id.tv_phone7);
        tv_phone8 = (TextView) findViewById(R.id.tv_phone8);
        tv_phone9 = (TextView) findViewById(R.id.tv_phone9);

        tv_phone1.setText("设备编号:" + tManager.getDeviceId());
        tv_phone2.setText("软件版本:" + (tManager.getDeviceSoftwareVersion()!= null?
                tManager.getDeviceSoftwareVersion():"未知"));
        tv_phone3.setText("运营商代号:" + tManager.getNetworkOperator());
        tv_phone4.setText("运营商名称:" + tManager.getNetworkOperatorName());
        tv_phone5.setText("网络类型:" + phoneType[tManager.getPhoneType()]);
        tv_phone6.setText("设备当前位置:" + (tManager.getCellLocation() != null ? tManager
                .getCellLocation().toString() : "未知位置"));
        tv_phone7.setText("SIM卡的国别:" + tManager.getSimCountryIso());
        tv_phone8.setText("SIM卡序列号:" + tManager.getSimSerialNumber());
        tv_phone9.setText("SIM卡状态:" + simState[tManager.getSimState()]);
    }
}

그런데, AndroidManifest.xml에 권한을 추가하는 것을 잊지 마세요!

<!-- 添加访问手机位置的权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- 添加访问手机状态的权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

그런데 일반 2G, 3G, 4G 대신 네트워크 표준을 원할 수도 있습니다. 실제로 TelephonyManager 클래스의 소스 코드로 이동할 수 있습니다.

2.png

다양한 네트워크 기반을 판단할 수 있습니다. 이 networkType 표준의 값(예: networkType == 1인 경우) 그거 GPRS 형식이에요~ 그리고 이 networkType의 값은 getNetworkType() 메소드를 통해 얻을 수 있어요! 좋아요, 위와 같이 배열을 나열한 다음 사용할 수 있습니다. 다른 첨자는 다른 값을 표시합니다! 그런데 문자열 배열에는 Sim 카드 상태와 값도 있습니다. 소스 코드에서 볼 수 있습니다.

3.png

다른 것들은 직접 탐색할 수 있습니다~

4.png3) 신호 강도를 확인하세요. 휴대폰

네트워크 신호 강도의 단위는 dBm(밀리와트 데시벨)이며 일반적으로 음수로 표시됩니다. 일반적인 휴대폰 신호 범위는 -110dBm입니다. (나쁨)과 -50dBm(양호) 사이에서 -50dBm보다 작으면 내 n5 디스플레이와 같이 기지국 근처에 서 있다는 의미입니다. 신호 강도는 -51dBm이고 때로는 -59dBm입니다. Nansoft 빌딩이 옆에 있고 위에 기지국이 있기 때문입니다...

또한 2G, 3G, 4G에서 신호 강도를 얻는 방법은 PhoneStateListener의 onSignalStrengthsChanged()를 재정의하는 것입니다. 방법, 이 이벤트는 신호 강도가 변경되면 트리거됩니다. 이 이벤트에서 신호 강도를 얻을 수 있습니다.

신호 강도를 얻기 위한 휴대폰의 코드 예:

dBm =-113+2*asu이것은 고정 공식 asu(독립 신호 단위)

작업 렌더링:

5.png

구현 코드 :

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private TextView tv_rssi;
    private MyPhoneStateListener mpsListener;
    private TelephonyManager tManager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tManager = ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE));
        tv_rssi = (TextView) findViewById(R.id.tv_rssi);
        mpsListener  = new MyPhoneStateListener();
        tManager.listen(mpsListener,290);
    }

    private class MyPhoneStateListener extends PhoneStateListener {
        private int asu = 0,lastSignal = 0;
        @Override
        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
            asu = signalStrength.getGsmSignalStrength();
            lastSignal = -113 + 2 * asu;
            tv_rssi.setText("当前手机的信号强度:" + lastSignal + " dBm" );
            super.onSignalStrengthsChanged(signalStrength);
        }
    }
}

게다가 작성자 카드가 모두 모바일 카드라서 차이나유니콤, 텔레콤은 모르겠지만 소스에서 이런 API가 여럿 보이더군요. code:

  • getEvdoDbm() : Telecom 3G
  • getCdmaDbm(): China Unicom 3G
  • getLteDbm(): 4G

이들은 dBm을 직접 얻을 수 있어야 합니다. 신호 강도를 높일 수 있습니다. 조건이 있으면 한번 해보세요~

그리고 권한 추가도 잊지 마세요!

<!-- 添加访问手机状态的权限 -->
 <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

4) 휴대폰의 모든 수신 통화를 모니터링하세요

모니터링된 통화 기록 결과를 다양한 방법으로 얻을 수 있습니다. 여기서 사용되는 것은 통화 기록을 파일에 쓰는 것입니다. 그리고 문자 메시지 형태로 보내거나, 특정 플랫폼에 업로드할 수도 있습니다. 물론, 통신 기록이 많지 않은 경우에는 문자 메시지를 사용할 수도 있습니다. 더 있으면 다른 사람들도 쉽게 찾을 수 있을 거예요! 또한 여기서는 Service 대신 Activity를 사용하는데, 이는 이 Activity를 여는 것을 의미하며, 그래야만 모니터링할 수 있습니다. 일반적으로 우리의 요구사항은 시간 제약으로 인해 백그라운드에서 비밀리에 실행되어야 합니다. 직접 수정하여 부팅과 함께 서비스를 시작할 수 있습니다!

코드 분석 :

실제로는 TelephonyManager의 통화 상태 리스너 PhoneStateListener를 다시 작성한 다음 TelephonyManager를 호출하는 것입니다. .listen() 메소드 호출이 들어올 때 모니터링하고, 프로그램은 발신자 번호를 파일에 기록합니다!

구현 코드:

MainActivity.java:

public class MainActivity extends Activity  
{  
    TelephonyManager tManager;  
  
    @Override  
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        // 取得TelephonyManager对象  
        tManager = (TelephonyManager)   
            getSystemService(Context.TELEPHONY_SERVICE);  
        // 创建一个通话状态监听器  
        PhoneStateListener listener = new PhoneStateListener()  
        {  
            @Override  
            public void onCallStateChanged(int state, String number)  
            {  
                switch (state)  
                {  
                // 无任何状态  
                    case TelephonyManager.CALL_STATE_IDLE:  
                        break;  
                    case TelephonyManager.CALL_STATE_OFFHOOK:  
                        break;  
                    // 来电铃响时  
                    case TelephonyManager.CALL_STATE_RINGING:  
                        OutputStream os = null;  
                        try  
                        {  
                            os = openFileOutput("phoneList", MODE_APPEND);  
                        }  
                        catch (FileNotFoundException e)  
                        {  
                            e.printStackTrace();  
                        }  
                        PrintStream ps = new PrintStream(os);  
                        // 将来电号码记录到文件中  
                        ps.println(new Date() + " 来电:" + number);  
                        ps.close();  
                        break;  
                    default:  
                        break;  
                }  
                super.onCallStateChanged(state, number);  
            }  
        };  
        // 监听电话通话状态的改变  
        tManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);  
    }  
}

실행 결과:

주의! 다른 전화를 사용하여 전화를 걸면 DDMS를 열 수 있습니다! 파일 탐색기 응용 프로그램 패키지 이름에 해당하는 파일 디렉터리에서 PhoneList 파일을 볼 수 있습니다. 파일의 대략적인 내용은 다음과 같습니다.

THR Oct 30 12:05:48 GMT Call : 137xxxxxxx

그런데 권한도 잊지 마세요!

<!-- 授予该应用读取通话状态的权限 -->  
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

5) 블랙리스트 전화는 자동으로 끊어집니다

소위 블랙리스트는 일부 전화번호를 컬렉션에 추가하고, 전화가 이러한 전화를 받으면 바로 끊어지는 것입니다! 하지만 안드로이드에서는 전화를 끊을 수 있는 API를 제공하지 않기 때문에 서비스 내에서 AIDL을 통해 API를 호출해야 합니다. 전화 끊기 달성!

첫 번째 단계는 Android 소스 코드의 다음 두 파일을 src 아래의 해당 위치에 복사하는 것입니다. ITelephony.aidl com.android.internal.telephony 패키지 아래

NeighboringCellInfo.aidl

android.telephony 패키지 아래

해당 패키지를 생성하려면 위 패키지 아래에aidl 파일을 넣으면 됩니다 !!! 그런 다음 ITelephony의 endCall에 전화하기만 하면 전화를 끊을 수 있습니다.

여기서는 차단된 전화가 오면 번호를 입력하고 차단 버튼을 클릭하면 됩니다. 코드는 비교적 간단합니다. 사용된 시뮬레이터는 Genymotion이므로 설명하지 않겠습니다. 프로그램 실행 후 스크린샷!

MainActivity.java:

public class MainActivity extends Activity {  
  
    private TelephonyManager tManager;  
    private PhoneStateListener pListener;  
    private String number;  
    private EditText locknum;  
    private Button btnlock;  
      
    public class PhonecallListener extends PhoneStateListener  
    {  
        @Override  
        public void onCallStateChanged(int state, String incomingNumber) {  
            switch(state)  
            {  
            case TelephonyManager.CALL_STATE_IDLE:break;  
            case TelephonyManager.CALL_STATE_OFFHOOK:break;  
            //当有电话拨入时  
            case TelephonyManager.CALL_STATE_RINGING:  
                if(isBlock(incomingNumber))  
                {  
                    try  
                    {  
                        Method method = Class.forName("android.os.ServiceManager")  
                                .getMethod("getService", String.class);  
                        // 获取远程TELEPHONY_SERVICE的IBinder对象的代理  
                        IBinder binder = (IBinder) method.invoke(null,  
                            new Object[] { TELEPHONY_SERVICE });  
                        // 将IBinder对象的代理转换为ITelephony对象  
                        ITelephony telephony = ITelephony.Stub.asInterface(binder);  
                        // 挂断电话  
                        telephony.endCall();  
                    }catch(Exception e){e.printStackTrace();}  
                }  
                break;  
            }  
            super.onCallStateChanged(state, incomingNumber);  
        }  
    }  
      
      
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
          
        locknum = (EditText) findViewById(R.id.locknum);  
        btnlock = (Button) findViewById(R.id.btnlock);  
          
        //获取系统的TelephonyManager管理器  
        tManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);  
        pListener = new PhoneStateListener();  
        tManager.listen(pListener, PhoneStateListener.LISTEN_CALL_STATE);  
          
        btnlock.setOnClickListener(new OnClickListener() {  
              
            @Override  
            public void onClick(View v) {  
                number = locknum.getText().toString();                
            }  
        });  
          
    }  
      
    public boolean isBlock(String phone)  
    {  
        if(phone.equals(number))return true;  
        return false;  
    }  
}

Permissions,Permissions,Permissions:

<!-- 授予该应用控制通话的权限 -->  
<uses-permission android:name="android.permission.CALL_PHONE" />    
<!-- 授予该应用读取通话状态的权限 -->  
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

또한 중국어 버전의 관련 속성 및 메소드를 볼 수 있습니다:

Android 휴대폰 정보 관련 API


3. 이 섹션에서 샘플 코드를 다운로드하세요

TelephonyManagerDemo.zip

TelephonyManagerDemo2.zip

Blacklist Interception Demo.zip


이 섹션 요약:

알았어, 이거 섹션은 TelephonyManager(phone 관리자에 대한 학습의 끝입니다)에 관한 것입니다. 다루어야 합니다. 대부분의 개발 요구 사항이 충족되었습니다. 부족한 점이 있으면 언제든지 말씀해 주세요~

감사합니다~

6.gif