最近在优化公司Launcher桌面,分配到了未接电话和未读短信桌面图标提示功能。也就是在电话图标和短信图标上显示未接电话条数或未读的信息条数。
1.监听未接电话
一般我们可以通过广播监听和电话数据库监听两种方式来获取到未接电话,都需要电话权限。
1.1广播监听
在manifest中注册监听android.intent.action.PHONE_STATE 的广播接收器, 当手机的状态改变后将会收到广播,然后再根据收到的手机状态进行处理。
手机的状态分为CALL_STATE_RINGING(响铃中),CALL_STATE_IDLE(空闲),CALL_STATE_OFFHOOK(忙音)。也就是说当你没有任何电话是,状态是 IDLE ,当接到电话时是 OFFHOOK ,电话结束后返回 IDLE 状态。记录上一次的手机状态,如果的手机现在的空闲,上次的状态响铃中的话,就可以判断是未接来电。
这种方式的问题在于,无法读取到之前的未接电话数据,而且需要自己处理状态和未接电话的数量,过于麻烦。
1.2 电话数据库监听
我们可以通过注册,来监听电话数据库的变化,当数据库发生变化时,将会触发我们的onChange方法,然后我们再进行数据库查找,看是否有未接电话信息,同时,当用户查看了未接电话后,我们也可以监听到,这时我们可以取消未接电话数量提示图标。而在广播监听方式来处理的话,就会复杂很多。
2. 短信监听
既然通过数据库监听的方式这么方便,那我们的短信监听也是使用短信数据库监听的方式来实现。
3.源码
3.1 处理未接电话和未读短信(刷新UI)
Handler mUnreadAndMessageHandler = new Handler() { public void handleMessage(Message msg) { if (mWorkspace == null) { return; } switch (msg.what) { case WHAT_MISS_PHONE: // 未对电话 for (View view : mWorkspace.getAllItemView()) { if (view instanceof BubbleTextView) { ShortcutInfo tag = (ShortcutInfo) view.getTag(); if (Mycontancs.getContacs(Launcher.this, tag)) { tag.contacsNum = Integer.valueOf(msg.arg1); view.setTag(tag); view.invalidate(); } } } break; case WHAT_MISS_MESSAGE: // 短信 for (View view : mWorkspace.getAllItemView()) { if (view instanceof BubbleTextView) { ShortcutInfo tag = (ShortcutInfo) view.getTag(); if (Mycontancs.getMmsString(Launcher.this, tag)) { tag.contacsNum = Integer.valueOf(msg.arg1); view.setTag(tag); view.invalidate(); } } } break; default: break; } } };
3.2 注册未接电话和未读短信监听
Uri mSmsuri = Uri.parse("content://mms-sms");
MyMessageObserver messageObserver = new MyMessageObserver(mUnreadAndMessageHandler, Launcher.this);getContentResolver () . registerContentObserver (mSmsuri , true, messageObserver ) ;
MissedCallContentObserver mMissedCallContentObserver =
new MissedCallContentObserver(Launcher.this, mUnreadAndMessageHandler);getContentResolver () . registerContentObserver ( CallLog.Calls . CONTENT_URI , false, mMissedCallContentObserver ) ;
3.3 短信监听器
class MyMessageObserver extends ContentObserver { private Context mContext; private Handler mMMsHandler; private View mView; /** * 构建未读短信数据观察对象 * * @param handler Handler */ public MyMessageObserver(Handler handler) { super(handler); this.mMMsHandler = handler; } /** * 构建未读短信数据观察对象 * * @param handler Handler * @param mContext 上下文对象 */ public MyMessageObserver(Handler handler, Context mContext) { this(handler); this.mContext = mContext; } @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); if ("content://mms-sms/conversations/".equals(uri)) { Message msg = new Message(); msg.what = Launcher.WHAT_MISS_MESSAGE; msg.arg1 = 0; mMMsHandler.sendMessage(msg); } else { if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED) { readMissMessage(); } } } /** * 读取未读短信数量 * 开发者: Administrator * 时间:2015-8-3 下午2:38:32 */ public void readMissMessage() { new Thread() { @Override public void run() { super.run(); final int missMessageCount = Mycontancs.getUnreadSmsCount(mContext); XLog.e("victor", "未读短信数量:" + missMessageCount); Message msg = new Message(); msg.what = Launcher.WHAT_MISS_MESSAGE; msg.arg1 = missMessageCount; mMMsHandler.sendMessage(msg); } }.start(); } public void setView(View view) { mView = view; } public View getView() { return mView; } }
3.3 电话监听器
class MissedCallContentObserver extends ContentObserver { private Context ctx; private Handler mHandler; private View mView; /** * 构建文件电话回调对象 * * @param context 上下文 * @param handler handler 对象 */ public MissedCallContentObserver(Context context, Handler handler) { super(handler); ctx = context; this.mHandler = handler; } @Override public void onChange(boolean selfChange) { XLog.e("victor", "call -- onChange()"); if (ActivityCompat.checkSelfPermission(ctx, Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED) { readMissPhone(); } } public void setView(View view) { mView = view; } public View getView() { return mView; } /** * 读取未接电话 * 开发者: Administrator * 时间:2015-8-3 下午2:32:20 */ public void readMissPhone() { new Thread() { @Override public void run() { super.run(); int missPhoneCount = Mycontancs.getMissCallCount(ctx); XLog.e("victor", "miss phone count = " + missPhoneCount); Message msg = Message.obtain(); msg.what = Launcher.WHAT_MISS_PHONE; msg.arg1 = missPhoneCount; mHandler.sendMessage(msg); } }.start(); } }
3.4 未接电话和未读短信管理类
public final class Mycontancs { /** * 获得电话组建的信息 * * @param info Shortcutinfo * @return boolean */ public static boolean getContacs(Context context, ShortcutInfo info) { Intent intent = info.getIntent(); if (intent == null) return false; if (intent.getComponent() == null) { return false; } String packageName = intent.getComponent().getPackageName(); List<String> phone_items = Arrays.asList(context.getResources().getStringArray(R.array.tip_phone)); return phone_items.contains(packageName); } /** * 返回短信组建的信息 * * @param info Shortcutinfo * @return boolean */ public static boolean getMmsString(Context context, ShortcutInfo info) { Intent intent = info.getIntent(); if (intent == null) return false; ComponentName component = intent.getComponent(); if (component == null) { return false; } if (context == null) return false; String packageName = component.getPackageName(); List<String> mms_items = Arrays.asList(context.getResources().getStringArray(R.array.tip_Message)); return mms_items.contains(packageName); } /** * 返回共享参数 * * @return */ public static SharedPreferences getSharedPreferences(Context context) { SharedPreferences sharedPreferences = null; if (sharedPreferences == null) { sharedPreferences = context.getSharedPreferences(Mycontancs.sSharedPreferencesKey, Context.MODE_PRIVATE); } return sharedPreferences; } /** * 获取未读电话的条数 * * @param mContext 上下文 * @return */ public static int getMissCallCount(final Context mContext) { int missCount = 0; Cursor cursor = null; if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) { return 0; } try { String[] select = new String[]{"number", "date", "type", "new"}; cursor = mContext.getContentResolver().query( CallLog.Calls.CONTENT_URI, select, "type=? and new=?", new String[]{"3", "1"}, null); if (null != cursor) { missCount = cursor.getCount(); cursor.close(); } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } return missCount; } /** * 获取未读短信条数 * * @param mContext 上下文 * @return */ public static int getUnreadSmsCount(Context mContext) { int result = 0; Cursor cursor = null; if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) { return 0; } try { cursor = mContext.getContentResolver().query( Uri.parse("content://sms"), null, "type = 1 and read = 0", null, null); if (cursor != null) { result = cursor.getCount(); cursor.close(); } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } return result; } }
3.4 填坑
由于未接电话需要电话权限,当电话权限被手动关闭,然后手动再打开,有未接电话时,无法监听到未接电话,需要再次注册才能监听到。
而当有电话权限时,未接电话图标提示功能需要自动开启,但是权限是否被开启了又没法监听,所以我在onResume中,每次都有判断是否有权限,有权限时,就注册未接电话功能,但是未读短信功能不会出现短信权限关了再开就收不到的情况。