Support date header and Recent in PhotosTabFragment
- Add DateHeaderHolder
- Update items for date header and recent
- Support ITEM_TYPE_DATE_HEADER in PhotosTabAdapter
- Add DateTimeUtils
Bug: 189732217
Test: Manual. videos on the bug.
Test: atest DateTimeUtilsTest
Test: atest ItemTest
Change-Id: I3e8b7582c743e12548fd44e71e8a5beb079f561f
Merged-In: I3e8b7582c743e12548fd44e71e8a5beb079f561f
(cherry picked from commit 1b6db2d497508fece1bfd4a194af7577bb8940ad)
diff --git a/res/layout/item_date_header.xml b/res/layout/item_date_header.xml
new file mode 100644
index 0000000..fd6f826
--- /dev/null
+++ b/res/layout/item_date_header.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 20121 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/date_header_title"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/picker_date_header_height"
+ android:padding="@dimen/picker_date_header_padding"
+ android:textAppearance="@style/PickerDateHeader"/>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index e593c25..8714efc 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -25,6 +25,7 @@
<color name="picker_primary_color">#1A73E8</color>
<color name="picker_background_color">@android:color/white</color>
<color name="picker_highlight_color">#E8F0FE</color>
+ <color name="picker_date_header_text_color">#3C4043</color>
<!-- PhotoPicker Preview -->
<color name="preview_default_blue">#8AB4F8</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 92812ee..28a7b60 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -31,6 +31,8 @@
<dimen name="picker_item_badge_margin">5dp</dimen>
<dimen name="picker_item_badge_text_margin">3dp</dimen>
<dimen name="picker_item_badge_text_size">10dp</dimen>
+ <dimen name="picker_date_header_height">56dp</dimen>
+ <dimen name="picker_date_header_padding">16dp</dimen>
<!-- PhotoPicker Preview -->
<dimen name="preview_buttons_margin_horizontal">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index be3c0a5..22998c6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -88,6 +88,9 @@
<!-- Select button for PhotoPicker. [CHAR LIMIT=30] -->
<string name="select">Select</string>
+ <!-- Recent header for PhotoPicker. [CHAR LIMIT=50] -->
+ <string name="recent">Recent</string>
+
<!-- PhotoPicker view selected action text. [CHAR LIMIT=80] -->
<string name="picker_view_selected">View selected</string>
diff --git a/res/values/styles_text.xml b/res/values/styles_text.xml
new file mode 100644
index 0000000..710631a
--- /dev/null
+++ b/res/values/styles_text.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <style name="PickerDateHeader" parent="@android:style/TextAppearance.Material.Title">
+ <item name="android:textColor">@color/picker_date_header_text_color</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+
+</resources>
diff --git a/src/com/android/providers/media/photopicker/DateTimeUtils.java b/src/com/android/providers/media/photopicker/DateTimeUtils.java
new file mode 100644
index 0000000..f7e0f00
--- /dev/null
+++ b/src/com/android/providers/media/photopicker/DateTimeUtils.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker;
+
+import static android.icu.text.DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE;
+import static android.icu.text.RelativeDateTimeFormatter.Style.LONG;
+
+import android.content.Context;
+import android.icu.text.RelativeDateTimeFormatter;
+import android.icu.text.RelativeDateTimeFormatter.Direction;
+import android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit;
+import android.icu.util.ULocale;
+import android.text.format.DateUtils;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoUnit;
+import java.util.Locale;
+
+/**
+ * Provide the utility methods to handle date time.
+ */
+public class DateTimeUtils {
+
+ /**
+ * Formats a time according to the local conventions.
+ *
+ * If the difference of the date between the time and now is zero, show
+ * "Today".
+ * If the difference is 1, show "Yesterday".
+ * If the difference is less than 7, show the weekday. E.g. "Sunday".
+ * Otherwise, show the weekday and the date. E.g. "Sat, Jun 5".
+ * If they have different years, show the weekday, the date and the year.
+ * E.g. "Sat, Jun 5, 2021"
+ *
+ * @param context the context
+ * @param when the time to be formatted. The unit is in milliseconds
+ * since January 1, 1970 00:00:00.0 UTC.
+ * @return the formatted string
+ */
+ public static String getDateTimeString(Context context, long when) {
+ // Get the system time zone
+ final ZoneId zoneId = ZoneId.systemDefault();
+ final LocalDate nowDate = LocalDate.now(zoneId);
+
+ return getDateTimeString(context, when, nowDate);
+ }
+
+ @VisibleForTesting
+ static String getDateTimeString(Context context, long when, LocalDate nowDate) {
+ // Get the system time zone
+ final ZoneId zoneId = ZoneId.systemDefault();
+ final LocalDate whenDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(when),
+ zoneId).toLocalDate();
+
+ final long dayDiff = ChronoUnit.DAYS.between(whenDate, nowDate);
+ if (dayDiff == 0) {
+ return getTodayString();
+ } else if (dayDiff == 1) {
+ return getYesterdayString();
+ } else if (dayDiff > 0 && dayDiff < 7) {
+ return whenDate.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault());
+ } else {
+ int flags = DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_DATE
+ | DateUtils.FORMAT_ABBREV_ALL;
+ if (whenDate.getYear() == nowDate.getYear()) {
+ flags |= DateUtils.FORMAT_NO_YEAR;
+ } else {
+ flags |= DateUtils.FORMAT_SHOW_YEAR;
+ }
+ return DateUtils.formatDateTime(context, when, flags);
+ }
+ }
+
+ /**
+ * It is borrowed from {@link DateUtils} since it is no official API yet.
+ *
+ * @param oneMillis the first time. The unit is in milliseconds since
+ * January 1, 1970 00:00:00.0 UTC.
+ * @param twoMillis the second time. The unit is in milliseconds since
+ * January 1, 1970 00:00:00.0 UTC.
+ * @return True, the date is the same. Otherwise, return false.
+ */
+ public static boolean isSameDate(long oneMillis, long twoMillis) {
+ // Get the system time zone
+ final ZoneId zoneId = ZoneId.systemDefault();
+
+ final Instant oneInstant = Instant.ofEpochMilli(oneMillis);
+ final LocalDateTime oneLocalDateTime = LocalDateTime.ofInstant(oneInstant, zoneId);
+
+ final Instant twoInstant = Instant.ofEpochMilli(twoMillis);
+ final LocalDateTime twoLocalDateTime = LocalDateTime.ofInstant(twoInstant, zoneId);
+
+ return (oneLocalDateTime.getYear() == twoLocalDateTime.getYear())
+ && (oneLocalDateTime.getMonthValue() == twoLocalDateTime.getMonthValue())
+ && (oneLocalDateTime.getDayOfMonth() == twoLocalDateTime.getDayOfMonth());
+ }
+
+ @VisibleForTesting
+ static String getTodayString() {
+ final RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(
+ ULocale.getDefault(), null, LONG, CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE);
+ return fmt.format(Direction.THIS, AbsoluteUnit.DAY);
+ }
+
+ @VisibleForTesting
+ static String getYesterdayString() {
+ final RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(
+ ULocale.getDefault(), null, LONG, CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE);
+ return fmt.format(Direction.LAST, AbsoluteUnit.DAY);
+ }
+}
diff --git a/src/com/android/providers/media/photopicker/data/model/Item.java b/src/com/android/providers/media/photopicker/data/model/Item.java
index be2910d..b91efe6 100644
--- a/src/com/android/providers/media/photopicker/data/model/Item.java
+++ b/src/com/android/providers/media/photopicker/data/model/Item.java
@@ -67,6 +67,7 @@
private boolean mIsImage;
private boolean mIsVideo;
private boolean mIsGif;
+ private boolean mIsDate;
private Item() {}
@@ -90,6 +91,10 @@
return mIsGif;
}
+ public boolean isDate() {
+ return mIsDate;
+ }
+
public Uri getContentUri() {
return mUri;
}
@@ -116,8 +121,21 @@
public static Item fromCursor(Cursor cursor, UserId userId) {
assert(cursor != null);
- final Item info = new Item(cursor, userId);
- return info;
+ final Item item = new Item(cursor, userId);
+ return item;
+ }
+
+ /**
+ * Return the date item. If dateTaken is 0, it is a recent item.
+ * @param dateTaken the time of date taken. The unit is in milliseconds since
+ * January 1, 1970 00:00:00.0 UTC.
+ * @return the item with date type
+ */
+ public static Item createDateItem(long dateTaken) {
+ final Item item = new Item();
+ item.mIsDate = true;
+ item.mDateTaken = dateTaken;
+ return item;
}
/**
diff --git a/src/com/android/providers/media/photopicker/ui/DateHeaderHolder.java b/src/com/android/providers/media/photopicker/ui/DateHeaderHolder.java
new file mode 100644
index 0000000..b5122a1
--- /dev/null
+++ b/src/com/android/providers/media/photopicker/ui/DateHeaderHolder.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.providers.media.photopicker.ui;
+import android.content.Context;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import com.android.providers.media.R;
+import com.android.providers.media.photopicker.DateTimeUtils;
+import com.android.providers.media.photopicker.data.model.Item;
+
+/**
+ * ViewHolder of a date header within a RecyclerView.
+ */
+public class DateHeaderHolder extends BaseItemHolder {
+ private TextView mTitle;
+ public DateHeaderHolder(Context context, ViewGroup parent) {
+ super(context, parent, R.layout.item_date_header);
+ mTitle = itemView.findViewById(R.id.date_header_title);
+ }
+
+ @Override
+ public void bind() {
+ final Item item = (Item) itemView.getTag();
+ final long dateTaken = item.getDateTaken();
+ if (dateTaken == 0) {
+ mTitle.setText(R.string.recent);
+ } else {
+ mTitle.setText(DateTimeUtils.getDateTimeString(itemView.getContext(), dateTaken));
+ }
+ }
+}
diff --git a/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java b/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java
index 9538a84..b239d52 100644
--- a/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java
+++ b/src/com/android/providers/media/photopicker/ui/PhotosTabAdapter.java
@@ -20,6 +20,7 @@
import android.view.ViewGroup;
import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.providers.media.photopicker.data.model.Item;
@@ -33,6 +34,7 @@
*/
public class PhotosTabAdapter extends RecyclerView.Adapter<BaseItemHolder> {
+ private static final int ITEM_TYPE_DATE_HEADER = 0;
private static final int ITEM_TYPE_PHOTO = 1;
public static final int COLUMN_COUNT = 3;
@@ -52,20 +54,26 @@
@NonNull
@Override
public BaseItemHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
+ if (viewType == ITEM_TYPE_DATE_HEADER) {
+ return new DateHeaderHolder(viewGroup.getContext(), viewGroup);
+ }
return new PhotoGridHolder(viewGroup.getContext(), viewGroup, mImageLoader,
mPickerViewModel.canSelectMultiple());
}
@Override
- public void onBindViewHolder(@NonNull BaseItemHolder photoHolder, int position) {
+ public void onBindViewHolder(@NonNull BaseItemHolder itemHolder, int position) {
final Item item = getItem(position);
- photoHolder.itemView.setTag(item);
- photoHolder.itemView.setOnClickListener(mOnClickListener);
- final boolean isItemSelected =
- mPickerViewModel.getSelectedItems().getValue().containsKey(
- item.getContentUri());
- photoHolder.itemView.setSelected(isItemSelected);
- photoHolder.bind();
+ itemHolder.itemView.setTag(item);
+
+ if (getItemViewType(position) == ITEM_TYPE_PHOTO) {
+ itemHolder.itemView.setOnClickListener(mOnClickListener);
+ final boolean isItemSelected =
+ mPickerViewModel.getSelectedItems().getValue().containsKey(
+ item.getContentUri());
+ itemHolder.itemView.setSelected(isItemSelected);
+ }
+ itemHolder.bind();
}
@Override
@@ -75,6 +83,9 @@
@Override
public int getItemViewType(int position) {
+ if (getItem(position).isDate()) {
+ return ITEM_TYPE_DATE_HEADER;
+ }
return ITEM_TYPE_PHOTO;
}
@@ -86,4 +97,19 @@
mItemList = itemList;
notifyDataSetChanged();
}
+
+ public GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
+ return new GridLayoutManager.SpanSizeLookup() {
+ @Override
+ public int getSpanSize(int position) {
+ // Make layout whitespace span the grid. This has the effect of breaking
+ // grid rows whenever layout whitespace is encountered.
+ if (getItemViewType(position) == ITEM_TYPE_DATE_HEADER) {
+ return COLUMN_COUNT;
+ } else {
+ return 1;
+ }
+ }
+ };
+ }
}
diff --git a/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java b/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
index 30a8cd5..7c344a1 100644
--- a/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
@@ -92,6 +92,10 @@
adapter.updateItemList(itemList);
});
final GridLayoutManager layoutManager = new GridLayoutManager(getContext(), COLUMN_COUNT);
+ final GridLayoutManager.SpanSizeLookup lookup = adapter.createSpanSizeLookup();
+ if (lookup != null) {
+ layoutManager.setSpanSizeLookup(lookup);
+ }
photosList.setLayoutManager(layoutManager);
photosList.setAdapter(adapter);
}
diff --git a/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java b/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java
index c0195e4..93b34a6 100644
--- a/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java
+++ b/src/com/android/providers/media/photopicker/viewmodel/PickerViewModel.java
@@ -27,6 +27,7 @@
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
+import com.android.providers.media.photopicker.DateTimeUtils;
import com.android.providers.media.photopicker.data.ItemsProvider;
import com.android.providers.media.photopicker.data.UserIdManager;
import com.android.providers.media.photopicker.data.model.Item;
@@ -43,6 +44,8 @@
public class PickerViewModel extends AndroidViewModel {
public static final String TAG = "PhotoPicker";
+ private static final int RECENT_MINIMUM_COUNT = 12;
+
private MutableLiveData<List<Item>> mItemList;
private MutableLiveData<Map<Uri, Item>> mSelectedItemList = new MutableLiveData<>();
private final ItemsProvider mItemsProvider;
@@ -116,10 +119,28 @@
return items;
}
+ int recentSize = 0;
+ long currentDateTaken = 0;
+ // add Recent date header
+ items.add(Item.createDateItem(0));
while (cursor.moveToNext()) {
// TODO(b/188394433): Return userId in the cursor so that we do not need to pass it
// here again.
- items.add(Item.fromCursor(cursor, userId));
+ final Item item = Item.fromCursor(cursor, userId);
+ final long dateTaken = item.getDateTaken();
+ // the minimum count of items in recent is not reached
+ if (recentSize < RECENT_MINIMUM_COUNT) {
+ recentSize++;
+ currentDateTaken = dateTaken;
+ }
+
+ // The date taken of these two images are not on the
+ // same day, add the new date header.
+ if (!DateTimeUtils.isSameDate(currentDateTaken, dateTaken)) {
+ items.add(Item.createDateItem(dateTaken));
+ currentDateTaken = dateTaken;
+ }
+ items.add(item);
}
Log.d(TAG, "Loaded " + items.size() + " items for user " + userId.toString());
diff --git a/tests/src/com/android/providers/media/photopicker/DateTimeUtilsTest.java b/tests/src/com/android/providers/media/photopicker/DateTimeUtilsTest.java
new file mode 100644
index 0000000..062d3d4
--- /dev/null
+++ b/tests/src/com/android/providers/media/photopicker/DateTimeUtilsTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.LocalDate;
+import java.time.ZoneOffset;
+
+@RunWith(AndroidJUnit4.class)
+public class DateTimeUtilsTest {
+
+ private Context mContext;
+ private static LocalDate FAKE_DATE =
+ LocalDate.of(2020 /* year */, 7 /* month */, 7 /* dayOfMonth */);
+ private static long FAKE_TIME =
+ FAKE_DATE.atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli();
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ @Test
+ public void testGetDateTimeString_today() throws Exception {
+ final String result = DateTimeUtils.getDateTimeString(mContext, FAKE_TIME, FAKE_DATE);
+
+ assertThat(result).isEqualTo(DateTimeUtils.getTodayString());
+ }
+
+ @Test
+ public void testGetDateTimeString_yesterday() throws Exception {
+ final LocalDate whenDate = FAKE_DATE.minusDays(1);
+ final long when = generateDateTimeMillis(whenDate.getYear(), whenDate.getMonthValue(),
+ whenDate.getDayOfMonth());
+
+ final String result = DateTimeUtils.getDateTimeString(mContext, when, FAKE_DATE);
+
+ assertThat(result).isEqualTo(DateTimeUtils.getYesterdayString());
+ }
+
+ @Test
+ public void testGetDateTimeString_weekday() throws Exception {
+ final LocalDate whenDate = FAKE_DATE.minusDays(3);
+ final long when = generateDateTimeMillis(whenDate.getYear(), whenDate.getMonthValue(),
+ whenDate.getDayOfMonth());
+
+ final String result = DateTimeUtils.getDateTimeString(mContext, when, FAKE_DATE);
+
+ assertThat(result).isEqualTo("Saturday");
+ }
+
+ @Test
+ public void testGetDateTimeString_weekdayAndDate() throws Exception {
+ final LocalDate whenDate = FAKE_DATE.minusMonths(1);
+ final long when = generateDateTimeMillis(whenDate.getYear(), whenDate.getMonthValue(),
+ whenDate.getDayOfMonth());
+
+ final String result = DateTimeUtils.getDateTimeString(mContext, when, FAKE_DATE);
+
+ assertThat(result).isEqualTo("Sun, Jun 7");
+ }
+
+ @Test
+ public void testGetDateTimeString_weekdayDateAndYear() throws Exception {
+ final LocalDate whenDate = FAKE_DATE.minusYears(1);
+ long when = generateDateTimeMillis(whenDate.getYear(), whenDate.getMonthValue(),
+ whenDate.getDayOfMonth());
+
+ final String result = DateTimeUtils.getDateTimeString(mContext, when, FAKE_DATE);
+
+ assertThat(result).isEqualTo("Sun, Jul 7, 2019");
+ }
+
+ @Test
+ public void testIsSameDay_differentYear_false() throws Exception {
+ final LocalDate whenDate = FAKE_DATE.minusYears(1);
+ long when = generateDateTimeMillis(whenDate.getYear(), whenDate.getMonthValue(),
+ whenDate.getDayOfMonth());
+
+ assertThat(DateTimeUtils.isSameDate(when, FAKE_TIME)).isFalse();
+ }
+
+ @Test
+ public void testIsSameDay_differentMonth_false() throws Exception {
+ final LocalDate whenDate = FAKE_DATE.minusMonths(1);
+ final long when = generateDateTimeMillis(whenDate.getYear(), whenDate.getMonthValue(),
+ whenDate.getDayOfMonth());
+
+ assertThat(DateTimeUtils.isSameDate(when, FAKE_TIME)).isFalse();
+ }
+
+ @Test
+ public void testIsSameDay_differentDay_false() throws Exception {
+ final LocalDate whenDate = FAKE_DATE.minusDays(1);
+ final long when = generateDateTimeMillis(whenDate.getYear(), whenDate.getMonthValue(),
+ whenDate.getDayOfMonth());
+
+ assertThat(DateTimeUtils.isSameDate(when, FAKE_TIME)).isFalse();
+ }
+
+ @Test
+ public void testIsSameDay_true() throws Exception {
+ assertThat(DateTimeUtils.isSameDate(FAKE_TIME, FAKE_TIME)).isTrue();
+ }
+
+ private static long generateDateTimeMillis(int year, int month, int dayOfMonth) {
+ final LocalDate result = LocalDate.of(year, month, dayOfMonth);
+ return result.atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli();
+ }
+}
+
diff --git a/tests/src/com/android/providers/media/photopicker/data/model/ItemTest.java b/tests/src/com/android/providers/media/photopicker/data/model/ItemTest.java
index 6c74140..0048327 100644
--- a/tests/src/com/android/providers/media/photopicker/data/model/ItemTest.java
+++ b/tests/src/com/android/providers/media/photopicker/data/model/ItemTest.java
@@ -39,7 +39,6 @@
final String displayName = "123.png";
final String volumeName = "primary";
final long duration = 1000;
-
final Cursor cursor = generateCursorForItem(id, mimeType, displayName, volumeName,
dateTaken, duration);
cursor.moveToFirst();
@@ -54,6 +53,67 @@
assertThat(item.getDuration()).isEqualTo(duration);
}
+ @Test
+ public void testIsImage() {
+ final long id = 1;
+ final long dateTaken = 12345678l;
+ final String mimeType = "image/png";
+ final String displayName = "123.png";
+ final String volumeName = "primary";
+ final long duration = 1000;
+ final Cursor cursor = generateCursorForItem(id, mimeType, displayName, volumeName,
+ dateTaken, duration);
+ cursor.moveToFirst();
+
+ final Item item = new Item(cursor, UserId.CURRENT_USER);
+
+ assertThat(item.isImage()).isTrue();
+ }
+
+ @Test
+ public void testIsVideo() {
+ final long id = 1;
+ final long dateTaken = 12345678l;
+ final String mimeType = "video/mpeg";
+ final String displayName = "123.png";
+ final String volumeName = "primary";
+ final long duration = 1000;
+ final Cursor cursor = generateCursorForItem(id, mimeType, displayName, volumeName,
+ dateTaken, duration);
+ cursor.moveToFirst();
+
+ final Item item = new Item(cursor, UserId.CURRENT_USER);
+
+ assertThat(item.isVideo()).isTrue();
+ }
+
+ @Test
+ public void testIsGif() {
+ final long id = 1;
+ final long dateTaken = 12345678l;
+ final String mimeType = "image/gif";
+ final String displayName = "123.png";
+ final String volumeName = "primary";
+ final long duration = 1000;
+ final Cursor cursor = generateCursorForItem(id, mimeType, displayName, volumeName,
+ dateTaken, duration);
+ cursor.moveToFirst();
+
+ final Item item = new Item(cursor, UserId.CURRENT_USER);
+
+ assertThat(item.isGif()).isTrue();
+ }
+
+ @Test
+ public void testCreateDateItem() {
+ final long dateTaken = 12345678l;
+
+ final Item item = Item.createDateItem(dateTaken);
+
+ assertThat(item.getDateTaken()).isEqualTo(dateTaken);
+ assertThat(item.isDate()).isTrue();
+ }
+
private static Cursor generateCursorForItem(long id, String mimeType,
String displayName, String volumeName, long dateTaken, long duration) {
final MatrixCursor cursor = new MatrixCursor(