[mobilesafe] 08_以Toast吐丝的方式显示来电归属地

Android 4.0

以Toast吐丝的方式显示来电归属地

1、来电时,显示号码归属地,但不可能在其他程序中修改电话拨号程序的界面
2、Toast很特殊的组件,它是显示在手机的(操作系统的)界面上,也就是所有UI的界面上方
需要开启一个Service来监听来电的状态
TelephonyManager    PhoneStateListener  
1、注册一个监听电话的状态的服务
2、在设置中提供是否开启来电提醒的功能
3、监听电话状态的服务,是否开启,不能用SharedPreferences保存,因为,当开启为true的时候,应用程序突然挂掉或者没电了,在下次启动的时候,service不在了(因为没有点击,服务启动不了),所以不能存,要检测服务的状态。然后根据检测出来的服务的状态来勾选或者不勾选这个。
1、注册一个监听电话的状态的服务ShowAddressService.java
package cn.zengfansheng.mobilesafe.service;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;
import cn.zengfansheng.mobilesafe.dao.AddressDao;
/**
 * 2、显示来电归属地Service
 * @author hacket
 */
public class ShowAddressService extends Service {
    private MyPhoneStateListener listener;// 电话状态监听器
    private TelephonyManager manager;// 电话管理器
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        manager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
        PhoneStateListener listener = new MyPhoneStateListener();
        manager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        manager.listen(listener, PhoneStateListener.LISTEN_NONE);
        listener = null;
    }
    /**
     * 电话状态监听器
     * @author hacket
     */
    private class MyPhoneStateListener extends PhoneStateListener {
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
            switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:// 电话响铃时
                String phoneAddress = AddressDao.getAddress(getApplicationContext(), incomingNumber);
                Toast.makeText(getApplicationContext(), phoneAddress, Toast.LENGTH_SHORT).show();
                break;
            }
        }
    }
}
2、在设置中提供是否开启来电提醒的功能
// 2、注册来电提醒是否提醒事件
sv_setting_showPhoneAddress = (SettingView) this.findViewById(R.id.sv_setting_show_phone_address);
sv_setting_showPhoneAddress.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
        if (sv_setting_showPhoneAddress.isChecked()) {
            sv_setting_showPhoneAddress.setChecked(false);
            stopService(addressIntent);// 停止服务
        }else {
            sv_setting_showPhoneAddress.setChecked(true);
            addressIntent = new Intent(SettingActivity.this, ShowAddressService.class);
            startService(addressIntent);// 开启服务
        }
    }
});
结果
问题1:监听电话状态的服务,是否开启,不能用SharedPreferences保存,因为,当开启为true的时候,应用程序突然挂掉或者没电了,在下次启动的时候,service不在了(因为没有点击,服务启动不了),所以不能存,要检测服务的状态。然后根据检测出来的服务的状态来勾选或者不勾选这个。
解决:只能检测服务,而不是保存服务 -- ActivityManager 
/**
 * 3、检测服务的状态-是否开启和关闭
 * @author hacket
 */
public class ServiceStatusUtils {
    /**
     * 1、检测服务是否开启
     * @param context 上下文
     * @param clazz 待检测的是否运行服务的字节码
     * @return true为开启,false为关闭状态
     */
    public static boolean isServiceOpen(Context context, Class<?> clazz) {
        ActivityManager activityManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        
        //获取正在运行的服务,参数表示最大获取的服务,超过100个,那么也只获取最近100个服务
        List<RunningServiceInfo> runningServices = activityManager.getRunningServices(100);
        for (RunningServiceInfo runningServiceInfo : runningServices) {
            // 注意要runningServiceInfo.service中的service一定要记得写上
            String runningServiceName = runningServiceInfo.service.getClassName();// 正在运行的服务的类名
            String isRunServiceName = clazz.getName();
            if (!TextUtils.isEmpty(isRunServiceName)) { //正在运行的服务和要检测的服务相同类名
                if (isRunServiceName.equals(runningServiceName)) {
                    return true;
                }
            }
        }
        return false;
    }
}  
结果测试:
a) 刚进去界面,Service没有开启,然后按后退键,退出程序,但服务还是在运行着,再次进来的时候,服务还是运行着,因为是开启服务,不是绑定服务,Activity销毁,服务还在后台运行着。
b) 要想停止服务,那么可以停止服务或者强制退出进程和服务

或者

c) 隐藏的bug:
设置中,勾选了开启服务,但按home键,此时SettingActivity并没有退出,
此时,将服务给关闭掉。

然后,在切换到SettingActivity界面中去,发现服务的勾,还在.

但如果是强制退出,就不会出现该bug,因为SettingActivity也退出了

这是一个隐藏的bug,这是因为我们检测服务是否运行的代码,写在
SettingActivity中的onCreate()方法中,这个方法只有按后退键会销毁,
而按Home键,不会销毁,所以此时将服务关闭,然后在进来,此时
Oncreate()方法并没有执行,那么勾自然也不会更新。

解决:将检测服务是否运行,放在SettingActivity中的onStart()方法,
当用户可见,Home切换过来,也会执行该方法,才能服务是否正在运行状态。
// 3、检测一下, 是否服务运行,用户界面可见时判断服务是否开启
@Override
protected void onStart() {
    super.onStart();
    boolean isServiceOpen = ServiceStatusUtils.isServiceOpen(this,ShowAddressService.class);
    if (isServiceOpen) {// 服务开启了
        Log.i(TAG, "手机归属地查询服务开启了。。。");
        sv_setting_showPhoneAddress.setChecked(true);
    } else {
        sv_setting_showPhoneAddress.setChecked(false);
        Log.i(TAG, "手机归属地查询服务关闭了。。。");
    }
}