1. 程式人生 > >android 上層電話狀態的監聽

android 上層電話狀態的監聽

1,概述

做開發時,有時完全不利用Dialer.apk來開發撥號等功能,如何撥打/接聽/結束通話電話呢?電話來了又怎麼知道呢?現在分為2個部分一一到來。首先是撥打/接聽/結束通話等電話操作,然後監聽電話的狀態,並進行相應的處理,本文基於Android 5.1.

 2, 電話操作

2.1 撥號

撥號最簡單了,直接發個廣播就可以了

private String callnumber = “10086”; // 比如 給移動客服打電話
   Uri uri = getCallUri(callnumber); // 將所撥號碼進行格式化
   Intent intentd = new Intent();
   intentd.setAction(Intent.ACTION_CALL);
	 intentd.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
	 intentd.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
	 intentd.setData(uri);
	 startActivity(intentd);

public static Uri getCallUri(String number) {
        if (number != null && (number.contains("@") || number.contains("%40"))) {
             return Uri.fromParts("sip", number, null);
        }
        return Uri.fromParts("tel", number, null);
     }


2.2 結束通話

利用反射機制呼叫telephonyManager的endCall方法進行結束通話。

private Object telephonyObject = null;
TelephonyManager telephonyManager = 
        (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		
		Class telManager = telephonyManager.getClass();
		Method getITelephony = null;
		try {
			try {
				getITelephony = telManager
						.getDeclaredMethod("getITelephony");
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			getITelephony.setAccessible(true);
			telephonyObject = getITelephony.invoke(telephonyManager);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		try {
			if (null != telephonyObject) {
				Class telephonyClass = telephonyObject.getClass();
                 Method endCallMethod = telephonyClass.getMethod("endCall");
				endCallMethod.setAccessible(true); 
				endCallMethod.invoke(telephonyObject);
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}


2.3 接聽

實現接聽有多種方法,和上小節的結束通話操作一樣,可以直接利用反射機制來進行接聽;還有一種方法利用按鍵事件這個介面,通過傳送廣播的形式,實現接聽。

try {
			Runtime.getRuntime().exec("input keyevent " + Integer
					.toString(KeyEvent.KEYCODE_HEADSETHOOK));
		} catch (IOException e) {
			String enforcedPerm = "android.permission.CALL_PRIVILEGED";
			Intent btnDown = new Intent(Intent.ACTION_MEDIA_BUTTON)
					.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(
							KeyEvent.ACTION_DOWN,
							KeyEvent.KEYCODE_HEADSETHOOK));
			Intent btnUp = new Intent(Intent.ACTION_MEDIA_BUTTON)
					.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(
							KeyEvent.ACTION_UP,
							KeyEvent.KEYCODE_HEADSETHOOK));

			sendOrderedBroadcast(btnDown, enforcedPerm);
			sendOrderedBroadcast(btnUp, enforcedPerm);
		}


3, 電話狀態的監聽

import java.lang.reflect.Method;

import android.app.Activity;
import android.app.Dialog;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.TextView;

public class PhoneBroadcastReceiver extends BroadcastReceiver   {

	private static final String TAG = "message";
    private static boolean mIncomingFlag = false;
    private static String mIncomingNumber = null;
    private static boolean callover = false;
    
    @Override
    public void onReceive(Context context, Intent intent) {
       if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {// 如果是撥打電話
            mIncomingFlag = false;
            String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
        } else {
            TelephonyManager tManager = (TelephonyManager) 
                  context.getSystemService(Service.TELEPHONY_SERVICE);
            switch (tManager.getCallState()) {
            case TelephonyManager.CALL_STATE_RINGING:  //來電狀態
                mIncomingNumber = intent.getStringExtra("incoming_number");
                •••                }
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK: //摘機狀態(接聽)
            	 mIncomingNumber = intent.getStringExtra("incoming_number");
                   callover = true;
                  •••
                break;
            case TelephonyManager.CALL_STATE_IDLE:// 空閒狀態,沒有任何活動。(結束通話)
            	android.util.Log.d("fangc", " mIncomingNumber " + "guaduan");
                if (mIncomingFlag||callover) {
                  mIncomingFlag = false;
                	callover = false;
                  •••                
                }
                break;
            }
        }
        
    }
	
}


在這四個狀態中,可以分別新增一些boolean值來確定是撥號/來電還是結束通話,接聽等狀態,然後在裡面分別進行不同的處理。

4, 結尾

最後不要忘記了在AdnroidManifest.xml 檔案中新增相關許可權

    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>


PhoneBroadcastReceiver類一定要註冊靜態廣播,而不是動態廣播。

<receiver android:name=".PhoneBroadcastReceiver">
            <intent-filter android:priority="1000">
                <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
                <action android:name="android.intent.action.PHONE_STATE"/>   
            </intent-filter>
        </receiver>