+1

Notification (đọc thông tin trên thanh notification)

I.Giới thiệu

  • Notification là một thông điệp hiển thị với người dùng bên ngoài UI bình thường của ứng dụng, nó nằm phía trên cùng của màn hình.
  • Một tin nhắn mới, một thông báo update version hay một lời mời kết bạn trên facebook được hiển thị và chuyển tải ngay lập tức đến người dùng thông qua Notification.
  • Notification giúp người dùng đọc lướt nhanh các tin tức,các thông báo được setting hiển thị trên máy của bạn, và cũng có thể mở ứng dụng đã thông báo từ nó.
  • Sự tiện lợi và phổ biến của Notification là không cần phải bàn cãi, vì thế các nhà lập trình viên luôn khai thác ưu điểm này để tạo ra các ứng dụng liên quan đến Notification.
  • Phần dưới đây mình không hướng dẫn các bạn tạo 1 Notification như thế nào mà hướng dẫn các bạn cách đọc thông tin của tất cả các Notification được hiển thị trên device.

II.Đọc dữ liệu trên Notification

  • Cấu trúc Notificaton:
    • Notification gồm 3 thành phần mà chúng ta có thể set hiển thị, và chúng ta cũng chỉ đọc được nội dung của 3 thành phần này.
      • setSmallIcon(R.drawable.notification_icon)
      • setContentTitle("My notification")
      • setContentText("Hello World!");
    • Ngoài ra cũng có thể xác định thêm Notification đang hiển thị là của app nào bằng cách đọc getPackageName(), Và dùng packageName để lựa chọn phân loại nội dụng Notification của các app mình mong muốn.
  • Sử dụng service để đọc dự liệu, service này extent từ AccessibilityService sẽ giúp chúng ta bắt được trạng thái thay đổi của Notification.
    • Khi connect Service thành công trong onServiceConnected hãy đăng ký infor cho AccessibilityServiceInfo
		AccessibilityServiceInfo info = new AccessibilityServiceInfo();
		info.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
		info.feedbackType = AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
		info.notificationTimeout = 100;
		setServiceInfo(info);
  • Trong onAccessibilityEvent(AccessibilityEvent event) của service sẽ hiển thị tất cả các data của Notification đang hiển thị, những data này của nhiều app khác nhau và nội dung thông tin và câu trúc khác nhau có dạng html, có dạng json, xml tùy theo các app cung cấp Notification.

    • Các hàm cơ bản thường dùng ở lớp này
    • event.getEventType(): lấy kiểu của event, ở đây chúng ta đang dùng service để bắt các trạng thái của hệ thống lên sẽ có nhiều eventType khác nhau, phần đăng ký info chúng ta đang đăng ký nhận eventTypes TYPE_NOTIFICATION_STATE_CHANGED do vậy ở đây chúng ta check chỉ quan tâm đến TYPE_NOTIFICATION_STATE_CHANGED còn những eventType khác thì bỏ qua.
    • event.getText(): lấy về 1 List các text nội dung của notification, ở đây chỉ lấy được nội dung của các app mà chúng ta cài đặt thêm như facebook, line... Nhưng nội dung của hệ thống như tin nhắn đến, thông báo update hệ thống thì không lấy được.
    • event.getParcelableData(): lấy về 1 Parcelable từ đây chúng ta có thể ép kiểu nó để trở thành 1 Notification notification = (Notification) event.getParcelableData(); Khi đã thành 1 Notification chúng ta có thể điểu khiển hay đọc nội dung tùy thích.
    • Nội dung Notification của các app hệ thống như SMS thì khó đọc hơn 1 chút vì chúng không được public. Chúng ta có thể dùng thủ thuật 1 chút. Bằng cách dùng event.getParcelableData() để lấy về 1 Notification từ Notification này chúng ta lấy cái view hiển thị của nó RemoteViews views = notification.contentView, từ RemoteViews này ta lại ép nó sang 1 Class rồi getDeclaredFields() lấy về 1 list các Field. Trong Field sẽ chưa các nội dung cần thiết.
  • Khởi động Server trong Manifest

        <service
            android:name="com.example.NotificationService"
            android:label="@string/app_name"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>

            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibilityservice" />
        </service>

III.Demo hướng dẫn đọc Notification của Line, KakaoTalk, Message, WeChat

public class NotificationService extends AccessibilityService {

    protected void onServiceConnected() {
        // TODO Auto-generated method stub
        super.onServiceConnected();
        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
        info.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
        info.feedbackType = AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
        info.notificationTimeout = 100;
        setServiceInfo(info);
    }

    public void onAccessibilityEvent(AccessibilityEvent event) {
        if (event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
            Parcelable data = event.getParcelableData();
            if (event.getPackageName().toString()
                    .equalsIgnoreCase(Const.PACKAGE_KAKAO_TALK)
                    || event.getPackageName().toString()
                    .equalsIgnoreCase(Const.PACKAGE_LINE)) {
                // data LINE and KAKAO_TALK
                //title > event.getText().get(0).toString()
                //content > event.getText().get(1).toString()
                return;
            }
            if (data instanceof Notification) {
                Notification notification = (Notification) data;
                RemoteViews views = notification.contentView;
                Class secretClass = views.getClass();
                try {
                    Map<String, String> text = new HashMap<String, String>();

                    Field outerFields[] = secretClass.getDeclaredFields();
                    for (int i = 0; i < outerFields.length; i++) {

                        if (!outerFields[i].getName().equals("mActions"))
                            continue;
                        outerFields[i].setAccessible(true);
                        ArrayList<Object> actions = (ArrayList<Object>) outerFields[i]
                                .get(views);
                        for (Object action : actions) {

                            Field innerFields[] = action.getClass()
                                    .getDeclaredFields();
                            for (Field field : innerFields) {
                                field.setAccessible(true);
                                if (field.get(action).toString()
                                        .equalsIgnoreCase("10")
                                        && field.getName().equals("type")) {
                                    for (Field field2 : innerFields) {

                                        field2.setAccessible(true);
                                        if (field2.getName().equals("value")) {
                                            if (!text.containsKey("sender")) {
                                                text.put("sender",
                                                        field2.get(action)
                                                                .toString());
                                            } else if (!text
                                                    .containsKey("body")) {
                                                String sBody = field2.get(
                                                        action).toString();
                                                if (event
                                                        .getPackageName()
                                                        .toString()
                                                        .equalsIgnoreCase(
                                                                Const.PACKAGE_WE_CHAT)) {
                                                    sBody = getBodyWeChat(sBody);
                                                }
                                                text.put("body", sBody);
                                            }
                                        }
                                    }
                                } else {
                                    continue;
                                }

                            }

                        }
                        // data WE_CHAT and MESSAGE
                        String title = text.get("sender");
                        String content = text.get("body");

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public String getBodyWeChat(String body) {
        char[] c = body.toCharArray();
        int count = 0;
        String rBody = body;
        for (int j = 0; j < c.length; j++) {
            if (c[j] == '[' && j == 0) {
                count = 1;
            }
            if (c[j] == '[' && count == 1) {
                count = 2;
            }
            if (count == 2 && c[j] == ':') {
                rBody = body.substring(j + 2, c.length);
            }
        }
        return rBody;
    }

    public void onInterrupt() {
        // TODO Auto-generated method stub

    }

}

IV.Note

  • Từ việc đọc Notification sẽ khơi gợi suy nghĩ cho các bạn tạo ra ý tưởng mới cho app của các bạn. App theo dõi ai đó chẳng hạn 😃

  • Xin cảm ơn các bạn đã đọc.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí