翻看谷歌源码 那些让人感兴趣的东西--通知的好用功能

标签: androidgit源码
8314人阅读 评论(3) 收藏 举报
分类:

转载请注明出处:王亟亟的大牛之路

上周写完那篇Blog之后就一直做着被分配到的Web任务,也就没继续捯饬N那些事,然后今天还在看Notification这部分,然后看到了LNotification这个包,读完源码之后继续给大家做简单的分析,因为源码涉及翻墙所以代码和自己加的注释丢到Git了

安理下我的收纳库:https://github.com/ddwhan0123/Useful-Open-Source-Android

首先我们来看下这个项目在哪个目录下
这里写图片描述

地址如下:https://developer.android.com/samples/LNotifications/index.html

跟我们上次的Messaging Service是邻居。

那我们来看下演示效果(部分)

他在桌面icon也有 类似 待处理事件的通知
这里写图片描述

实现点击触发复杂事件以及通知排序

这里写图片描述

这里写图片描述

OK,因为是Sample所以好看难看我们不管,我们来看看分别能做什么,有3个功能块(都是Fragment)的,一个一个来分析


首先是HeadsUpNotificationFragment(这部分注释很详细了,就不过多分析了)

主要是实现这一点 用户点击通知会在Activity Task中生成一个新的实例

/**
 * Fragment that demonstrates options for displaying Heads-Up Notifications.
 * 这种模式下,用户点击通知会在Activity Task中生成一个新的实例
 */
public class HeadsUpNotificationFragment extends Fragment {

    /**
     * NotificationId用于从此Fragment的通知。
     */
    private static final int NOTIFICATION_ID = 1;

    private NotificationManager mNotificationManager;

    /**
     * 按钮用于点击显示通知
     */
    private Button mShowNotificationButton;

    /**
     * 如果选中,该Fragment创建的通知将显示为Heads-Up通知。
     */
    private CheckBox mUseHeadsUpCheckbox;

    /**
     * 使用此工厂方法来创建新实例
     * 该Fragment使用提供的参数。
     *
     * @return 新的HeadsUpNotificationFragment的实例.
     */
    public static HeadsUpNotificationFragment newInstance() {
        HeadsUpNotificationFragment fragment = new HeadsUpNotificationFragment();
        fragment.setRetainInstance(true);
        return fragment;
    }

    public HeadsUpNotificationFragment() {
        // 空构造
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //初始化NotificationManager
        mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
                .NOTIFICATION_SERVICE);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 填充UI
        return inflater.inflate(R.layout.fragment_heads_up_notification, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
        //点击按钮就Toast一段话,告知用户已经触发点击事件
        mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mNotificationManager.notify(NOTIFICATION_ID, createNotification(
                        mUseHeadsUpCheckbox.isChecked()));
                Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
            }
        });
        mUseHeadsUpCheckbox = (CheckBox) view.findViewById(R.id.use_heads_up_checkbox);
    }

    /**
     * 创建一个新的取决于参数的通知。
     *
     * @param makeHeadsUpNotification 一个布尔值判断是否通知将作为heads-up通知来创建。
     *                                <ul>
     *                                <li>true :  heads-up通知</li>
     *                                <li>false : 普通通知</li>
     *                                </ul>
     * @return 一个Notification 实例.
     */
    //@VisibleForTesting
    Notification createNotification(boolean makeHeadsUpNotification) {
        //这里就是一些普通的配置
        Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
                .setSmallIcon(R.drawable.ic_launcher_notification)
                .setPriority(Notification.PRIORITY_DEFAULT)
                .setCategory(Notification.CATEGORY_MESSAGE)
                .setContentTitle("Sample Notification")
                .setContentText("This is a normal notification.");
        //如果是heads-up通知
        if (makeHeadsUpNotification) {
            Intent push = new Intent();
            push.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            push.setClass(getActivity(), LNotificationActivity.class);

            PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(getActivity(), 0,
                    push, PendingIntent.FLAG_CANCEL_CURRENT);
            notificationBuilder
                    .setContentText("Heads-Up Notification on Android L or above.")
                    .setFullScreenIntent(fullScreenPendingIntent, true);
        }
        return notificationBuilder.build();
    }
}

然后是 VisibilityMetadataFragment

**主要行为是 在锁屏条件下Notification的各种现实情况,Public Private Secret
可应对与所需的一些业务场景,诸如需要输入一些pin 密码什么的才可以做操作的功能**

/**
 * Fragment that demonstrates how notifications with different visibility metadata differ on
 * a lockscreen.
 *在锁屏情况下不同的通知,默认PUBLIC
 */
public class VisibilityMetadataFragment extends Fragment {

    private NotificationManager mNotificationManager;

    /**
     * {@link RadioGroup} that has Visibility RadioButton in its children.
     */
    //用于选择模式
    private RadioGroup mRadioGroup;

    /**
     * 构建不同的ID,让他被区别对待
     */
    private Integer mIncrementalNotificationId = Integer.valueOf(0);

    /**
     * 按钮,显示通知用
     */
    private Button mShowNotificationButton;

    /**
     * 使用此工厂方法来创建使用提供的参数,该Fragment的新实例。
     *
     * @return 一个新的NotificationFragment的实例.
     */
    public static VisibilityMetadataFragment newInstance() {
        VisibilityMetadataFragment fragment = new VisibilityMetadataFragment();
        fragment.setRetainInstance(true);
        return fragment;
    }

    public VisibilityMetadataFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
                .NOTIFICATION_SERVICE);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_visibility_metadata_notification, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
        mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                NotificationVisibility visibility = getVisibilityFromSelectedRadio(mRadioGroup);
                showNotificationClicked(visibility);
            }
        });
        mRadioGroup = (RadioGroup) view.findViewById(R.id.visibility_radio_group);
    }

    /**
     * 创建一个具有不同级别可视性的通知。
     *
     * @param visibility 要创建的通知的可见性
     * @return 通知的实例.
     */
    //@VisibleForTesting
    Notification createNotification(NotificationVisibility visibility) {
        Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
                .setContentTitle("Notification for Visibility metadata");

        notificationBuilder.setVisibility(visibility.getVisibility());
        notificationBuilder.setContentText(String.format("Visibility : %s",
                visibility.getDescription()));
        notificationBuilder.setSmallIcon(visibility.getNotificationIconId());

        return notificationBuilder.build();
    }

    /**
     * Returns a {@link NotificationVisibility} depending on which RadioButton in the radiogroup
     * is selected.
     *
     * @param radiogroup The RadioGroup.
     * @return The instance of {@link NotificationVisibility} corresponding to RadioButton.
     */
    private NotificationVisibility getVisibilityFromSelectedRadio(RadioGroup radiogroup) {
        switch (radiogroup.getCheckedRadioButtonId()) {
            case R.id.visibility_public_radio_button:
                return NotificationVisibility.PUBLIC;
            case R.id.visibility_private_radio_button:
                return NotificationVisibility.PRIVATE;
            case R.id.visibility_secret_radio_button:
                return NotificationVisibility.SECRET;
            default:
                //If not selected, returns PUBLIC as default.
                return NotificationVisibility.PUBLIC;
        }
    }

    /**
     * Invoked when {@link #mShowNotificationButton} is clicked.
     * Creates a new notification with a different visibility level.
     *
     * @param visibility The visibility of the notification to be created.
     */
    private void showNotificationClicked(NotificationVisibility visibility) {
        // Assigns a unique (incremented) notification ID in order to treat each notification as a
        // different one. This helps demonstrate how a notification with a different visibility
        // level differs on the lockscreen.
        mIncrementalNotificationId = new Integer(mIncrementalNotificationId + 1);
        mNotificationManager.notify(mIncrementalNotificationId, createNotification(visibility));
        Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
    }

    /**
     * Enum indicating possible visibility levels for notifications and related data(String
     * representation of visibility levels, an icon ID to create a notification) to
     * create a notification.
     */
    //@VisibleForTesting
     enum NotificationVisibility {
        PUBLIC(Notification.VISIBILITY_PUBLIC, "Public", R.drawable.ic_public_notification),
        PRIVATE(Notification.VISIBILITY_PRIVATE, "Private", R.drawable.ic_private_notification),
        SECRET(Notification.VISIBILITY_SECRET, "Secret", R.drawable.ic_secret_notification);

        /**
         * Visibility level of the notification.
         */
        private final int mVisibility;

        /**
         * String representation of the visibility.
         */
        private final String mDescription;

        /**
         * Id of an icon used for notifications created from the visibility.
         */
        private final int mNotificationIconId;

        NotificationVisibility(int visibility, String description, int notificationIconId) {
            mVisibility = visibility;
            mDescription = description;
            mNotificationIconId = notificationIconId;
        }

        public int getVisibility() {
            return mVisibility;
        }

        public String getDescription() {
            return mDescription;
        }

        public int getNotificationIconId() {
            return mNotificationIconId;
        }
    }
}

还有个就是我们截图中的类OtherMetadataFragment

他可以根据用户操作做一些列诸如邮件,电话,闹钟提示等功能,并对通知进行轻重缓急的排序

/**
 * Fragment that demonstrates how to attach metadata introduced in Android L, such as
 * priority data, notification category and person data.
 * 通知列表会根据优先级高低进行排序
 */
public class OtherMetadataFragment extends Fragment {

    private static final String TAG = OtherMetadataFragment.class.getSimpleName();

    /**
     * 用于采摘联系人请求的代码。
     */
    public static final int REQUEST_CODE_PICK_CONTACT = 1;

    /**
     * Incremental Integer used for ID for notifications so that each notification will be
     * treated differently.
     * 构建不同的ID,让他被区别对待
     */
    private Integer mIncrementalNotificationId = Integer.valueOf(0);

    private NotificationManager mNotificationManager;

    /**
     * 按钮,显示通知用
     */
    private Button mShowNotificationButton;

    /**
     * Spinner that holds possible categories used for a notification as
     * {@link Notification.Builder#setCategory(String)}.
     * 设置类型的下拉选择栏
     */
    private Spinner mCategorySpinner;

    /**
     * Spinner that holds possible priorities used for a notification as
     * {@link Notification.Builder#setPriority(int)}.
     * 设置优先级的下拉选择栏
     */
    private Spinner mPrioritySpinner;

    /**
     * Holds a URI for the person to be attached to the notification.
     * 持有的URI的人要附加到该通知。
     */
    //@VisibleForTesting
    Uri mContactUri;

    /**
     * 使用此工厂方法来创建使用提供的参数,该Fragment的新实例。
     *
     * @return 1个新的NotificationFragment的实例.
     */
    public static OtherMetadataFragment newInstance() {
        OtherMetadataFragment fragment = new OtherMetadataFragment();
        fragment.setRetainInstance(true);
        return fragment;
    }

    public OtherMetadataFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
                .NOTIFICATION_SERVICE);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_other_metadata, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
        mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //往spinner里填东西,然后发送通知
                Priority selectedPriority = (Priority) mPrioritySpinner.getSelectedItem();
                Category selectedCategory = (Category) mCategorySpinner.getSelectedItem();
                showNotificationClicked(selectedPriority, selectedCategory, mContactUri);
            }
        });
        //填充数据
        mCategorySpinner = (Spinner) view.findViewById(R.id.category_spinner);
        ArrayAdapter<Category> categoryArrayAdapter = new ArrayAdapter<Category>(getActivity(),
                android.R.layout.simple_spinner_item, Category.values());
        categoryArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        mCategorySpinner.setAdapter(categoryArrayAdapter);

        mPrioritySpinner = (Spinner) view.findViewById(R.id.priority_spinner);
        ArrayAdapter<Priority> priorityArrayAdapter = new ArrayAdapter<Priority>(getActivity(),
                android.R.layout.simple_spinner_item, Priority.values());
        priorityArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        mPrioritySpinner.setAdapter(priorityArrayAdapter);

        view.findViewById(R.id.attach_person).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                findContact();
            }
        });

        view.findViewById(R.id.contact_entry).setVisibility(View.GONE);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case REQUEST_CODE_PICK_CONTACT:
                if (resultCode == Activity.RESULT_OK) {
                    Uri contactUri = data.getData();
                    mContactUri = contactUri;
                    updateContactEntryFromUri(contactUri);
                }
                break;
        }
    }

    /**
     * Invoked when {@link #mShowNotificationButton} is clicked.
     * Creates a new notification and sets metadata passed as arguments.
     *
     * @param priority   The priority metadata.
     * @param category   The category metadata.
     * @param contactUri The URI to be added to the new notification as metadata.
     * @return A Notification instance.
     */
    //@VisibleForTesting
    Notification createNotification(Priority priority, Category category, Uri contactUri) {
        Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
                .setContentTitle("Notification with other metadata")
                .setSmallIcon(R.drawable.ic_launcher_notification)
                .setPriority(priority.value)
                .setCategory(category.value)
                .setContentText(String.format("Category %s, Priority %s", category.value,
                        priority.name()));
        if (contactUri != null) {
            notificationBuilder.addPerson(contactUri.toString());
            Bitmap photoBitmap = loadBitmapFromContactUri(contactUri);
            if (photoBitmap != null) {
                notificationBuilder.setLargeIcon(photoBitmap);
            }
        }
        return notificationBuilder.build();
    }

    /**
     * Invoked when {@link #mShowNotificationButton} is clicked.
     * Creates a new notification and sets metadata passed as arguments.
     *
     * @param priority   The priority metadata.
     * @param category   The category metadata.
     * @param contactUri The URI to be added to the new notification as metadata.
     */
    private void showNotificationClicked(Priority priority, Category category, Uri contactUri) {
        // Assigns a unique (incremented) notification ID in order to treat each notification as a
        // different one. This helps demonstrate how a priority flag affects ordering.
        mIncrementalNotificationId = new Integer(mIncrementalNotificationId + 1);
        mNotificationManager.notify(mIncrementalNotificationId, createNotification(priority,
                category, contactUri));
        Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
    }

    private void findContact() {
        Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
        startActivityForResult(intent, REQUEST_CODE_PICK_CONTACT);
    }

    /**
     * Returns a {@link Bitmap} from the Uri specified as the argument.
     *
     * @param contactUri The Uri from which the result Bitmap is created.
     * @return The {@link Bitmap} instance retrieved from the contactUri.
     */
    private Bitmap loadBitmapFromContactUri(Uri contactUri) {
        if (contactUri == null) {
            return null;
        }
        Bitmap result = null;
        Cursor cursor = getActivity().getContentResolver().query(contactUri, null, null, null,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            int idx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
            String hasPhoto = cursor.getString(idx);
            Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo
                    .CONTENT_DIRECTORY);
            if (hasPhoto != null) {
                try {
                    result = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver()
                            , photoUri);
                } catch (IOException e) {
                    Log.e(TAG, String.format("Failed to load resource. Uri %s", photoUri), e);
                }
            } else {
                Drawable defaultContactDrawable = getActivity().getResources().getDrawable(R
                        .drawable.ic_contact_picture);
                result = ((BitmapDrawable) defaultContactDrawable).getBitmap();
            }
        }
        return result;
    }

    /**
     * Updates the Contact information on the screen when a contact is picked.
     *
     * @param contactUri The Uri from which the contact is retrieved.
     */
    private void updateContactEntryFromUri(Uri contactUri) {
        Cursor cursor = getActivity().getContentResolver().query(contactUri, null, null, null,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            int idx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
            String name = cursor.getString(idx);
            idx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
            String hasPhoto = cursor.getString(idx);

            Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo
                    .CONTENT_DIRECTORY);
            ImageView contactPhoto = (ImageView) getActivity().findViewById(R.id.contact_photo);
            if (hasPhoto != null) {
                contactPhoto.setImageURI(photoUri);
            } else {
                Drawable defaultContactDrawable = getActivity().getResources().getDrawable(R
                        .drawable.ic_contact_picture);
                contactPhoto.setImageDrawable(defaultContactDrawable);
            }
            TextView contactName = (TextView) getActivity().findViewById(R.id.contact_name);
            contactName.setText(name);

            getActivity().findViewById(R.id.contact_entry).setVisibility(View.VISIBLE);
            getActivity().findViewById(R.id.attach_person).setVisibility(View.GONE);
            getActivity().findViewById(R.id.click_to_change).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    findContact();
                }
            });
            Log.i(TAG, String.format("Contact updated. Name %s, PhotoUri %s", name, photoUri));
        }
    }

    /**
     * Enum indicating possible categories in {@link Notification} used from
     * {@link #mCategorySpinner}.
     */
     enum Category {
        ALARM("alarm"),
        CALL("call"),
        EMAIL("email"),
        ERROR("err"),
        EVENT("event"),
        MESSAGE("msg"),
        PROGRESS("progress"),
        PROMO("promo"),
        RECOMMENDATION("recommendation"),
        SERVICE("service"),
        SOCIAL("social"),
        STATUS("status"),
        SYSTEM("sys"),
        TRANSPORT("transport");

        private final String value;

        Category(String value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return value;
        }
    }

    /**
     * Enum indicating possible priorities in {@link Notification} used from
     * {@link #mPrioritySpinner}.
     */
    //@VisibleForTesting
     enum Priority {
        DEFAULT(Notification.PRIORITY_DEFAULT),
        MAX(Notification.PRIORITY_MAX),
        HIGH(Notification.PRIORITY_HIGH),
        LOW(Notification.PRIORITY_LOW),
        MIN(Notification.PRIORITY_MIN);

        private final int value;

        Priority(int value) {
            this.value = value;
        }
    }
}

这部分的代码比较长,没有对每一部分进行翻译OR解释,在这里大致描述下。
首先声明了2个枚举,一个操作类型,一个操作排序的次序。

测试的时候分别对,默认,最高和最低进行了测试,结果也如大家所看到的,最高就会在最上面,最低就出现在通知栏最下面了,然后就是行为类型,用户在产生通知之前需要选择他的行为类型以及该类型所需的一些参数诸如通讯录联系人的号码啊,邮箱地址什么的,有些需要图片操作的源码里也做了相应实现大家需要的可以调用就行了。(因为测试机没通讯录,所以没有测的很深,大家可以自己插卡试试,这部分如何暂时保留意见,但是排序是绝对有效的)

以上是对这个包里3个实现Fragment的简单分析,然后提一下注意点,使用场景在 安卓 L 就是 棒棒糖版本版本过低的有问题就是自己适配了。

最重要的一点是 这些通知 都会在桌面的应用 ICON产生 1 2 3这类未读数的统计

源码地址:https://github.com/ddwhan0123/BlogSample/blob/master/LNotifications.zip?raw=true

谢谢各位观众老爷,有问题可以微信M我(活人不是公众号)

这里写图片描述

7
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:741741次
    • 积分:9815
    • 等级:
    • 排名:第1976名
    • 原创:208篇
    • 转载:5篇
    • 译文:6篇
    • 评论:920条
    博客专栏
    最新评论