| package com.android.car.notification; |
| |
| import android.car.drivingstate.CarUxRestrictions; |
| import android.car.drivingstate.CarUxRestrictionsManager; |
| import android.content.Context; |
| import android.graphics.Rect; |
| import android.util.AttributeSet; |
| import android.view.View; |
| import android.widget.Button; |
| |
| import androidx.annotation.NonNull; |
| import androidx.constraintlayout.widget.ConstraintLayout; |
| import androidx.recyclerview.widget.LinearLayoutManager; |
| import androidx.recyclerview.widget.RecyclerView; |
| import androidx.recyclerview.widget.RecyclerView.OnScrollListener; |
| import androidx.recyclerview.widget.SimpleItemAnimator; |
| |
| import java.util.List; |
| |
| |
| /** |
| * Layout that contains Car Notifications. |
| * |
| * It does some extra setup in the onFinishInflate method because it may not get used from an |
| * activity where one would normally attach RecyclerViews |
| */ |
| public class CarNotificationView extends ConstraintLayout |
| implements CarUxRestrictionsManager.OnUxRestrictionsChangedListener { |
| |
| private CarNotificationViewAdapter mAdapter; |
| private Context mContext; |
| private LinearLayoutManager mLayoutManager; |
| private NotificationDataManager mNotificationDataManager; |
| |
| public CarNotificationView(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| mContext = context; |
| } |
| |
| /** |
| * Attaches the CarNotificationViewAdapter and CarNotificationItemTouchListener to the |
| * notification list. |
| */ |
| @Override |
| protected void onFinishInflate() { |
| super.onFinishInflate(); |
| RecyclerView listView = findViewById(R.id.notifications); |
| |
| listView.setClipChildren(false); |
| mLayoutManager = new LinearLayoutManager(mContext); |
| listView.setLayoutManager(mLayoutManager); |
| listView.addItemDecoration(new TopAndBottomOffsetDecoration( |
| mContext.getResources().getDimensionPixelSize(R.dimen.item_spacing))); |
| listView.addItemDecoration(new ItemSpacingDecoration( |
| mContext.getResources().getDimensionPixelSize(R.dimen.item_spacing))); |
| |
| mAdapter = new CarNotificationViewAdapter(mContext, /* isGroupNotificationAdapter= */ |
| false); |
| listView.setAdapter(mAdapter); |
| |
| ((SimpleItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); |
| listView.addOnItemTouchListener(new CarNotificationItemTouchListener(mContext, mAdapter)); |
| |
| Button clearAllButton = findViewById(R.id.clear_all_button); |
| if (clearAllButton != null) { |
| clearAllButton.setOnClickListener(view -> mAdapter.clearAllNotifications()); |
| } |
| |
| listView.addOnScrollListener(new OnScrollListener() { |
| @Override |
| public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { |
| super.onScrollStateChanged(recyclerView, newState); |
| |
| // RecyclerView is not currently scrolling. |
| if (newState == RecyclerView.SCROLL_STATE_IDLE) { |
| setVisibleNotificationsAsSeen(); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Updates notifications and update views. |
| */ |
| public void setNotifications(List<NotificationGroup> notifications) { |
| mAdapter.setNotifications(notifications, /* setRecyclerViewListHeaderAndFooter= */ true); |
| } |
| |
| /** |
| * Collapses all expanded groups. |
| */ |
| public void collapseAllGroups() { |
| mAdapter.collapseAllGroups(); |
| } |
| |
| @Override |
| public void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo) { |
| mAdapter.setCarUxRestrictions(restrictionInfo); |
| } |
| |
| /** |
| * Sets the NotificationClickHandlerFactory that allows for a hook to run a block off code |
| * when the notification is clicked. This is useful to dismiss a screen after |
| * a notification list clicked. |
| */ |
| public void setClickHandlerFactory(NotificationClickHandlerFactory clickHandlerFactory) { |
| mAdapter.setClickHandlerFactory(clickHandlerFactory); |
| } |
| |
| /** |
| * Sets NotificationDataManager that handles additional states for notifications such as "seen", |
| * and muting a messaging type notification. |
| * |
| * @param notificationDataManager An instance of NotificationDataManager. |
| */ |
| public void setNotificationDataManager(NotificationDataManager notificationDataManager) { |
| mNotificationDataManager = notificationDataManager; |
| mAdapter.setNotificationDataManager(notificationDataManager); |
| } |
| |
| /** |
| * A {@link RecyclerView.ItemDecoration} that will add a top offset to the first item and bottom |
| * offset to the last item in the RecyclerView it is added to. |
| */ |
| private static class TopAndBottomOffsetDecoration extends RecyclerView.ItemDecoration { |
| private int mTopAndBottomOffset; |
| |
| private TopAndBottomOffsetDecoration(int topOffset) { |
| mTopAndBottomOffset = topOffset; |
| } |
| |
| @Override |
| public void getItemOffsets(Rect outRect, View view, RecyclerView parent, |
| RecyclerView.State state) { |
| super.getItemOffsets(outRect, view, parent, state); |
| int position = parent.getChildAdapterPosition(view); |
| |
| if (position == 0) { |
| outRect.top = mTopAndBottomOffset; |
| } |
| if (position == state.getItemCount() - 1) { |
| outRect.bottom = mTopAndBottomOffset; |
| } |
| } |
| } |
| |
| /** |
| * A {@link RecyclerView.ItemDecoration} that will add spacing between each item in the |
| * RecyclerView that it is added to. |
| */ |
| private static class ItemSpacingDecoration extends RecyclerView.ItemDecoration { |
| private int mItemSpacing; |
| |
| private ItemSpacingDecoration(int itemSpacing) { |
| mItemSpacing = itemSpacing; |
| } |
| |
| @Override |
| public void getItemOffsets(Rect outRect, View view, RecyclerView parent, |
| RecyclerView.State state) { |
| super.getItemOffsets(outRect, view, parent, state); |
| int position = parent.getChildAdapterPosition(view); |
| |
| // Skip offset for last item. |
| if (position == state.getItemCount() - 1) { |
| return; |
| } |
| |
| outRect.bottom = mItemSpacing; |
| } |
| } |
| |
| /** |
| * Sets currently visible notifications as "seen". |
| */ |
| public void setVisibleNotificationsAsSeen() { |
| int firstVisible = mLayoutManager.findFirstVisibleItemPosition(); |
| int lastVisible = mLayoutManager.findLastVisibleItemPosition(); |
| |
| // No visible items are found. |
| if (firstVisible == RecyclerView.NO_POSITION) return; |
| |
| |
| for (int i = firstVisible; i <= lastVisible; i++) { |
| mAdapter.setNotificationAsSeen(i); |
| } |
| } |
| } |