Android 自定義來電顯示
自定義來電顯示主要完成兩個操作:
- 監聽來電廣播
- 使用WindowManager完成來電資訊展示
監聽來電廣播
1. 新增許可權
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
複製程式碼
2.定義廣播接收器
首先要在manifest中註冊靜態廣播
<receiver android:name=".PhoneReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
複製程式碼
自定義廣播接收器:
public class PhoneReceiver extends BroadcastReceiver {
private Context mContext;
@Override
public void onReceive(Context context, Intent intent) {
mContext = context;
//撥打電話
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
final String phoneNum = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i("PhoneReceiver", "phoneNum: " + phoneNum);
} else {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
final PhoneStateListener listener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
//電話等待接聽
case TelephonyManager.CALL_STATE_RINGING:
Log.i("PhoneReceiver", "CALL IN RINGING :" + incomingNumber);
PluginUtils.getSqLiteOpenHelperByName("evo_moblie");
WindowUtils.showPopupWindow(mContext.getApplicationContext(), incomingNumber);
break;
//電話接聽
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.i("PhoneReceiver", "CALL IN ACCEPT :" + incomingNumber);
WindowUtils.hidePopupWindow();
break;
//電話掛機
case TelephonyManager.CALL_STATE_IDLE:
Log.i("PhoneReceiver", "CALL IDLE");
WindowUtils.hidePopupWindow();
break;
}
}
};
}
複製程式碼
使用WindowManager完成來電資訊展示
自定義展示介面並設定按鍵監聽
public class CallIDView extends RelativeLayout {
//構造器
...
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|| event.getKeyCode() == KeyEvent.KEYCODE_SETTINGS) {
if (mOnKeyListener != null) {
mOnKeyListener.onKey(this, KeyEvent.KEYCODE_BACK, event);
return true;
}
}
return super.dispatchKeyEvent(event);
}
OnKeyListener mOnKeyListener = null;
@Override
public void setOnKeyListener(OnKeyListener l) {
mOnKeyListener = l;
super.setOnKeyListener(l);
}
}
複製程式碼
介面 xml:
<com.imagjs.plugin.jsplugin.callerid.CallIDView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:gravity="center">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textViewPhoneNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Large"
/>
<TextView
android:id="@+id/textViewPhoneName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="陳大大"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Large"
/>
</LinearLayout>
</com.imagjs.plugin.jsplugin.callerid.CallIDView>
複製程式碼
建立 WindowUtils 類,來管理 Window 的顯示和隱藏。
public class WindowUtils {
private static final String LOG_TAG = "WindowUtils";
private static View mView = null;
private static WindowManager mWindowManager = null;
private static Context mContext = null;
public static Boolean isShown = false;
/**
* 顯示彈出框
*
* @param context
*/
public static void showPopupWindow(final Context context, String phoneNum) {
if (isShown) {
Log.i(LOG_TAG, "return cause already shown");
return;
}
isShown = true;
Log.i(LOG_TAG, "showPopupWindow");
// 獲取應用的Context
mContext = context.getApplicationContext();
// 獲取WindowManager
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mView = setUpView(context, phoneNum);
//在建立View時註冊Receiver
IntentFilter homeFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mContext.getApplicationContext().registerReceiver(mHomeListenerReceiver, homeFilter);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
// 型別
// 設定window type
params.type = WindowManager.LayoutParams.TYPE_PHONE;
// 設定flag
// 如果設定了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,彈出的View收不到Back鍵的事件
params.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN|WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;;
// | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 不設定這個彈出框的透明遮罩顯示為黑色
params.format = PixelFormat.TRANSLUCENT;
// FLAG_NOT_TOUCH_MODAL不阻塞事件傳遞到後面的視窗
// 設定 FLAG_NOT_FOCUSABLE 懸浮視窗較小時,後面的應用圖示由不可長按變為可長按
// 不設定這個flag的話,home頁的劃屏會有問題
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
params.gravity = Gravity.CENTER;
mWindowManager.addView(mView, params);
Log.i(LOG_TAG, "add view");
}
/**
* 隱藏彈出框
*/
private static void hidePopupWindow() {
Log.i(LOG_TAG, "hide " + isShown + ", " + mView);
if (isShown && null != mView) {
Log.i(LOG_TAG, "hidePopupWindow");
mWindowManager.removeView(mView);
isShown = false;
mContext.getApplicationContext().unregisterReceiver(mHomeListenerReceiver);
}
}
private static CallIDView setUpView(final Context context, String phoneNum) {
CallIDView callIDView = (CallIDView) LayoutInflater.from(context).inflate(R.layout.callid_window_manager, null);
TextView textViewPhoneNum = callIDView.findViewById(R.id.textViewPhoneNum);
textViewPhoneNum.setText(phoneNum);
callIDView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int i, KeyEvent keyEvent) {
switch (keyEvent.getKeyCode()) {
case KeyEvent.KEYCODE_BACK:
hidePopupWindow();
return true;
default:
return false;
}
}
});
return callIDView;
}
//監聽home鍵
private static BroadcastReceiver mHomeListenerReceiver = new BroadcastReceiver() {
final String SYSTEM_DIALOG_REASON_KEY = "reason";
final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
&& reason != null && reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
hidePopupWindow();
}
}
};
複製程式碼
後續
接下來只要匹配上你的通訊錄資料就可以了。