来电监听
业务需求:来电监听手机号,查询归属地,悬浮展示归属地查询结果
悬浮在手机上(悬浮框不停留在手机卫士应用(界面)中,所以需要去开启一个服务,在服务中去管理toast代码逻辑)
1. 点击是否开启归属地显示的自定义组合控件SettingItemView
开启:开启服务,服务中管理吐司的显示,关闭:关闭服务,不需要显示吐司
2. 只有在来电的时候(响铃状态)显示吐司,挂断电话的时候,吐司移除掉
3. 电话状态的监听
服务开启的时候,需要去做监听
mTM = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
mPhoneStateListener = new MyPhoneStateListener();
mTM.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
关闭的时候电话状态就不需要监听
if(mTM!=null && mPhoneStateListener!=null){
mTM.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
}
4. 是否开启来电归属地显示的判断条件
服务正在运行==来电归属地开启
服务关闭==来电归属地关闭
activity代码
PS:彻底关掉状态监听要在服务的onDestroy()方法中设置PhoneStateListener.LISTEN_NONE
/**
* 是否显示电话号码归属地的方法
*/
private void initAddress() {
final SettingItemView siv_address = (SettingItemView) findViewById(R.id.siv_address);
//对服务是否开的状态做显示
boolean isRunning = ServiceUtil.isRunning(this, "com.itheima.mobilesafe74.service.AddressService");
siv_address.setCheck(isRunning);
//点击过程中,状态(是否开启电话号码归属地)的切换过程
siv_address.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//返回点击前的选中状态
boolean isCheck = siv_address.isCheck();
siv_address.setCheck(!isCheck);
if(!isCheck){
//开启服务,管理吐司
startService(new Intent(getApplicationContext(),AddressService.class));
}else{
//关闭服务,不需要显示吐司
stopService(new Intent(getApplicationContext(),AddressService.class));
}
}
});
}
服务代码
public class AddressService extends Service {
public static final String tag = "AddressService";
private TelephonyManager mTM;
private MyPhoneStateListener mPhoneStateListener;
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
private View mViewToast;
private WindowManager mWM;
private String mAddress;
private TextView tv_toast;
private Handler mHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
tv_toast.setText(mAddress);
};
};
private int[] mDrawableIds;
@Override
public void onCreate() {
//第一次开启服务以后,就需要去管理吐司的显示
//电话状态的监听(服务开启的时候,需要去做监听,关闭的时候电话状态就不需要监听)
//1,电话管理者对象
mTM = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
//2,监听电话状态
mPhoneStateListener = new MyPhoneStateListener();
mTM.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
//获取窗体对象
mWM = (WindowManager) getSystemService(WINDOW_SERVICE);
super.onCreate();
}
class MyPhoneStateListener extends PhoneStateListener{
//3,手动重写,电话状态发生改变会触发的方法
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
//空闲状态,没有任何活动(移除吐司)
Log.i(tag, "挂断电话,空闲了.......................");
//挂断电话的时候窗体需要移除吐司
if(mWM!=null && mViewToast!=null){
mWM.removeView(mViewToast);
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//摘机状态,至少有个电话活动。该活动或是拨打(dialing)或是通话
break;
case TelephonyManager.CALL_STATE_RINGING:
//响铃(展示吐司)
Log.i(tag, "响铃了.......................");
showToast(incomingNumber);
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
public void showToast(String incomingNumber) {
final WindowManager.LayoutParams params = mParams;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
// | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 默认能够被触摸
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = PixelFormat.TRANSLUCENT;
//在响铃的时候显示吐司,和电话类型一致
params.type = WindowManager.LayoutParams.TYPE_PHONE;
params.setTitle("Toast");
//指定吐司的所在位置(将吐司指定在左上角)
params.gravity = Gravity.LEFT+Gravity.TOP;
//吐司显示效果(吐司布局文件),xml-->view(吐司),将吐司挂在到windowManager窗体上
mViewToast = View.inflate(this, R.layout.toast_view, null);
tv_toast = (TextView) mViewToast.findViewById(R.id.tv_toast);
//从sp中获取色值文字的索引,匹配图片,用作展示
mDrawableIds = new int[]{
R.drawable.call_locate_white,
R.drawable.call_locate_orange,
R.drawable.call_locate_blue,
R.drawable.call_locate_gray,
R.drawable.call_locate_green};
int toastStyleIndex = SpUtil.getInt(getApplicationContext(), ConstantValue.TOAST_STYLE, 0);
tv_toast.setBackgroundResource(mDrawableIds[toastStyleIndex]);
//在窗体上挂在一个view(权限)
mWM.addView(mViewToast, params);
//获取到了来电号码以后,需要做来电号码查询
query(incomingNumber);
}
private void query(final String incomingNumber) {
new Thread(){
public void run() {
mAddress = AddressDao.getAddress(incomingNumber);
mHandler.sendEmptyMessage(0);
};
}.start();
}
@Override
public void onDestroy() {
//取消对电话状态的监听(开启服务的时候监听电话的对象)
if(mTM!=null && mPhoneStateListener!=null){
mTM.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
}
super.onDestroy();
}
}
自定义悬浮toast
查询源码,模拟源码来实现
代码
public void showToast(String incomingNumber) {
final WindowManager.LayoutParams params = mParams;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
// | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 默认能够被触摸
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = PixelFormat.TRANSLUCENT;
//在响铃的时候显示吐司,和电话类型一致
params.type = WindowManager.LayoutParams.TYPE_PHONE;
params.setTitle("Toast");
//指定吐司的所在位置(将吐司指定在左上角)
params.gravity = Gravity.LEFT+Gravity.TOP;
//吐司显示效果(吐司布局文件),xml-->view(吐司),将吐司挂在到windowManager窗体上
mViewToast = View.inflate(this, R.layout.toast_view, null);
tv_toast = (TextView) mViewToast.findViewById(R.id.tv_toast);
//从sp中获取色值文字的索引,匹配图片,用作展示
mDrawableIds = new int[]{
R.drawable.call_locate_white,
R.drawable.call_locate_orange,
R.drawable.call_locate_blue,
R.drawable.call_locate_gray,
R.drawable.call_locate_green};
int toastStyleIndex = SpUtil.getInt(getApplicationContext(), ConstantValue.TOAST_STYLE, 0);
tv_toast.setBackgroundResource(mDrawableIds[toastStyleIndex]);
//在窗体上挂在一个view(权限)
mWM.addView(mViewToast, params);
//获取到了来电号码以后,需要做来电号码查询
query(incomingNumber);
}
private void query(final String incomingNumber) {
new Thread(){
public void run() {
mAddress = AddressDao.getAddress(incomingNumber);
mHandler.sendEmptyMessage(0);
};
}.start();
}
toast样式单选对话框
效果图
代码
private void initToastStyle() {
scv_toast_style = (SettingClickView) findViewById(R.id.scv_toast_style);
//话述(产品)
scv_toast_style.setTitle("设置归属地显示风格");
//1,创建描述文字所在的string类型数组
mToastStyleDes = new String[]{"透明","橙色","蓝色","灰色","绿色"};
//2,SP获取吐司显示样式的索引值(int),用于获取描述文字
mToastStyle = SpUtil.getInt(this, ConstantValue.TOAST_STYLE, 0);
//3,通过索引,获取字符串数组中的文字,显示给描述内容控件
scv_toast_style.setDes(mToastStyleDes[mToastStyle]);
//4,监听点击事件,弹出对话框
scv_toast_style.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//5,显示吐司样式的对话框
showToastStyleDialog();
}
});
}
/**
* 创建选中显示样式的对话框
*/
protected void showToastStyleDialog() {
Builder builder = new AlertDialog.Builder(this);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("请选择归属地样式");
//选择单个条目事件监听
/*
* 1:string类型的数组描述颜色文字数组
* 2:弹出对画框的时候的选中条目索引值
* 3:点击某一个条目后触发的点击事件
* */
builder.setSingleChoiceItems(mToastStyleDes, mToastStyle, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {//which选中的索引值
//(1,记录选中的索引值,2,关闭对话框,3,显示选中色值文字)
SpUtil.putInt(getApplicationContext(), ConstantValue.TOAST_STYLE, which);
dialog.dismiss();
scv_toast_style.setDes(mToastStyleDes[which]);
}
});
//消极按钮
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
}
窗体触摸拖拽监听
效果图
实现思路:
设置页面点击跳转到一个透明主题,背景色被浅灰色的activity
监听拖拽的图片记录的位置
注册透明主题的activity
<activity android:name="com.itheima.mobilesafe74.activity.ToastLocationActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#accc">
<!-- imageView在相对布局中,所以其所在位置的规则需要由相对布局提供 -->
<ImageView
android:id="@+id/iv_drag"
android:background="@drawable/drag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/bt_top"
android:layout_width="match_parent"
android:text="按中提示框拖拽到任意位置"
android:gravity="center"
android:visibility="invisible"
android:background="@drawable/call_locate_blue"
android:layout_height="wrap_content"/>
<Button
android:layout_alignParentBottom="true"
android:id="@+id/bt_bottom"
android:layout_width="match_parent"
android:text="按中提示框拖拽到任意位置"
android:gravity="center"
android:visibility="visible"
android:background="@drawable/call_locate_blue"
android:layout_height="wrap_content"/>
</RelativeLayout>
移动过程图解
左上右下坐标获取
getRowX和getX差异
下边缘显示范围
代码
public class ToastLocationActivity extends Activity {
private ImageView iv_drag;
private Button bt_top,bt_bottom;
private WindowManager mWM;
private int mScreenHeight;
private int mScreenWidth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_toast_location);
initUI();
}
private void initUI() {
//可拖拽双击居中的图片控件
iv_drag = (ImageView) findViewById(R.id.iv_drag);
bt_top = (Button) findViewById(R.id.bt_top);
bt_bottom = (Button) findViewById(R.id.bt_bottom);
mWM = (WindowManager) getSystemService(WINDOW_SERVICE);
mScreenHeight = mWM.getDefaultDisplay().getHeight();
mScreenWidth = mWM.getDefaultDisplay().getWidth();
int locationX = SpUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_X, 0);
int locationY = SpUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_Y, 0);
//左上角坐标作用在iv_drag上
//iv_drag在相对布局中,所以其所在位置的规则需要由相对布局提供
//指定宽高都为WRAP_CONTENT
LayoutParams layoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
//将左上角的坐标作用在iv_drag对应规则参数上
layoutParams.leftMargin = locationX;
layoutParams.topMargin = locationY;
//将以上规则作用在iv_drag上
iv_drag.setLayoutParams(layoutParams);
if(locationY>mScreenHeight/2){
bt_bottom.setVisibility(View.INVISIBLE);
bt_top.setVisibility(View.VISIBLE);
}else{
bt_bottom.setVisibility(View.VISIBLE);
bt_top.setVisibility(View.INVISIBLE);
}
//监听某一个控件的拖拽过程(按下(1),移动(多次),抬起(1))
iv_drag.setOnTouchListener(new OnTouchListener() {
private int startX;
private int startY;
//对不同的事件做不同的逻辑处理
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getRawX();
startY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getRawX();
int moveY = (int) event.getRawY();
int disX = moveX-startX;
int disY = moveY-startY;
//1,当前控件所在屏幕的(左,上)角的位置
int left = iv_drag.getLeft()+disX;//左侧坐标
int top = iv_drag.getTop()+disY;//顶端坐标
int right = iv_drag.getRight()+disX;//右侧坐标
int bottom = iv_drag.getBottom()+disY;//底部坐标
//容错处理(iv_drag不能拖拽出手机屏幕)
//左边缘不能超出屏幕
if(left<0){
return true;
}
//右边边缘不能超出屏幕
if(right>mScreenWidth){
return true;
}
//上边缘不能超出屏幕可现实区域
if(top<0){
return true;
}
//下边缘(屏幕的高度-22 = 底边缘显示最大值)
if(bottom>mScreenHeight - 22){
return true;
}
if(top>mScreenHeight/2){
bt_bottom.setVisibility(View.INVISIBLE);
bt_top.setVisibility(View.VISIBLE);
}else{
bt_bottom.setVisibility(View.VISIBLE);
bt_top.setVisibility(View.INVISIBLE);
}
//2,告知移动的控件,按计算出来的坐标去做展示
iv_drag.layout(left, top, right, bottom);
//3,重置一次其实坐标
startX = (int) event.getRawX();
startY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
//4,存储移动到的位置
SpUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_X, iv_drag.getLeft());
SpUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_Y, iv_drag.getTop());
break;
}
//在当前的情况下返回false不响应事件,返回true才会响应事件
return true;
}
});
}
}
双击多击事件
多击事件参考谷歌源码实现
原理图
代码
public class MainActivity extends Activity {
private long startTime = 0;
private long[] mHits = new long[5];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt_click = (Button) findViewById(R.id.bt_click);
Button bt_many_click = (Button) findViewById(R.id.bt_many_click);
bt_click.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//两次点击在一定的时间间隔内,才是双击
if(startTime!=0){
long endTime = System.currentTimeMillis();
if(endTime-startTime<500){
Toast.makeText(getApplicationContext(), "是男人", 0).show();
}
}
startTime = System.currentTimeMillis();
}
});
bt_many_click.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//了解
//1,原数组(要被拷贝的数组)
//2,原数组的拷贝起始位置索引值
//3,目标数组(原数组的数据---拷贝-->目标数组)
//4,目标数组接受值的起始索引位置
//5,拷贝的长度
System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
mHits[mHits.length-1] = SystemClock.uptimeMillis();
if(mHits[mHits.length-1]-mHits[0]<500){
//响应了一个三击事件
Toast.makeText(getApplicationContext(), "超级赛亚人!!!!", 0).show();
}
}
});
/* System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
mHits[mHits.length-1] = SystemClock.uptimeMillis();
if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName("android",
com.android.internal.app.PlatLogoActivity.class.getName());
try {
startActivity(intent);
} catch (Exception e) {
Log.e(LOG_TAG, "Unable to start activity " + intent.toString());
}
}*/
}
}
将双击事件添加到设置中心的设置中
双击居中图解
public class ToastLocationActivity extends Activity {
private ImageView iv_drag;
private Button bt_top,bt_bottom;
private WindowManager mWM;
private int mScreenHeight;
private int mScreenWidth;
private long[] mHits = new long[2];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_toast_location);
initUI();
}
private void initUI() {
//可拖拽双击居中的图片控件
iv_drag = (ImageView) findViewById(R.id.iv_drag);
bt_top = (Button) findViewById(R.id.bt_top);
bt_bottom = (Button) findViewById(R.id.bt_bottom);
mWM = (WindowManager) getSystemService(WINDOW_SERVICE);
mScreenHeight = mWM.getDefaultDisplay().getHeight();
mScreenWidth = mWM.getDefaultDisplay().getWidth();
int locationX = SpUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_X, 0);
int locationY = SpUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_Y, 0);
//左上角坐标作用在iv_drag上
//iv_drag在相对布局中,所以其所在位置的规则需要由相对布局提供
//指定宽高都为WRAP_CONTENT
LayoutParams layoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
//将左上角的坐标作用在iv_drag对应规则参数上
layoutParams.leftMargin = locationX;
layoutParams.topMargin = locationY;
//将以上规则作用在iv_drag上
iv_drag.setLayoutParams(layoutParams);
if(locationY>mScreenHeight/2){
bt_bottom.setVisibility(View.INVISIBLE);
bt_top.setVisibility(View.VISIBLE);
}else{
bt_bottom.setVisibility(View.VISIBLE);
bt_top.setVisibility(View.INVISIBLE);
}
iv_drag.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
mHits[mHits.length-1] = SystemClock.uptimeMillis();
if(mHits[mHits.length-1]-mHits[0]<500){
//满足双击事件后,调用代码
int left = mScreenWidth/2 - iv_drag.getWidth()/2;
int top = mScreenHeight/2 - iv_drag.getHeight()/2;
int right = mScreenWidth/2+iv_drag.getWidth()/2;
int bottom = mScreenHeight/2+iv_drag.getHeight()/2;
//控件按以上规则显示
iv_drag.layout(left, top, right, bottom);
//存储最终位置
SpUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_X, iv_drag.getLeft());
SpUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_Y, iv_drag.getTop());
}
}
});
//监听某一个控件的拖拽过程(按下(1),移动(多次),抬起(1))
iv_drag.setOnTouchListener(new OnTouchListener() {
private int startX;
private int startY;
//对不同的事件做不同的逻辑处理
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getRawX();
startY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getRawX();
int moveY = (int) event.getRawY();
int disX = moveX-startX;
int disY = moveY-startY;
//1,当前控件所在屏幕的(左,上)角的位置
int left = iv_drag.getLeft()+disX;//左侧坐标
int top = iv_drag.getTop()+disY;//顶端坐标
int right = iv_drag.getRight()+disX;//右侧坐标
int bottom = iv_drag.getBottom()+disY;//底部坐标
//容错处理(iv_drag不能拖拽出手机屏幕)
//左边缘不能超出屏幕
if(left<0){
return true;
}
//右边边缘不能超出屏幕
if(right>mScreenWidth){
return true;
}
//上边缘不能超出屏幕可现实区域
if(top<0){
return true;
}
//下边缘(屏幕的高度-22 = 底边缘显示最大值)
if(bottom>mScreenHeight - 22){
return true;
}
if(top>mScreenHeight/2){
bt_bottom.setVisibility(View.INVISIBLE);
bt_top.setVisibility(View.VISIBLE);
}else{
bt_bottom.setVisibility(View.VISIBLE);
bt_top.setVisibility(View.INVISIBLE);
}
//2,告知移动的控件,按计算出来的坐标去做展示
iv_drag.layout(left, top, right, bottom);
//3,重置一次其实坐标
startX = (int) event.getRawX();
startY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
//4,存储移动到的位置
SpUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_X, iv_drag.getLeft());
SpUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_Y, iv_drag.getTop());
break;
}
//在当前的情况下返回false不响应事件,返回true才会响应事件
//既要响应点击事件,又要响应拖拽过程,则此返回值结果需要修改为false
return false;
}
});
}
}
自定义toast获取设置中心中设置的位置及添加移动事件
public class AddressService extends Service {
public static final String tag = "AddressService";
private TelephonyManager mTM;
private MyPhoneStateListener mPhoneStateListener;
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
private View mViewToast;
private WindowManager mWM;
private String mAddress;
private TextView tv_toast;
private Handler mHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
tv_toast.setText(mAddress);
};
};
private int[] mDrawableIds;
private int mScreenHeight;
private int mScreenWidth;
@Override
public void onCreate() {
//第一次开启服务以后,就需要去管理吐司的显示
//电话状态的监听(服务开启的时候,需要去做监听,关闭的时候电话状态就不需要监听)
//1,电话管理者对象
mTM = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
//2,监听电话状态
mPhoneStateListener = new MyPhoneStateListener();
mTM.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
//获取窗体对象
mWM = (WindowManager) getSystemService(WINDOW_SERVICE);
mScreenHeight = mWM.getDefaultDisplay().getHeight();
mScreenWidth = mWM.getDefaultDisplay().getWidth();
super.onCreate();
}
class MyPhoneStateListener extends PhoneStateListener{
//3,手动重写,电话状态发生改变会触发的方法
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
//空闲状态,没有任何活动(移除吐司)
Log.i(tag, "挂断电话,空闲了.......................");
//挂断电话的时候窗体需要移除吐司
if(mWM!=null && mViewToast!=null){
mWM.removeView(mViewToast);
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//摘机状态,至少有个电话活动。该活动或是拨打(dialing)或是通话
break;
case TelephonyManager.CALL_STATE_RINGING:
//响铃(展示吐司)
Log.i(tag, "响铃了.......................");
showToast(incomingNumber);
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
public void showToast(String incomingNumber) {
final WindowManager.LayoutParams params = mParams;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
// | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 默认能够被触摸
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = PixelFormat.TRANSLUCENT;
//在响铃的时候显示吐司,和电话类型一致
params.type = WindowManager.LayoutParams.TYPE_PHONE;
params.setTitle("Toast");
//指定吐司的所在位置(将吐司指定在左上角)
params.gravity = Gravity.LEFT+Gravity.TOP;
//吐司显示效果(吐司布局文件),xml-->view(吐司),将吐司挂在到windowManager窗体上
mViewToast = View.inflate(this, R.layout.toast_view, null);
tv_toast = (TextView) mViewToast.findViewById(R.id.tv_toast);
mViewToast.setOnTouchListener(new OnTouchListener() {
private int startX;
private int startY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getRawX();
startY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getRawX();
int moveY = (int) event.getRawY();
int disX = moveX-startX;
int disY = moveY-startY;
params.x = params.x+disX;
params.y = params.y+disY;
//容错处理
if(params.x<0){
params.x = 0;
}
if(params.y<0){
params.y=0;
}
if(params.x>mScreenWidth-mViewToast.getWidth()){
params.x = mScreenWidth-mViewToast.getWidth();
}
if(params.y>mScreenHeight-mViewToast.getHeight()-22){
params.y = mScreenHeight-mViewToast.getHeight()-22;
}
//告知窗体吐司需要按照手势的移动,去做位置的更新
mWM.updateViewLayout(mViewToast, params);
startX = (int) event.getRawX();
startY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
SpUtil.putInt(getApplicationContext(),ConstantValue.LOCATION_X, params.x);
SpUtil.putInt(getApplicationContext(),ConstantValue.LOCATION_Y, params.y);
break;
}
//true 响应拖拽触发的事件
return true;
}
});
//读取sp中存储吐司位置的x,y坐标值
// params.x为吐司左上角的x的坐标
params.x = SpUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_X, 0);
// params.y为吐司左上角的y的坐标
params.y = SpUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_Y, 0);
//从sp中获取色值文字的索引,匹配图片,用作展示
mDrawableIds = new int[]{
R.drawable.call_locate_white,
R.drawable.call_locate_orange,
R.drawable.call_locate_blue,
R.drawable.call_locate_gray,
R.drawable.call_locate_green};
int toastStyleIndex = SpUtil.getInt(getApplicationContext(), ConstantValue.TOAST_STYLE, 0);
tv_toast.setBackgroundResource(mDrawableIds[toastStyleIndex]);
//在窗体上挂在一个view(权限)
mWM.addView(mViewToast, params);
//获取到了来电号码以后,需要做来电号码查询
query(incomingNumber);
}
private void query(final String incomingNumber) {
new Thread(){
public void run() {
mAddress = AddressDao.getAddress(incomingNumber);
mHandler.sendEmptyMessage(0);
};
}.start();
}
@Override
public void onDestroy() {
//取消对电话状态的监听(开启服务的时候监听电话的对象)
if(mTM!=null && mPhoneStateListener!=null){
mTM.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
}
super.onDestroy();
}
}