diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/car/calendar/CarCalendarView.java | 39 | ||||
-rw-r--r-- | src/com/android/car/calendar/common/EventsLiveData.java | 22 |
2 files changed, 35 insertions, 26 deletions
diff --git a/src/com/android/car/calendar/CarCalendarView.java b/src/com/android/car/calendar/CarCalendarView.java index 07b9516..1a63588 100644 --- a/src/com/android/car/calendar/CarCalendarView.java +++ b/src/com/android/car/calendar/CarCalendarView.java @@ -17,7 +17,6 @@ package com.android.car.calendar; import static com.google.common.base.Verify.verify; -import static com.google.common.base.Verify.verifyNotNull; import android.Manifest; import android.util.Log; @@ -25,10 +24,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.Observer; import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; import com.android.car.calendar.common.CalendarFormatter; import com.android.car.calendar.common.Dialer; @@ -64,15 +63,8 @@ class CarCalendarView { /** Holds an instance of either {@link LocalDate} or {@link Event} for each item in the list. */ private final List<CalendarItem> mRecyclerViewItems = new ArrayList<>(); - private final RecyclerView.Adapter mAdapter = new EventRecyclerViewAdapter(); - private final Observer<ImmutableList<Event>> mEventsObserver = - events -> { - if (DEBUG) Log.d(TAG, "Events changed"); - updateRecyclerViewItems(events); - - // TODO(jdp) Only change the affected items (DiffUtil) to allow animated changes. - mAdapter.notifyDataSetChanged(); - }; + private final RecyclerView.Adapter<ViewHolder> mAdapter = new EventRecyclerViewAdapter(); + private final Observer<ImmutableList<Event>> mEventsObserver = this::onEventsChanged; CarCalendarView( CarCalendarActivity carCalendarActivity, @@ -102,23 +94,30 @@ class CarCalendarView { private void showWithPermission() { EventsLiveData eventsLiveData = mCarCalendarViewModel.getEventsLiveData(); eventsLiveData.observe(mCarCalendarActivity, mEventsObserver); - updateRecyclerViewItems(verifyNotNull(eventsLiveData.getValue())); + } + + private void onEventsChanged(ImmutableList<Event> events) { + updateRecyclerViewItems(events); + + // TODO(jdp) Only change the affected items (DiffUtil) to allow animated changes. + mAdapter.notifyDataSetChanged(); } /** * If the events list is null there is no calendar data available. If the events list is empty * there is calendar data but no events. */ - private void updateRecyclerViewItems(@Nullable ImmutableList<Event> carCalendarEvents) { + private void updateRecyclerViewItems(@Nullable ImmutableList<Event> events) { + if (DEBUG) Log.d(TAG, "Update events"); LocalDate currentDate = null; mRecyclerViewItems.clear(); - if (carCalendarEvents == null) { + if (events == null) { mNoEventsTextView.setVisibility(View.VISIBLE); mNoEventsTextView.setText(R.string.no_calendars); return; } - if (carCalendarEvents.isEmpty()) { + if (events.isEmpty()) { mNoEventsTextView.setVisibility(View.VISIBLE); mNoEventsTextView.setText(R.string.no_events); return; @@ -130,7 +129,7 @@ class CarCalendarView { // add the event rows after looking at all events for the day. List<CalendarItem> eventItems = null; List<EventCalendarItem> allDayEventItems = null; - for (Event event : carCalendarEvents) { + for (Event event : events) { LocalDate date = event.getDayStartInstant().atZone(ZoneId.systemDefault()).toLocalDate(); @@ -177,17 +176,15 @@ class CarCalendarView { mRecyclerViewItems.addAll(eventItems); } - private class EventRecyclerViewAdapter extends RecyclerView.Adapter { - - @NonNull + private class EventRecyclerViewAdapter extends RecyclerView.Adapter<ViewHolder> { @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { CalendarItem.Type type = CalendarItem.Type.values()[viewType]; return type.createViewHolder(parent); } @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + public void onBindViewHolder(ViewHolder holder, int position) { mRecyclerViewItems.get(position).bind(holder); } diff --git a/src/com/android/car/calendar/common/EventsLiveData.java b/src/com/android/car/calendar/common/EventsLiveData.java index f2df3fe..92ae0bb 100644 --- a/src/com/android/car/calendar/common/EventsLiveData.java +++ b/src/com/android/car/calendar/common/EventsLiveData.java @@ -31,7 +31,9 @@ import android.provider.CalendarContract; import android.provider.CalendarContract.Instances; import android.util.Log; +import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LiveData; +import androidx.lifecycle.Observer; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; @@ -54,6 +56,8 @@ import javax.annotation.Nullable; * Provider</a>. * * <p>While in the active state the content provider is observed for changes. + * + * <p>When the value given to the observer is null it signals that there are no calendars. */ public class EventsLiveData extends LiveData<ImmutableList<Event>> { @@ -72,20 +76,22 @@ public class EventsLiveData extends LiveData<ImmutableList<Event>> { private final ContentResolver mContentResolver; private final EventDescriptions mEventDescriptions; private final EventLocations mLocations; - private final Runnable mUpdateRunnable = this::updateIfChanged; + private final Runnable mUpdateIfChangedRunnable = this::updateIfChanged; /** The event instances cursor is a field to allow observers to be managed. */ @Nullable private Cursor mEventsCursor; @Nullable private ContentObserver mEventInstancesObserver; + // This can be updated on the background thread but read from any thread. + private volatile boolean mValueUpdated; + public EventsLiveData( Clock clock, Handler backgroundHandler, ContentResolver contentResolver, EventDescriptions eventDescriptions, EventLocations locations) { - super(ImmutableList.of()); mClock = clock; mBackgroundHandler = backgroundHandler; mContentResolver = contentResolver; @@ -95,10 +101,14 @@ public class EventsLiveData extends LiveData<ImmutableList<Event>> { /** Refreshes the event instances and sets the new value which notifies observers. */ private void updateIfChanged() { + Log.d(TAG, "Update if changed"); ImmutableList<Event> latest = getEventsUntilTomorrow(); ImmutableList<Event> current = getValue(); - if (!Objects.equals(latest, current)) { + + // Always post the first value even if it is null. + if (!mValueUpdated || !Objects.equals(latest, current)) { postValue(latest); + mValueUpdated = true; } } @@ -187,8 +197,9 @@ public class EventsLiveData extends LiveData<ImmutableList<Event>> { private void updateWithDelay() { // Do not update the events until there have been no changes for a given duration. - mBackgroundHandler.removeCallbacks(mUpdateRunnable); - mBackgroundHandler.postDelayed(mUpdateRunnable, UPDATE_DELAY_MILLIS); + Log.d(TAG, "Events changed"); + mBackgroundHandler.removeCallbacks(mUpdateIfChangedRunnable); + mBackgroundHandler.postDelayed(mUpdateIfChangedRunnable, UPDATE_DELAY_MILLIS); } /** Can return multiple events for a single cursor row when an event spans multiple days. */ @@ -277,6 +288,7 @@ public class EventsLiveData extends LiveData<ImmutableList<Event>> { if (DEBUG) Log.d(TAG, "Live data inactive"); mBackgroundHandler.post(this::cancelScheduledUpdate); mBackgroundHandler.post(this::tearDownCursor); + mValueUpdated = false; } /** Calls {@link #updateIfChanged()} every minute to keep the displayed time range correct. */ |