From ebd8b1bd7e56151338e18d678b33f3a8f92ff391 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Wed, 16 Oct 2019 19:47:17 -0700 Subject: [PATCH 01/15] Add 12 new parameter support for Android Notifications --- .../messaging/AndroidNotification.java | 252 ++++++++++++++++++ .../firebase/messaging/MessageTest.java | 92 +++++++ 2 files changed, 344 insertions(+) diff --git a/src/main/java/com/google/firebase/messaging/AndroidNotification.java b/src/main/java/com/google/firebase/messaging/AndroidNotification.java index ef286d499..8cefad5cd 100644 --- a/src/main/java/com/google/firebase/messaging/AndroidNotification.java +++ b/src/main/java/com/google/firebase/messaging/AndroidNotification.java @@ -22,7 +22,9 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.firebase.internal.NonNull; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; /** @@ -69,6 +71,39 @@ public class AndroidNotification { @Key("image") private final String image; + + @Key("ticker") + private final String ticker; + + @Key("sticky") + private final Boolean sticky; + + @Key("event_time") + private final String eventTime; + + @Key("local_only") + private final Boolean localOnly; + + @Key("notification_priority") + private final String priority; + + @Key("vibrate_timings") + private final List vibrateTimingsInMillis; + + @Key("default_vibrate_timings") + private final Boolean defaultVibrateTimings; + + @Key("default_sound") + private final Boolean defaultSound; + + @Key("light_settings") + private final LightSettings lightSettings; + + @Key("visibility") + private final String visibility; + + @Key("notification_count") + private final Integer notificationCount; private AndroidNotification(Builder builder) { this.title = builder.title; @@ -101,6 +136,43 @@ private AndroidNotification(Builder builder) { } this.channelId = builder.channelId; this.image = builder.image; + this.ticker = builder.ticker; + this.sticky = builder.sticky; + this.eventTime = builder.eventTime; + this.localOnly = builder.localOnly; + if (builder.priority != null) { + this.priority = builder.priority.name().toLowerCase(); + } else { + this.priority = null; + } + if (!builder.vibrateTimingsInMillis.isEmpty()) { + this.vibrateTimingsInMillis = ImmutableList.copyOf(builder.vibrateTimingsInMillis); + } else { + this.vibrateTimingsInMillis = null; + } + this.defaultVibrateTimings = builder.defaultVibrateTimings; + this.defaultSound = builder.defaultSound; + this.lightSettings = builder.lightSettings; + if (builder.visibility != null) { + this.visibility = builder.visibility.name().toLowerCase(); + } else { + this.visibility = null; + } + this.notificationCount = builder.notificationCount; + } + + public enum Priority { + MIN, + LOW, + DEFAULT, + HIGH, + MAX, + } + + public enum Visibility { + PRIVATE, + PUBLIC, + SECRET, } /** @@ -127,6 +199,17 @@ public static class Builder { private List titleLocArgs = new ArrayList<>(); private String channelId; private String image; + private String ticker; + private Boolean sticky; + private String eventTime; + private Boolean localOnly; + private Priority priority; + private List vibrateTimingsInMillis = new ArrayList<>(); + private Boolean defaultVibrateTimings; + private Boolean defaultSound; + private LightSettings lightSettings; + private Visibility visibility; + private Integer notificationCount; private Builder() {} @@ -309,6 +392,175 @@ public Builder setImage(String imageUrl) { return this; } + /** + * Sets the "ticker" text, which is sent to accessibility services. Prior to API level 21 + * (Lollipop), sets the text that is displayed in the status bar when the notification + * first arrives. + * + * @param ticker Ticker name. + * @return This builder. + */ + public Builder setTicker(String ticker) { + this.ticker = ticker; + return this; + } + + /** + * Sets the sticky flag. When set to false or unset, the notification is automatically + * dismissed when the user clicks it in the panel. When set to true, the notification + * persists even when the user clicks it. + * + * @param sticky The sticky flag + * @return This builder. + */ + public Builder setSticky(Boolean sticky) { + this.sticky = sticky; + return this; + } + + /** + * Sets the time that the event in the notification occurred in milliseconds. Notifications + * in the panel are sorted by this time. The time will be formated in RFC3339 UTC "Zulu" + * format, accurate to nanoseconds. Example: "2014-10-02T15:01:23.045123456Z". Note that + * since the time is in milliseconds, the last section of the time representation always + * has 6 leading zeros. + * + * @param eventTimeInMillis The event time in milliseconds + * @return This builder. + */ + public Builder setEventTimeInMillis(Long eventTimeInMillis) { + this.eventTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'") + .format(new Date(eventTimeInMillis)); + return this; + } + + /** + * Sets whether or not this notification is relevant only to the current device. Some + * notifications can be bridged to other devices for remote display, such as a Wear + * OS watch. This hint can be set to recommend this notification not be bridged. + * + * @param localOnly The "local only" flag + * @return This builder. + */ + public Builder setLocalOnly(Boolean localOnly) { + this.localOnly = localOnly; + return this; + } + + /** + * Sets the relative priority for this notification. Priority is an indication of how much of + * the user's attention should be consumed by this notification. Low-priority notifications + * may be hidden from the user in certain situations, while the user might be interrupted + * for a higher-priority notification. The effect of setting the same priorities may differ + * slightly on different platforms. + * + * @param priority The priority value, one of the values in {MIN, LOW, DEFAULT, HIGH, MAX} + * @return This builder. + */ + public Builder setPriority(Priority priority) { + this.priority = priority; + return this; + } + + /** + * Adds a vibration timing in milliseconds in the array to use. The first value in the + * array indicates the duration to wait before turning the vibrator on. The next value + * indicates the Duration to keep the vibrator on. Subsequent values alternate between + * duration to turn the vibrator off and to turn the vibrator on. If vibrate_timings + * is set and default_vibrate_timings is set to true, the default value is used instead + * of the user-specified vibrate_timings. + * A duration in seconds with up to nine fractional digits, terminated by 's'. Example: "3.5s". + * + * @param vibrateTimingInMillis vibration time in milliseconds. + * @return This builder. + */ + public Builder addVibrateTimingsInMillis(@NonNull Long vibrateTimingInMillis) { + this.vibrateTimingsInMillis.add(vibrateTimingInMillis); + return this; + } + + /** + * Adds a list of vibration timings in milliseconds in the array to use. The first value in the + * array indicates the duration to wait before turning the vibrator on. The next value + * indicates the Duration to keep the vibrator on. Subsequent values alternate between + * duration to turn the vibrator off and to turn the vibrator on. If vibrate_timings + * is set and default_vibrate_timings is set to true, the default value is used instead + * of the user-specified vibrate_timings. + * A duration in seconds with up to nine fractional digits, terminated by 's'. Example: "3.5s". + * + * @param vibrateTimingsInMillis List of vibration time in milliseconds + * @return This builder. + */ + public Builder addAllVibrateTimingInMillis(@NonNull List vibrateTimingsInMillis) { + this.vibrateTimingsInMillis.addAll(vibrateTimingsInMillis); + return this; + } + + /** + * Sets the whether to use the default vibration timings. If set to true, use the Android + * framework's default vibrate pattern for the notification. Default values are specified + * in config.xml. If default_vibrate_timings is set to true and vibrate_timings is also + * set, the default value is used instead of the user-specified vibrate_timings. + * + * @param defaultVibrateTimings The flag incicating whether to use the default vibration timings + * @return This builder. + */ + public Builder setDefaultVibrateTimings(Boolean defaultVibrateTimings) { + this.defaultVibrateTimings = defaultVibrateTimings; + return this; + } + + /** + * Sets the whether to use the default sound. If set to true, use the Android framework's + * default sound for the notification. Default values are specified in config.xml. + * + * @param defaultSound The flag incicating whether to use the default sound + * @return This builder. + */ + public Builder setDefaultSound(Boolean defaultSound) { + this.defaultSound = defaultSound; + return this; + } + + /** + * Sets the settings to control the notification's LED blinking rate and color if LED is + * available on the device. The total blinking time is controlled by the OS. + * + * @param lightSettings The light settings to use + * @return This builder. + */ + public Builder setLightSettings(LightSettings lightSettings) { + this.lightSettings = lightSettings; + return this; + } + + /** + * Sets the visibility of this notification. + * + * @param visibility The visibility value. one of the values in {PRIVATE, PUBLIC, SECRET} + * @return This builder. + */ + public Builder setVisibility(Visibility visibility) { + this.visibility = visibility; + return this; + } + + /** + * Sets the number of items this notification represents. May be displayed as a badge + * count for launchers that support badging.See Notification Badge. For example, this + * might be useful if you're using just one notification to represent multiple new messages + * but you want the count here to represent the number of total new messages. If zero or + * unspecified, systems that support badging use the default, which is to increment a number + * displayed on the long-press menu each time a new notification arrives. + * + * @param notificationCount The notification count + * @return This builder. + */ + public Builder setNotificationCount(Integer notificationCount) { + this.notificationCount = notificationCount; + return this; + } + /** * Creates a new {@link AndroidNotification} instance from the parameters set on this builder. * diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index 556f2d9ea..a8331649a 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -28,6 +28,7 @@ import com.google.firebase.messaging.AndroidConfig.Priority; import java.io.IOException; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -796,6 +797,97 @@ public void testImageInApnsNotification() throws IOException { .build(); assertJsonEquals(expected, message); } + + @Test + public void testInvalidColorInAndroidNotificationLightSettings() throws IOException { + try { + Message.Builder messageBuilder = Message.builder() + .setNotification(new Notification("title", "body")) + .setAndroidConfig(AndroidConfig.builder() + .setNotification(AndroidNotification.builder() + .setTitle("android-title") + .setBody("android-body") + .setLightSettings(LightSettings.builder() + .setColorFromString("#01020K") + .setLightOnDurationInMillis(1002L) + .setLightOffDurationInMillis(1003L) + .build()) + .build()) + .build()) + .setTopic("test-topic"); + + messageBuilder.build(); + fail("No error thrown for invalid notification"); + } catch (IllegalArgumentException expected) { + // expected + } + } + + @Test + public void testExtendedAndroidNotificationParameters() throws IOException { + Message message = Message.builder() + .setNotification(new Notification("title", "body")) + .setAndroidConfig(AndroidConfig.builder() + .setNotification(AndroidNotification.builder() + .setTitle("android-title") + .setBody("android-body") + .setTicker("ticker") + .setSticky(true) + .setEventTimeInMillis(1546304523123L) + .setLocalOnly(true) + .setPriority(AndroidNotification.Priority.HIGH) + .addVibrateTimingsInMillis(1001L) + .setDefaultVibrateTimings(false) + .setDefaultSound(false) + .setLightSettings(LightSettings.builder() + .setColorFromString("#010203") + .setLightOnDurationInMillis(1002L) + .setLightOffDurationInMillis(1003L) + .build()) + .setVisibility(AndroidNotification.Visibility.PUBLIC) + .setNotificationCount(10) + .build()) + .build()) + .setTopic("test-topic") + .build(); + Map notification = ImmutableMap.builder() + .put("title", "title") + .put("body", "body") + .build(); + Map androidConfig = ImmutableMap.builder() + .put("notification", ImmutableMap.builder() + .put("title", "android-title") + .put("body", "android-body") + .put("ticker", "ticker") + .put("sticky", true) + .put("event_time", "2018-12-31T17:02:03.000000123Z") + .put("local_only", true) + .put("notification_priority", "high") + .put("vibrate_timings", ImmutableList.of(new BigDecimal(1001))) + .put("default_vibrate_timings", false) + .put("default_sound", false) + .put("light_settings", ImmutableMap.builder() + .put("color", ImmutableMap.builder() + .put("red", new BigDecimal(new BigInteger("10"), 1)) + .put("green", new BigDecimal(new BigInteger("20"), 1)) + .put("blue", new BigDecimal(new BigInteger("30"), 1)) + .build()) + .put("light_on_duration", ImmutableMap.builder() + .put("seconds", new BigDecimal(1)) + .put("nanos", new BigDecimal(2000)) + .build()) + .put("light_off_duration", ImmutableMap.builder() + .put("seconds", new BigDecimal(1)) + .put("nanos", new BigDecimal(3000)) + .build()) + .build()) + .put("visibility", "public") + .put("notification_count", new BigDecimal(10)) + .build()) + .build(); + assertJsonEquals(ImmutableMap.of( + "topic", "test-topic", "notification", notification, "android", androidConfig), message); + } private static void assertJsonEquals( Map expected, Object actual) throws IOException { From 3cb348d2995ec136c83d620c49ec24c753a1ade9 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Wed, 16 Oct 2019 19:53:46 -0700 Subject: [PATCH 02/15] Add new classes for the new light settings field --- .../com/google/firebase/messaging/Color.java | 81 +++++++++++++ .../google/firebase/messaging/Duration.java | 69 ++++++++++++ .../firebase/messaging/LightSettings.java | 106 ++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100644 src/main/java/com/google/firebase/messaging/Color.java create mode 100644 src/main/java/com/google/firebase/messaging/Duration.java create mode 100644 src/main/java/com/google/firebase/messaging/LightSettings.java diff --git a/src/main/java/com/google/firebase/messaging/Color.java b/src/main/java/com/google/firebase/messaging/Color.java new file mode 100644 index 000000000..734699552 --- /dev/null +++ b/src/main/java/com/google/firebase/messaging/Color.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 Google Inc. + * + * 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.google.firebase.messaging; + +import com.google.api.client.util.Key; + +/** + * A class representing color in LightSettings. + */ +public class Color { + + @Key("red") + private final Float red; + + @Key("green") + private final Float green; + + @Key("blue") + private final Float blue; + + private Color(Builder builder) { + this.red = builder.red; + this.green = builder.green; + this.blue = builder.blue; + } + + /** + * Creates a new {@link Color.Builder}. + * + * @return A {@link Color.Builder} instance. + */ + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private Float red; + private Float green; + private Float blue; + + private Builder() {} + + /** + * Sets the RGB component values with a string. + * + * @param color Color specified in the {@code #rrggbb} format. + * @return This builder. + */ + public Builder fromString(String color) { + this.red = Float.valueOf(color.substring(1,3)); + this.green = Float.valueOf(color.substring(3,5)); + this.blue = Float.valueOf(color.substring(5,7)); + return this; + } + + /** + * Builds a new {@link Color} instance from the fields set on this builder. + * + * @return A non-null {@link Color}. + * @throws IllegalArgumentException If the volume value is out of range. + */ + public Color build() { + return new Color(this); + } + } +} diff --git a/src/main/java/com/google/firebase/messaging/Duration.java b/src/main/java/com/google/firebase/messaging/Duration.java new file mode 100644 index 000000000..3e346f6a8 --- /dev/null +++ b/src/main/java/com/google/firebase/messaging/Duration.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 Google Inc. + * + * 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.google.firebase.messaging; + +import com.google.api.client.util.Key; + +/** + * A class representing duration in an LightSettings. + */ +public class Duration { + + @Key("seconds") + private final Long seconds; + + @Key("nanos") + private final Integer nanos; + + private Duration(Builder builder) { + this.seconds = builder.seconds; + this.nanos = builder.nanos; + } + + /** + * Creates a new {@link Duration.Builder}. + * + * @return A {@link Duration.Builder} instance. + */ + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private Long seconds; + private Integer nanos; + + private Builder() {} + + /** + * Sets the duration in milliseconds. + * + * @param durationInMillis The time duration in milliseconds. + * @return This builder. + */ + public Builder fromLongInMillis(Long durationInMillis) { + this.seconds = durationInMillis / 1000; + this.nanos = (int) (durationInMillis % 1000) * 1000; + return this; + } + + public Duration build() { + return new Duration(this); + } + } +} diff --git a/src/main/java/com/google/firebase/messaging/LightSettings.java b/src/main/java/com/google/firebase/messaging/LightSettings.java new file mode 100644 index 000000000..64246053d --- /dev/null +++ b/src/main/java/com/google/firebase/messaging/LightSettings.java @@ -0,0 +1,106 @@ +/* + * Copyright 2018 Google Inc. + * + * 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.google.firebase.messaging; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.api.client.util.Key; + +/** + * A class representing light settings in an Android Notification. + */ +public class LightSettings { + + @Key("color") + private final Color color; + + @Key("light_on_duration") + private final Duration lightOnDuration; + + @Key("light_off_duration") + private final Duration lightOffDuration; + + private LightSettings(Builder builder) { + this.color = builder.color; + this.lightOnDuration = builder.lightOnDuration; + this.lightOffDuration = builder.lightOffDuration; + } + + /** + * Creates a new {@link LightSettings.Builder}. + * + * @return A {@link LightSettings.Builder} instance. + */ + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private Color color; + private Duration lightOnDuration; + private Duration lightOffDuration; + + private Builder() {} + + /** + * Sets the color value with a string. + * + * @param color Color specified in the {@code #rrggbb} format. + * @return This builder. + */ + public Builder setColorFromString(String color) { + checkArgument(color.matches("^#[0-9a-fA-F]{6}$"), + "color must be in the form #RRGGBB"); + this.color = Color.builder().fromString(color).build(); + return this; + } + + /** + * Sets the light on duration in milliseconds. + * + * @param lightOnDurationInMillis The time duration in milliseconds for the LED light to be on. + * @return This builder. + */ + public Builder setLightOnDurationInMillis(Long lightOnDurationInMillis) { + this.lightOnDuration = Duration.builder().fromLongInMillis(lightOnDurationInMillis).build(); + return this; + } + + /** + * Sets the light off duration in milliseconds. + * + * @param lightOffDurationInMillis The time duration in milliseconds for the LED light to be + * off. + * @return This builder. + */ + public Builder setLightOffDurationInMillis(Long lightOffDurationInMillis) { + this.lightOffDuration = Duration.builder().fromLongInMillis(lightOffDurationInMillis).build(); + return this; + } + + /** + * Builds a new {@link LightSettings} instance from the fields set on this builder. + * + * @return A non-null {@link LightSettings}. + * @throws IllegalArgumentException If the volume value is out of range. + */ + public LightSettings build() { + return new LightSettings(this); + } + } +} From 69de21b421596f4baa897c8358a5fed5ca6a43bd Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Wed, 16 Oct 2019 20:04:10 -0700 Subject: [PATCH 03/15] set time zone in the test to be UTC --- src/test/java/com/google/firebase/messaging/MessageTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index a8331649a..655261d72 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -860,7 +860,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .put("body", "android-body") .put("ticker", "ticker") .put("sticky", true) - .put("event_time", "2018-12-31T17:02:03.000000123Z") + .put("event_time", "2019-01-01T01:02:03.000000123Z") .put("local_only", true) .put("notification_priority", "high") .put("vibrate_timings", ImmutableList.of(new BigDecimal(1001))) From 9e4fcf701b0b990d17ad8884b6d1ebbd9b5dd59b Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Thu, 17 Oct 2019 15:05:33 -0700 Subject: [PATCH 04/15] Add support for defaultLightSettings --- .../messaging/AndroidNotification.java | 21 +++++++++++++++++++ .../firebase/messaging/MessageTest.java | 2 ++ 2 files changed, 23 insertions(+) diff --git a/src/main/java/com/google/firebase/messaging/AndroidNotification.java b/src/main/java/com/google/firebase/messaging/AndroidNotification.java index 8cefad5cd..1ea9500dd 100644 --- a/src/main/java/com/google/firebase/messaging/AndroidNotification.java +++ b/src/main/java/com/google/firebase/messaging/AndroidNotification.java @@ -98,6 +98,9 @@ public class AndroidNotification { @Key("light_settings") private final LightSettings lightSettings; + + @Key("default_light_settings") + private final Boolean defaultLightSettings; @Key("visibility") private final String visibility; @@ -153,6 +156,7 @@ private AndroidNotification(Builder builder) { this.defaultVibrateTimings = builder.defaultVibrateTimings; this.defaultSound = builder.defaultSound; this.lightSettings = builder.lightSettings; + this.defaultLightSettings = builder.defaultLightSettings; if (builder.visibility != null) { this.visibility = builder.visibility.name().toLowerCase(); } else { @@ -208,6 +212,7 @@ public static class Builder { private Boolean defaultVibrateTimings; private Boolean defaultSound; private LightSettings lightSettings; + private Boolean defaultLightSettings; private Visibility visibility; private Integer notificationCount; @@ -534,6 +539,22 @@ public Builder setLightSettings(LightSettings lightSettings) { return this; } + /** + * Sets the whether to use the default light settings. If set to true, use the Android + * framework's default LED light settings for the notification. Default values are + * specified in config.xml. If default_light_settings is set to true and + * light_settings is also set, the user-specified light_settings is used instead of + * the default value. + * + * @param defaultLightSettings The flag incicating whether to use the default light + * settings + * @return This builder. + */ + public Builder setDefaultLightSettings(Boolean defaultLightSettings) { + this.defaultLightSettings = defaultLightSettings; + return this; + } + /** * Sets the visibility of this notification. * diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index 655261d72..739ac1e4d 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -844,6 +844,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .setLightOnDurationInMillis(1002L) .setLightOffDurationInMillis(1003L) .build()) + .setDefaultLightSettings(false) .setVisibility(AndroidNotification.Visibility.PUBLIC) .setNotificationCount(10) .build()) @@ -881,6 +882,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .put("nanos", new BigDecimal(3000)) .build()) .build()) + .put("default_light_settings", false) .put("visibility", "public") .put("notification_count", new BigDecimal(10)) .build()) From c08771d2f9394b23fc219d1c91b207d7a4132fe0 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Fri, 18 Oct 2019 14:02:00 -0700 Subject: [PATCH 05/15] Update Color class to include alpha, address reviewers comments --- .../messaging/AndroidNotification.java | 20 +++--- .../com/google/firebase/messaging/Color.java | 68 ++++++++----------- .../google/firebase/messaging/Duration.java | 47 +++++-------- .../firebase/messaging/LightSettings.java | 10 +-- .../firebase/messaging/MessageTest.java | 25 +++---- 5 files changed, 67 insertions(+), 103 deletions(-) diff --git a/src/main/java/com/google/firebase/messaging/AndroidNotification.java b/src/main/java/com/google/firebase/messaging/AndroidNotification.java index 1ea9500dd..1e74d60e1 100644 --- a/src/main/java/com/google/firebase/messaging/AndroidNotification.java +++ b/src/main/java/com/google/firebase/messaging/AndroidNotification.java @@ -418,7 +418,7 @@ public Builder setTicker(String ticker) { * @param sticky The sticky flag * @return This builder. */ - public Builder setSticky(Boolean sticky) { + public Builder setSticky(boolean sticky) { this.sticky = sticky; return this; } @@ -433,7 +433,7 @@ public Builder setSticky(Boolean sticky) { * @param eventTimeInMillis The event time in milliseconds * @return This builder. */ - public Builder setEventTimeInMillis(Long eventTimeInMillis) { + public Builder setEventTimeInMillis(long eventTimeInMillis) { this.eventTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'") .format(new Date(eventTimeInMillis)); return this; @@ -447,7 +447,7 @@ public Builder setEventTimeInMillis(Long eventTimeInMillis) { * @param localOnly The "local only" flag * @return This builder. */ - public Builder setLocalOnly(Boolean localOnly) { + public Builder setLocalOnly(boolean localOnly) { this.localOnly = localOnly; return this; } @@ -479,7 +479,7 @@ public Builder setPriority(Priority priority) { * @param vibrateTimingInMillis vibration time in milliseconds. * @return This builder. */ - public Builder addVibrateTimingsInMillis(@NonNull Long vibrateTimingInMillis) { + public Builder addVibrateTimingsInMillis(long vibrateTimingInMillis) { this.vibrateTimingsInMillis.add(vibrateTimingInMillis); return this; } @@ -496,8 +496,10 @@ public Builder addVibrateTimingsInMillis(@NonNull Long vibrateTimingInMillis) { * @param vibrateTimingsInMillis List of vibration time in milliseconds * @return This builder. */ - public Builder addAllVibrateTimingInMillis(@NonNull List vibrateTimingsInMillis) { - this.vibrateTimingsInMillis.addAll(vibrateTimingsInMillis); + public Builder addAllVibrateTimingInMillis(long[] vibrateTimingsInMillis) { + for (long value : vibrateTimingsInMillis) { + this.vibrateTimingsInMillis.add(value); + } return this; } @@ -510,7 +512,7 @@ public Builder addAllVibrateTimingInMillis(@NonNull List vibrateTimingsInM * @param defaultVibrateTimings The flag incicating whether to use the default vibration timings * @return This builder. */ - public Builder setDefaultVibrateTimings(Boolean defaultVibrateTimings) { + public Builder setDefaultVibrateTimings(boolean defaultVibrateTimings) { this.defaultVibrateTimings = defaultVibrateTimings; return this; } @@ -522,7 +524,7 @@ public Builder setDefaultVibrateTimings(Boolean defaultVibrateTimings) { * @param defaultSound The flag incicating whether to use the default sound * @return This builder. */ - public Builder setDefaultSound(Boolean defaultSound) { + public Builder setDefaultSound(boolean defaultSound) { this.defaultSound = defaultSound; return this; } @@ -550,7 +552,7 @@ public Builder setLightSettings(LightSettings lightSettings) { * settings * @return This builder. */ - public Builder setDefaultLightSettings(Boolean defaultLightSettings) { + public Builder setDefaultLightSettings(boolean defaultLightSettings) { this.defaultLightSettings = defaultLightSettings; return this; } diff --git a/src/main/java/com/google/firebase/messaging/Color.java b/src/main/java/com/google/firebase/messaging/Color.java index 734699552..86a5778cc 100644 --- a/src/main/java/com/google/firebase/messaging/Color.java +++ b/src/main/java/com/google/firebase/messaging/Color.java @@ -16,6 +16,8 @@ package com.google.firebase.messaging; +import static com.google.common.base.Preconditions.checkArgument; + import com.google.api.client.util.Key; /** @@ -32,50 +34,38 @@ public class Color { @Key("blue") private final Float blue; - private Color(Builder builder) { - this.red = builder.red; - this.green = builder.green; - this.blue = builder.blue; - } + @Key("alpha") + private final Float alpha; /** - * Creates a new {@link Color.Builder}. + * Creates a new {@link Color} using the given red, green, blue, and + * alpha values. * - * @return A {@link Color.Builder} instance. + * @param red The red component. + * @param green The green component. + * @param blue The blue component. + * @param alpha The alpha component. */ - public static Builder builder() { - return new Builder(); + public Color(float red, float green, float blue, float alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; } - - public static class Builder { - - private Float red; - private Float green; - private Float blue; - - private Builder() {} - /** - * Sets the RGB component values with a string. - * - * @param color Color specified in the {@code #rrggbb} format. - * @return This builder. - */ - public Builder fromString(String color) { - this.red = Float.valueOf(color.substring(1,3)); - this.green = Float.valueOf(color.substring(3,5)); - this.blue = Float.valueOf(color.substring(5,7)); - return this; - } - - /** - * Builds a new {@link Color} instance from the fields set on this builder. - * - * @return A non-null {@link Color}. - * @throws IllegalArgumentException If the volume value is out of range. - */ - public Color build() { - return new Color(this); - } + /** + * Creates a new {@link Color} with a string. Alpha of the color will be + * set to 1. + * + * @param rrggbb Color specified in the {@code #rrggbb} format. + * @return A {@link Color} instance. + */ + public static Color fromString(String rrggbb) { + checkArgument(rrggbb.matches("^#[0-9a-fA-F]{6}$"), + "color must be in the form #RRGGBB"); + float red = (float) Integer.parseInt(rrggbb.substring(1, 3), 16) / 255.0f; + float green = (float) Integer.valueOf(rrggbb.substring(3, 5), 16) / 255.0f; + float blue = (float) Integer.valueOf(rrggbb.substring(5, 7), 16) / 255.0f; + return new Color(red, green, blue, 1.0f); } } diff --git a/src/main/java/com/google/firebase/messaging/Duration.java b/src/main/java/com/google/firebase/messaging/Duration.java index 3e346f6a8..cc31e13a1 100644 --- a/src/main/java/com/google/firebase/messaging/Duration.java +++ b/src/main/java/com/google/firebase/messaging/Duration.java @@ -29,41 +29,26 @@ public class Duration { @Key("nanos") private final Integer nanos; - private Duration(Builder builder) { - this.seconds = builder.seconds; - this.nanos = builder.nanos; - } - /** - * Creates a new {@link Duration.Builder}. + * Creates a new {@link Duration} using the given seconds and nanoseconds. * - * @return A {@link Duration.Builder} instance. + * @param seconds The time duration in seconds. + * @param nanos The time duration fraction nanoseconds. */ - public static Builder builder() { - return new Builder(); + public Duration(long seconds, int nanos) { + this.seconds = seconds; + this.nanos = nanos; } - public static class Builder { - - private Long seconds; - private Integer nanos; - - private Builder() {} - - /** - * Sets the duration in milliseconds. - * - * @param durationInMillis The time duration in milliseconds. - * @return This builder. - */ - public Builder fromLongInMillis(Long durationInMillis) { - this.seconds = durationInMillis / 1000; - this.nanos = (int) (durationInMillis % 1000) * 1000; - return this; - } - - public Duration build() { - return new Duration(this); - } + /** + * Creates a new {@link Duration} using the given duration in milliseconds. + * + * @param durationInMillis The time duration in milliseconds. + * @return A {@link Duration} instance. + */ + public static Duration fromLongInMillis(Long durationInMillis) { + long seconds = durationInMillis / 1000; + int nanos = (int) (durationInMillis % 1000) * 1000; + return new Duration(seconds, nanos); } } diff --git a/src/main/java/com/google/firebase/messaging/LightSettings.java b/src/main/java/com/google/firebase/messaging/LightSettings.java index 64246053d..ad3fcede7 100644 --- a/src/main/java/com/google/firebase/messaging/LightSettings.java +++ b/src/main/java/com/google/firebase/messaging/LightSettings.java @@ -16,8 +16,6 @@ package com.google.firebase.messaging; -import static com.google.common.base.Preconditions.checkArgument; - import com.google.api.client.util.Key; /** @@ -64,9 +62,7 @@ private Builder() {} * @return This builder. */ public Builder setColorFromString(String color) { - checkArgument(color.matches("^#[0-9a-fA-F]{6}$"), - "color must be in the form #RRGGBB"); - this.color = Color.builder().fromString(color).build(); + this.color = Color.fromString(color); return this; } @@ -77,7 +73,7 @@ public Builder setColorFromString(String color) { * @return This builder. */ public Builder setLightOnDurationInMillis(Long lightOnDurationInMillis) { - this.lightOnDuration = Duration.builder().fromLongInMillis(lightOnDurationInMillis).build(); + this.lightOnDuration = Duration.fromLongInMillis(lightOnDurationInMillis); return this; } @@ -89,7 +85,7 @@ public Builder setLightOnDurationInMillis(Long lightOnDurationInMillis) { * @return This builder. */ public Builder setLightOffDurationInMillis(Long lightOffDurationInMillis) { - this.lightOffDuration = Duration.builder().fromLongInMillis(lightOffDurationInMillis).build(); + this.lightOffDuration = Duration.fromLongInMillis(lightOffDurationInMillis); return this; } diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index 739ac1e4d..2fa12be54 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -801,22 +801,12 @@ public void testImageInApnsNotification() throws IOException { @Test public void testInvalidColorInAndroidNotificationLightSettings() throws IOException { try { - Message.Builder messageBuilder = Message.builder() - .setNotification(new Notification("title", "body")) - .setAndroidConfig(AndroidConfig.builder() - .setNotification(AndroidNotification.builder() - .setTitle("android-title") - .setBody("android-body") - .setLightSettings(LightSettings.builder() + LightSettings.Builder lightSettingsBuilder = LightSettings.builder() .setColorFromString("#01020K") .setLightOnDurationInMillis(1002L) - .setLightOffDurationInMillis(1003L) - .build()) - .build()) - .build()) - .setTopic("test-topic"); + .setLightOffDurationInMillis(1003L); - messageBuilder.build(); + lightSettingsBuilder.build(); fail("No error thrown for invalid notification"); } catch (IllegalArgumentException expected) { // expected @@ -840,7 +830,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .setDefaultVibrateTimings(false) .setDefaultSound(false) .setLightSettings(LightSettings.builder() - .setColorFromString("#010203") + .setColorFromString("#336699") .setLightOnDurationInMillis(1002L) .setLightOffDurationInMillis(1003L) .build()) @@ -869,9 +859,10 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .put("default_sound", false) .put("light_settings", ImmutableMap.builder() .put("color", ImmutableMap.builder() - .put("red", new BigDecimal(new BigInteger("10"), 1)) - .put("green", new BigDecimal(new BigInteger("20"), 1)) - .put("blue", new BigDecimal(new BigInteger("30"), 1)) + .put("red", new BigDecimal(new BigInteger("2"), 1)) + .put("green", new BigDecimal(new BigInteger("4"), 1)) + .put("blue", new BigDecimal(new BigInteger("6"), 1)) + .put("alpha", new BigDecimal(new BigInteger("10"), 1)) .build()) .put("light_on_duration", ImmutableMap.builder() .put("seconds", new BigDecimal(1)) From d5096ccc2e6742fcca28f94ec2063c5dee926f33 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Fri, 18 Oct 2019 14:39:56 -0700 Subject: [PATCH 06/15] Remove Duration class, use String to represent lightOn/OffDuration and vibrateTiming --- .../messaging/AndroidNotification.java | 29 +++++++--- .../google/firebase/messaging/Duration.java | 54 ------------------- .../firebase/messaging/LightSettings.java | 35 +++++++++--- .../firebase/messaging/MessageTest.java | 12 ++--- 4 files changed, 52 insertions(+), 78 deletions(-) delete mode 100644 src/main/java/com/google/firebase/messaging/Duration.java diff --git a/src/main/java/com/google/firebase/messaging/AndroidNotification.java b/src/main/java/com/google/firebase/messaging/AndroidNotification.java index 1e74d60e1..6210a739a 100644 --- a/src/main/java/com/google/firebase/messaging/AndroidNotification.java +++ b/src/main/java/com/google/firebase/messaging/AndroidNotification.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.concurrent.TimeUnit; /** * Represents the Android-specific notification options that can be included in a {@link Message}. @@ -88,7 +89,7 @@ public class AndroidNotification { private final String priority; @Key("vibrate_timings") - private final List vibrateTimingsInMillis; + private final List vibrateTimings; @Key("default_vibrate_timings") private final Boolean defaultVibrateTimings; @@ -148,10 +149,10 @@ private AndroidNotification(Builder builder) { } else { this.priority = null; } - if (!builder.vibrateTimingsInMillis.isEmpty()) { - this.vibrateTimingsInMillis = ImmutableList.copyOf(builder.vibrateTimingsInMillis); + if (!builder.vibrateTimings.isEmpty()) { + this.vibrateTimings = ImmutableList.copyOf(builder.vibrateTimings); } else { - this.vibrateTimingsInMillis = null; + this.vibrateTimings = null; } this.defaultVibrateTimings = builder.defaultVibrateTimings; this.defaultSound = builder.defaultSound; @@ -208,7 +209,7 @@ public static class Builder { private String eventTime; private Boolean localOnly; private Priority priority; - private List vibrateTimingsInMillis = new ArrayList<>(); + private List vibrateTimings = new ArrayList<>(); private Boolean defaultVibrateTimings; private Boolean defaultSound; private LightSettings lightSettings; @@ -480,7 +481,14 @@ public Builder setPriority(Priority priority) { * @return This builder. */ public Builder addVibrateTimingsInMillis(long vibrateTimingInMillis) { - this.vibrateTimingsInMillis.add(vibrateTimingInMillis); + checkArgument(vibrateTimingInMillis >= 0, "vibrateTimingInMillis must not be negative"); + long seconds = TimeUnit.MILLISECONDS.toSeconds(vibrateTimingInMillis); + long subsecondNanos = TimeUnit.MILLISECONDS.toNanos(vibrateTimingInMillis - seconds * 1000L); + if (subsecondNanos > 0) { + this.vibrateTimings.add(String.format("%d.%09ds", seconds, subsecondNanos)); + } else { + this.vibrateTimings.add(String.format("%ds", seconds)); + } return this; } @@ -498,7 +506,14 @@ public Builder addVibrateTimingsInMillis(long vibrateTimingInMillis) { */ public Builder addAllVibrateTimingInMillis(long[] vibrateTimingsInMillis) { for (long value : vibrateTimingsInMillis) { - this.vibrateTimingsInMillis.add(value); + checkArgument(value >= 0, "elements in vibrateTimingsInMillis must not be negative"); + long seconds = TimeUnit.MILLISECONDS.toSeconds(value); + long subsecondNanos = TimeUnit.MILLISECONDS.toNanos(value - seconds * 1000L); + if (subsecondNanos > 0) { + this.vibrateTimings.add(String.format("%d.%09ds", seconds, subsecondNanos)); + } else { + this.vibrateTimings.add(String.format("%ds", seconds)); + } } return this; } diff --git a/src/main/java/com/google/firebase/messaging/Duration.java b/src/main/java/com/google/firebase/messaging/Duration.java deleted file mode 100644 index cc31e13a1..000000000 --- a/src/main/java/com/google/firebase/messaging/Duration.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * 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.google.firebase.messaging; - -import com.google.api.client.util.Key; - -/** - * A class representing duration in an LightSettings. - */ -public class Duration { - - @Key("seconds") - private final Long seconds; - - @Key("nanos") - private final Integer nanos; - - /** - * Creates a new {@link Duration} using the given seconds and nanoseconds. - * - * @param seconds The time duration in seconds. - * @param nanos The time duration fraction nanoseconds. - */ - public Duration(long seconds, int nanos) { - this.seconds = seconds; - this.nanos = nanos; - } - - /** - * Creates a new {@link Duration} using the given duration in milliseconds. - * - * @param durationInMillis The time duration in milliseconds. - * @return A {@link Duration} instance. - */ - public static Duration fromLongInMillis(Long durationInMillis) { - long seconds = durationInMillis / 1000; - int nanos = (int) (durationInMillis % 1000) * 1000; - return new Duration(seconds, nanos); - } -} diff --git a/src/main/java/com/google/firebase/messaging/LightSettings.java b/src/main/java/com/google/firebase/messaging/LightSettings.java index ad3fcede7..a98fd8e55 100644 --- a/src/main/java/com/google/firebase/messaging/LightSettings.java +++ b/src/main/java/com/google/firebase/messaging/LightSettings.java @@ -16,7 +16,10 @@ package com.google.firebase.messaging; +import static com.google.common.base.Preconditions.checkArgument; + import com.google.api.client.util.Key; +import java.util.concurrent.TimeUnit; /** * A class representing light settings in an Android Notification. @@ -27,10 +30,10 @@ public class LightSettings { private final Color color; @Key("light_on_duration") - private final Duration lightOnDuration; + private final String lightOnDuration; @Key("light_off_duration") - private final Duration lightOffDuration; + private final String lightOffDuration; private LightSettings(Builder builder) { this.color = builder.color; @@ -50,8 +53,8 @@ public static Builder builder() { public static class Builder { private Color color; - private Duration lightOnDuration; - private Duration lightOffDuration; + private String lightOnDuration; + private String lightOffDuration; private Builder() {} @@ -72,8 +75,16 @@ public Builder setColorFromString(String color) { * @param lightOnDurationInMillis The time duration in milliseconds for the LED light to be on. * @return This builder. */ - public Builder setLightOnDurationInMillis(Long lightOnDurationInMillis) { - this.lightOnDuration = Duration.fromLongInMillis(lightOnDurationInMillis); + public Builder setLightOnDurationInMillis(long lightOnDurationInMillis) { + checkArgument(lightOnDurationInMillis >= 0, "ttl must not be negative"); + long seconds = TimeUnit.MILLISECONDS.toSeconds(lightOnDurationInMillis); + long subsecondNanos = TimeUnit.MILLISECONDS + .toNanos(lightOnDurationInMillis - seconds * 1000L); + if (subsecondNanos > 0) { + this.lightOnDuration = String.format("%d.%09ds", seconds, subsecondNanos); + } else { + this.lightOnDuration = String.format("%ds", seconds); + } return this; } @@ -84,8 +95,16 @@ public Builder setLightOnDurationInMillis(Long lightOnDurationInMillis) { * off. * @return This builder. */ - public Builder setLightOffDurationInMillis(Long lightOffDurationInMillis) { - this.lightOffDuration = Duration.fromLongInMillis(lightOffDurationInMillis); + public Builder setLightOffDurationInMillis(long lightOffDurationInMillis) { + checkArgument(lightOffDurationInMillis >= 0, "ttl must not be negative"); + long seconds = TimeUnit.MILLISECONDS.toSeconds(lightOffDurationInMillis); + long subsecondNanos = TimeUnit.MILLISECONDS + .toNanos(lightOffDurationInMillis - seconds * 1000L); + if (subsecondNanos > 0) { + this.lightOffDuration = String.format("%d.%09ds", seconds, subsecondNanos); + } else { + this.lightOffDuration = String.format("%ds", seconds); + } return this; } diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index 2fa12be54..2983adedf 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -854,7 +854,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .put("event_time", "2019-01-01T01:02:03.000000123Z") .put("local_only", true) .put("notification_priority", "high") - .put("vibrate_timings", ImmutableList.of(new BigDecimal(1001))) + .put("vibrate_timings", ImmutableList.of("1.001000000s")) .put("default_vibrate_timings", false) .put("default_sound", false) .put("light_settings", ImmutableMap.builder() @@ -864,14 +864,8 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .put("blue", new BigDecimal(new BigInteger("6"), 1)) .put("alpha", new BigDecimal(new BigInteger("10"), 1)) .build()) - .put("light_on_duration", ImmutableMap.builder() - .put("seconds", new BigDecimal(1)) - .put("nanos", new BigDecimal(2000)) - .build()) - .put("light_off_duration", ImmutableMap.builder() - .put("seconds", new BigDecimal(1)) - .put("nanos", new BigDecimal(3000)) - .build()) + .put("light_on_duration", "1.002000000s") + .put("light_off_duration", "1.003000000s") .build()) .put("default_light_settings", false) .put("visibility", "public") From 92b7990494bb8bb950286af8ac52658cdef5a396 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Sat, 19 Oct 2019 14:16:51 -0700 Subject: [PATCH 07/15] Address reviewer's comments --- .../messaging/AndroidNotification.java | 36 ++++------------ .../com/google/firebase/messaging/Color.java | 4 +- .../firebase/messaging/LightSettings.java | 41 +++++++++++-------- .../firebase/messaging/MessageTest.java | 5 ++- 4 files changed, 36 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/google/firebase/messaging/AndroidNotification.java b/src/main/java/com/google/firebase/messaging/AndroidNotification.java index 6210a739a..cbe37ba99 100644 --- a/src/main/java/com/google/firebase/messaging/AndroidNotification.java +++ b/src/main/java/com/google/firebase/messaging/AndroidNotification.java @@ -469,31 +469,7 @@ public Builder setPriority(Priority priority) { } /** - * Adds a vibration timing in milliseconds in the array to use. The first value in the - * array indicates the duration to wait before turning the vibrator on. The next value - * indicates the Duration to keep the vibrator on. Subsequent values alternate between - * duration to turn the vibrator off and to turn the vibrator on. If vibrate_timings - * is set and default_vibrate_timings is set to true, the default value is used instead - * of the user-specified vibrate_timings. - * A duration in seconds with up to nine fractional digits, terminated by 's'. Example: "3.5s". - * - * @param vibrateTimingInMillis vibration time in milliseconds. - * @return This builder. - */ - public Builder addVibrateTimingsInMillis(long vibrateTimingInMillis) { - checkArgument(vibrateTimingInMillis >= 0, "vibrateTimingInMillis must not be negative"); - long seconds = TimeUnit.MILLISECONDS.toSeconds(vibrateTimingInMillis); - long subsecondNanos = TimeUnit.MILLISECONDS.toNanos(vibrateTimingInMillis - seconds * 1000L); - if (subsecondNanos > 0) { - this.vibrateTimings.add(String.format("%d.%09ds", seconds, subsecondNanos)); - } else { - this.vibrateTimings.add(String.format("%ds", seconds)); - } - return this; - } - - /** - * Adds a list of vibration timings in milliseconds in the array to use. The first value in the + * Sets a list of vibration timings in milliseconds in the array to use. The first value in the * array indicates the duration to wait before turning the vibrator on. The next value * indicates the Duration to keep the vibrator on. Subsequent values alternate between * duration to turn the vibrator off and to turn the vibrator on. If vibrate_timings @@ -504,17 +480,19 @@ public Builder addVibrateTimingsInMillis(long vibrateTimingInMillis) { * @param vibrateTimingsInMillis List of vibration time in milliseconds * @return This builder. */ - public Builder addAllVibrateTimingInMillis(long[] vibrateTimingsInMillis) { + public Builder setVibrateTimingsInMillis(long[] vibrateTimingsInMillis) { + List list = new ArrayList<>(); for (long value : vibrateTimingsInMillis) { checkArgument(value >= 0, "elements in vibrateTimingsInMillis must not be negative"); long seconds = TimeUnit.MILLISECONDS.toSeconds(value); long subsecondNanos = TimeUnit.MILLISECONDS.toNanos(value - seconds * 1000L); if (subsecondNanos > 0) { - this.vibrateTimings.add(String.format("%d.%09ds", seconds, subsecondNanos)); + list.add(String.format("%d.%09ds", seconds, subsecondNanos)); } else { - this.vibrateTimings.add(String.format("%ds", seconds)); + list.add(String.format("%ds", seconds)); } } + this.vibrateTimings = ImmutableList.copyOf(list); return this; } @@ -594,7 +572,7 @@ public Builder setVisibility(Visibility visibility) { * @param notificationCount The notification count * @return This builder. */ - public Builder setNotificationCount(Integer notificationCount) { + public Builder setNotificationCount(int notificationCount) { this.notificationCount = notificationCount; return this; } diff --git a/src/main/java/com/google/firebase/messaging/Color.java b/src/main/java/com/google/firebase/messaging/Color.java index 86a5778cc..2631490ab 100644 --- a/src/main/java/com/google/firebase/messaging/Color.java +++ b/src/main/java/com/google/firebase/messaging/Color.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Google Inc. + * Copyright 2019 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ /** * A class representing color in LightSettings. */ -public class Color { +public final class Color { @Key("red") private final Float red; diff --git a/src/main/java/com/google/firebase/messaging/LightSettings.java b/src/main/java/com/google/firebase/messaging/LightSettings.java index a98fd8e55..c86d9362c 100644 --- a/src/main/java/com/google/firebase/messaging/LightSettings.java +++ b/src/main/java/com/google/firebase/messaging/LightSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Google Inc. + * Copyright 2019 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ /** * A class representing light settings in an Android Notification. */ -public class LightSettings { +public final class LightSettings { @Key("color") private final Color color; @@ -68,6 +68,17 @@ public Builder setColorFromString(String color) { this.color = Color.fromString(color); return this; } + + /** + * Sets the color value in the light settings. + * + * @param color Color to be used in the light settings. + * @return This builder. + */ + public Builder setColorFromString(Color color) { + this.color = color; + return this; + } /** * Sets the light on duration in milliseconds. @@ -76,15 +87,7 @@ public Builder setColorFromString(String color) { * @return This builder. */ public Builder setLightOnDurationInMillis(long lightOnDurationInMillis) { - checkArgument(lightOnDurationInMillis >= 0, "ttl must not be negative"); - long seconds = TimeUnit.MILLISECONDS.toSeconds(lightOnDurationInMillis); - long subsecondNanos = TimeUnit.MILLISECONDS - .toNanos(lightOnDurationInMillis - seconds * 1000L); - if (subsecondNanos > 0) { - this.lightOnDuration = String.format("%d.%09ds", seconds, subsecondNanos); - } else { - this.lightOnDuration = String.format("%ds", seconds); - } + this.lightOnDuration = convertToSecondsAndNanosFormat(lightOnDurationInMillis); return this; } @@ -96,16 +99,20 @@ public Builder setLightOnDurationInMillis(long lightOnDurationInMillis) { * @return This builder. */ public Builder setLightOffDurationInMillis(long lightOffDurationInMillis) { - checkArgument(lightOffDurationInMillis >= 0, "ttl must not be negative"); - long seconds = TimeUnit.MILLISECONDS.toSeconds(lightOffDurationInMillis); + this.lightOffDuration = convertToSecondsAndNanosFormat(lightOffDurationInMillis); + return this; + } + + private String convertToSecondsAndNanosFormat(long millis) { + checkArgument(millis >= 0, "ttl must not be negative"); + long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); long subsecondNanos = TimeUnit.MILLISECONDS - .toNanos(lightOffDurationInMillis - seconds * 1000L); + .toNanos(millis - seconds * 1000L); if (subsecondNanos > 0) { - this.lightOffDuration = String.format("%d.%09ds", seconds, subsecondNanos); + return String.format("%d.%09ds", seconds, subsecondNanos); } else { - this.lightOffDuration = String.format("%ds", seconds); + return String.format("%ds", seconds); } - return this; } /** diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index 2983adedf..09cdb24d3 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -815,6 +815,7 @@ public void testInvalidColorInAndroidNotificationLightSettings() throws IOExcept @Test public void testExtendedAndroidNotificationParameters() throws IOException { + long[] vibrateTimings = {1000L, 1001L}; Message message = Message.builder() .setNotification(new Notification("title", "body")) .setAndroidConfig(AndroidConfig.builder() @@ -826,7 +827,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .setEventTimeInMillis(1546304523123L) .setLocalOnly(true) .setPriority(AndroidNotification.Priority.HIGH) - .addVibrateTimingsInMillis(1001L) + .setVibrateTimingsInMillis(vibrateTimings) .setDefaultVibrateTimings(false) .setDefaultSound(false) .setLightSettings(LightSettings.builder() @@ -854,7 +855,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .put("event_time", "2019-01-01T01:02:03.000000123Z") .put("local_only", true) .put("notification_priority", "high") - .put("vibrate_timings", ImmutableList.of("1.001000000s")) + .put("vibrate_timings", ImmutableList.of("1s", "1.001000000s")) .put("default_vibrate_timings", false) .put("default_sound", false) .put("light_settings", ImmutableMap.builder() From 6e25179321eff26efdf691e0afcffff5c72f525b Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Mon, 21 Oct 2019 10:46:49 -0700 Subject: [PATCH 08/15] Add priority mapping so the priority values are with the prefix "PRIORITY_" --- .../firebase/messaging/AndroidNotification.java | 13 ++++++++++++- .../com/google/firebase/messaging/MessageTest.java | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/google/firebase/messaging/AndroidNotification.java b/src/main/java/com/google/firebase/messaging/AndroidNotification.java index cbe37ba99..3e501fd2f 100644 --- a/src/main/java/com/google/firebase/messaging/AndroidNotification.java +++ b/src/main/java/com/google/firebase/messaging/AndroidNotification.java @@ -21,11 +21,13 @@ import com.google.api.client.util.Key; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.firebase.internal.NonNull; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; /** @@ -145,7 +147,7 @@ private AndroidNotification(Builder builder) { this.eventTime = builder.eventTime; this.localOnly = builder.localOnly; if (builder.priority != null) { - this.priority = builder.priority.name().toLowerCase(); + this.priority = PRIORITY_MAP.get(builder.priority); } else { this.priority = null; } @@ -180,6 +182,15 @@ public enum Visibility { SECRET, } + private static final Map PRIORITY_MAP = + ImmutableMap.builder() + .put(Priority.MIN, "PRIORITY_MIN") + .put(Priority.LOW, "PRIORITY_LOW") + .put(Priority.DEFAULT, "PRIORITY_DEFAULT") + .put(Priority.HIGH, "PRIORITY_HIGH") + .put(Priority.MAX, "PRIORITY_MAX") + .build(); + /** * Creates a new {@link AndroidNotification.Builder}. * diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index 09cdb24d3..74f133a53 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -854,7 +854,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .put("sticky", true) .put("event_time", "2019-01-01T01:02:03.000000123Z") .put("local_only", true) - .put("notification_priority", "high") + .put("notification_priority", "PRIORITY_HIGH") .put("vibrate_timings", ImmutableList.of("1s", "1.001000000s")) .put("default_vibrate_timings", false) .put("default_sound", false) From 62dac2b3ef238e0829c776038d3da1c40e7ecf15 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Mon, 21 Oct 2019 16:01:23 -0700 Subject: [PATCH 09/15] address reviewer's comments --- .../messaging/AndroidNotification.java | 27 +++++++++++-------- .../firebase/messaging/LightSettings.java | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/google/firebase/messaging/AndroidNotification.java b/src/main/java/com/google/firebase/messaging/AndroidNotification.java index 3e501fd2f..c80285aac 100644 --- a/src/main/java/com/google/firebase/messaging/AndroidNotification.java +++ b/src/main/java/com/google/firebase/messaging/AndroidNotification.java @@ -111,6 +111,15 @@ public class AndroidNotification { @Key("notification_count") private final Integer notificationCount; + private static final Map PRIORITY_MAP = + ImmutableMap.builder() + .put(Priority.MIN, "PRIORITY_MIN") + .put(Priority.LOW, "PRIORITY_LOW") + .put(Priority.DEFAULT, "PRIORITY_DEFAULT") + .put(Priority.HIGH, "PRIORITY_HIGH") + .put(Priority.MAX, "PRIORITY_MAX") + .build(); + private AndroidNotification(Builder builder) { this.title = builder.title; this.body = builder.body; @@ -147,7 +156,7 @@ private AndroidNotification(Builder builder) { this.eventTime = builder.eventTime; this.localOnly = builder.localOnly; if (builder.priority != null) { - this.priority = PRIORITY_MAP.get(builder.priority); + this.priority = builder.priority.toString(); } else { this.priority = null; } @@ -173,7 +182,12 @@ public enum Priority { LOW, DEFAULT, HIGH, - MAX, + MAX; + + @Override + public String toString() { + return PRIORITY_MAP.get(this); + } } public enum Visibility { @@ -182,15 +196,6 @@ public enum Visibility { SECRET, } - private static final Map PRIORITY_MAP = - ImmutableMap.builder() - .put(Priority.MIN, "PRIORITY_MIN") - .put(Priority.LOW, "PRIORITY_LOW") - .put(Priority.DEFAULT, "PRIORITY_DEFAULT") - .put(Priority.HIGH, "PRIORITY_HIGH") - .put(Priority.MAX, "PRIORITY_MAX") - .build(); - /** * Creates a new {@link AndroidNotification.Builder}. * diff --git a/src/main/java/com/google/firebase/messaging/LightSettings.java b/src/main/java/com/google/firebase/messaging/LightSettings.java index c86d9362c..7dd812d4b 100644 --- a/src/main/java/com/google/firebase/messaging/LightSettings.java +++ b/src/main/java/com/google/firebase/messaging/LightSettings.java @@ -104,7 +104,7 @@ public Builder setLightOffDurationInMillis(long lightOffDurationInMillis) { } private String convertToSecondsAndNanosFormat(long millis) { - checkArgument(millis >= 0, "ttl must not be negative"); + checkArgument(millis >= 0, "Milliseconds duration must not be negative"); long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); long subsecondNanos = TimeUnit.MILLISECONDS .toNanos(millis - seconds * 1000L); From 013e945ced30040bdd9607dc2e156288c97c69e7 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Tue, 22 Oct 2019 13:55:10 -0700 Subject: [PATCH 10/15] address reviewer's comments --- src/main/java/com/google/firebase/messaging/LightSettings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/google/firebase/messaging/LightSettings.java b/src/main/java/com/google/firebase/messaging/LightSettings.java index 7dd812d4b..f8d33ff04 100644 --- a/src/main/java/com/google/firebase/messaging/LightSettings.java +++ b/src/main/java/com/google/firebase/messaging/LightSettings.java @@ -75,7 +75,7 @@ public Builder setColorFromString(String color) { * @param color Color to be used in the light settings. * @return This builder. */ - public Builder setColorFromString(Color color) { + public Builder setColor(Color color) { this.color = color; return this; } From b3bf96b7aba3359de031e6bc9919b45101b90f86 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Tue, 22 Oct 2019 16:30:17 -0700 Subject: [PATCH 11/15] address reviewer's comments --- .../messaging/AndroidNotification.java | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/google/firebase/messaging/AndroidNotification.java b/src/main/java/com/google/firebase/messaging/AndroidNotification.java index c80285aac..adb84c638 100644 --- a/src/main/java/com/google/firebase/messaging/AndroidNotification.java +++ b/src/main/java/com/google/firebase/messaging/AndroidNotification.java @@ -441,8 +441,9 @@ public Builder setSticky(boolean sticky) { } /** - * Sets the time that the event in the notification occurred in milliseconds. Notifications - * in the panel are sorted by this time. The time will be formated in RFC3339 UTC "Zulu" + * For notifications that inform users about events with an absolute time reference, sets + * the time that the event in the notification occurred in milliseconds. Notifications + * in the panel are sorted by this time. The time is be formated in RFC3339 UTC "Zulu" * format, accurate to nanoseconds. Example: "2014-10-02T15:01:23.045123456Z". Note that * since the time is in milliseconds, the last section of the time representation always * has 6 leading zeros. @@ -473,8 +474,7 @@ public Builder setLocalOnly(boolean localOnly) { * Sets the relative priority for this notification. Priority is an indication of how much of * the user's attention should be consumed by this notification. Low-priority notifications * may be hidden from the user in certain situations, while the user might be interrupted - * for a higher-priority notification. The effect of setting the same priorities may differ - * slightly on different platforms. + * for a higher-priority notification. * * @param priority The priority value, one of the values in {MIN, LOW, DEFAULT, HIGH, MAX} * @return This builder. @@ -487,10 +487,10 @@ public Builder setPriority(Priority priority) { /** * Sets a list of vibration timings in milliseconds in the array to use. The first value in the * array indicates the duration to wait before turning the vibrator on. The next value - * indicates the Duration to keep the vibrator on. Subsequent values alternate between - * duration to turn the vibrator off and to turn the vibrator on. If vibrate_timings - * is set and default_vibrate_timings is set to true, the default value is used instead - * of the user-specified vibrate_timings. + * indicates the duration to keep the vibrator on. Subsequent values alternate between + * duration to turn the vibrator off and to turn the vibrator on. If {@code vibrate_timings} + * is set and {@code default_vibrate_timings} is set to true, the default value is used instead + * of the user-specified {@code vibrate_timings}. * A duration in seconds with up to nine fractional digits, terminated by 's'. Example: "3.5s". * * @param vibrateTimingsInMillis List of vibration time in milliseconds @@ -515,10 +515,11 @@ public Builder setVibrateTimingsInMillis(long[] vibrateTimingsInMillis) { /** * Sets the whether to use the default vibration timings. If set to true, use the Android * framework's default vibrate pattern for the notification. Default values are specified - * in config.xml. If default_vibrate_timings is set to true and vibrate_timings is also - * set, the default value is used instead of the user-specified vibrate_timings. + * in {@code config.xml}. If {@code default_vibrate_timings} is set to true and + * {@code vibrate_timings} is also set, the default value is used instead of the + * user-specified {@code vibrate_timings}. * - * @param defaultVibrateTimings The flag incicating whether to use the default vibration timings + * @param defaultVibrateTimings The flag indicating whether to use the default vibration timings * @return This builder. */ public Builder setDefaultVibrateTimings(boolean defaultVibrateTimings) { @@ -530,7 +531,7 @@ public Builder setDefaultVibrateTimings(boolean defaultVibrateTimings) { * Sets the whether to use the default sound. If set to true, use the Android framework's * default sound for the notification. Default values are specified in config.xml. * - * @param defaultSound The flag incicating whether to use the default sound + * @param defaultSound The flag indicating whether to use the default sound * @return This builder. */ public Builder setDefaultSound(boolean defaultSound) { @@ -553,11 +554,11 @@ public Builder setLightSettings(LightSettings lightSettings) { /** * Sets the whether to use the default light settings. If set to true, use the Android * framework's default LED light settings for the notification. Default values are - * specified in config.xml. If default_light_settings is set to true and - * light_settings is also set, the user-specified light_settings is used instead of - * the default value. + * specified in config.xml. If {@code default_light_settings} is set to true and + * {@code light_settings} is also set, the user-specified {@code light_settings} is used + * instead of the default value. * - * @param defaultLightSettings The flag incicating whether to use the default light + * @param defaultLightSettings The flag indicating whether to use the default light * settings * @return This builder. */ @@ -579,11 +580,11 @@ public Builder setVisibility(Visibility visibility) { /** * Sets the number of items this notification represents. May be displayed as a badge - * count for launchers that support badging.See Notification Badge. For example, this - * might be useful if you're using just one notification to represent multiple new messages - * but you want the count here to represent the number of total new messages. If zero or - * unspecified, systems that support badging use the default, which is to increment a number - * displayed on the long-press menu each time a new notification arrives. + * count for launchers that support badging. For example, this might be useful if you're + * using just one notification to represent multiple new messages but you want the count + * here to represent the number of total new messages. If zero or unspecified, systems + * that support badging use the default, which is to increment a number displayed on + * the long-press menu each time a new notification arrives. * * @param notificationCount The notification count * @return This builder. From fb6580796c058bb4a41237ec21dac6271d4bdbf4 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Tue, 22 Oct 2019 18:24:31 -0700 Subject: [PATCH 12/15] Rename Color to LightSettingsColor --- .../com/google/firebase/messaging/Color.java | 71 ------------------- .../firebase/messaging/LightSettings.java | 22 +++--- .../firebase/messaging/MessageTest.java | 4 +- 3 files changed, 13 insertions(+), 84 deletions(-) delete mode 100644 src/main/java/com/google/firebase/messaging/Color.java diff --git a/src/main/java/com/google/firebase/messaging/Color.java b/src/main/java/com/google/firebase/messaging/Color.java deleted file mode 100644 index 2631490ab..000000000 --- a/src/main/java/com/google/firebase/messaging/Color.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2019 Google Inc. - * - * 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.google.firebase.messaging; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.api.client.util.Key; - -/** - * A class representing color in LightSettings. - */ -public final class Color { - - @Key("red") - private final Float red; - - @Key("green") - private final Float green; - - @Key("blue") - private final Float blue; - - @Key("alpha") - private final Float alpha; - - /** - * Creates a new {@link Color} using the given red, green, blue, and - * alpha values. - * - * @param red The red component. - * @param green The green component. - * @param blue The blue component. - * @param alpha The alpha component. - */ - public Color(float red, float green, float blue, float alpha) { - this.red = red; - this.green = green; - this.blue = blue; - this.alpha = alpha; - } - - /** - * Creates a new {@link Color} with a string. Alpha of the color will be - * set to 1. - * - * @param rrggbb Color specified in the {@code #rrggbb} format. - * @return A {@link Color} instance. - */ - public static Color fromString(String rrggbb) { - checkArgument(rrggbb.matches("^#[0-9a-fA-F]{6}$"), - "color must be in the form #RRGGBB"); - float red = (float) Integer.parseInt(rrggbb.substring(1, 3), 16) / 255.0f; - float green = (float) Integer.valueOf(rrggbb.substring(3, 5), 16) / 255.0f; - float blue = (float) Integer.valueOf(rrggbb.substring(5, 7), 16) / 255.0f; - return new Color(red, green, blue, 1.0f); - } -} diff --git a/src/main/java/com/google/firebase/messaging/LightSettings.java b/src/main/java/com/google/firebase/messaging/LightSettings.java index f8d33ff04..a5d7c689d 100644 --- a/src/main/java/com/google/firebase/messaging/LightSettings.java +++ b/src/main/java/com/google/firebase/messaging/LightSettings.java @@ -27,7 +27,7 @@ public final class LightSettings { @Key("color") - private final Color color; + private final LightSettingsColor lightSettingsColor; @Key("light_on_duration") private final String lightOnDuration; @@ -36,7 +36,7 @@ public final class LightSettings { private final String lightOffDuration; private LightSettings(Builder builder) { - this.color = builder.color; + this.lightSettingsColor = builder.lightSettingsColor; this.lightOnDuration = builder.lightOnDuration; this.lightOffDuration = builder.lightOffDuration; } @@ -52,31 +52,31 @@ public static Builder builder() { public static class Builder { - private Color color; + private LightSettingsColor lightSettingsColor; private String lightOnDuration; private String lightOffDuration; private Builder() {} /** - * Sets the color value with a string. + * Sets the lightSettingsColor value with a string. * - * @param color Color specified in the {@code #rrggbb} format. + * @param lightSettingsColor LightSettingsColor specified in the {@code #rrggbb} format. * @return This builder. */ - public Builder setColorFromString(String color) { - this.color = Color.fromString(color); + public Builder setLightSettingsColorFromString(String lightSettingsColor) { + this.lightSettingsColor = LightSettingsColor.fromString(lightSettingsColor); return this; } /** - * Sets the color value in the light settings. + * Sets the lightSettingsColor value in the light settings. * - * @param color Color to be used in the light settings. + * @param lightSettingsColor Color to be used in the light settings. * @return This builder. */ - public Builder setColor(Color color) { - this.color = color; + public Builder setLightSettingsColor(LightSettingsColor lightSettingsColor) { + this.lightSettingsColor = lightSettingsColor; return this; } diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index 74f133a53..c5d0bb464 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -802,7 +802,7 @@ public void testImageInApnsNotification() throws IOException { public void testInvalidColorInAndroidNotificationLightSettings() throws IOException { try { LightSettings.Builder lightSettingsBuilder = LightSettings.builder() - .setColorFromString("#01020K") + .setLightSettingsColorFromString("#01020K") .setLightOnDurationInMillis(1002L) .setLightOffDurationInMillis(1003L); @@ -831,7 +831,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .setDefaultVibrateTimings(false) .setDefaultSound(false) .setLightSettings(LightSettings.builder() - .setColorFromString("#336699") + .setLightSettingsColorFromString("#336699") .setLightOnDurationInMillis(1002L) .setLightOffDurationInMillis(1003L) .build()) From b9c677caf3d6f6e9108de355c0a6baf74427eef1 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Tue, 22 Oct 2019 18:30:21 -0700 Subject: [PATCH 13/15] Add LightSettingsColor class --- .../messaging/LightSettingsColor.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/main/java/com/google/firebase/messaging/LightSettingsColor.java diff --git a/src/main/java/com/google/firebase/messaging/LightSettingsColor.java b/src/main/java/com/google/firebase/messaging/LightSettingsColor.java new file mode 100644 index 000000000..cfec64995 --- /dev/null +++ b/src/main/java/com/google/firebase/messaging/LightSettingsColor.java @@ -0,0 +1,71 @@ +/* + * Copyright 2019 Google Inc. + * + * 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.google.firebase.messaging; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.api.client.util.Key; + +/** + * A class representing color in LightSettings. + */ +public final class LightSettingsColor { + + @Key("red") + private final Float red; + + @Key("green") + private final Float green; + + @Key("blue") + private final Float blue; + + @Key("alpha") + private final Float alpha; + + /** + * Creates a new {@link LightSettingsColor} using the given red, green, blue, and + * alpha values. + * + * @param red The red component. + * @param green The green component. + * @param blue The blue component. + * @param alpha The alpha component. + */ + public LightSettingsColor(float red, float green, float blue, float alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + } + + /** + * Creates a new {@link LightSettingsColor} with a string. Alpha of the color will be + * set to 1. + * + * @param rrggbb LightSettingsColor specified in the {@code #rrggbb} format. + * @return A {@link LightSettingsColor} instance. + */ + public static LightSettingsColor fromString(String rrggbb) { + checkArgument(rrggbb.matches("^#[0-9a-fA-F]{6}$"), + "LightSettingsColor must be in the form #RRGGBB"); + float red = (float) Integer.parseInt(rrggbb.substring(1, 3), 16) / 255.0f; + float green = (float) Integer.valueOf(rrggbb.substring(3, 5), 16) / 255.0f; + float blue = (float) Integer.valueOf(rrggbb.substring(5, 7), 16) / 255.0f; + return new LightSettingsColor(red, green, blue, 1.0f); + } +} From f02c2bc38345396d038b1f680c6ec16f77f5cc5f Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Mon, 28 Oct 2019 11:02:27 -0700 Subject: [PATCH 14/15] address reviewer's comments --- .../google/firebase/messaging/LightSettings.java | 14 +++++++------- .../com/google/firebase/messaging/MessageTest.java | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/google/firebase/messaging/LightSettings.java b/src/main/java/com/google/firebase/messaging/LightSettings.java index a5d7c689d..75a692090 100644 --- a/src/main/java/com/google/firebase/messaging/LightSettings.java +++ b/src/main/java/com/google/firebase/messaging/LightSettings.java @@ -27,7 +27,7 @@ public final class LightSettings { @Key("color") - private final LightSettingsColor lightSettingsColor; + private final LightSettingsColor color; @Key("light_on_duration") private final String lightOnDuration; @@ -36,7 +36,7 @@ public final class LightSettings { private final String lightOffDuration; private LightSettings(Builder builder) { - this.lightSettingsColor = builder.lightSettingsColor; + this.color = builder.color; this.lightOnDuration = builder.lightOnDuration; this.lightOffDuration = builder.lightOffDuration; } @@ -52,7 +52,7 @@ public static Builder builder() { public static class Builder { - private LightSettingsColor lightSettingsColor; + private LightSettingsColor color; private String lightOnDuration; private String lightOffDuration; @@ -64,8 +64,8 @@ private Builder() {} * @param lightSettingsColor LightSettingsColor specified in the {@code #rrggbb} format. * @return This builder. */ - public Builder setLightSettingsColorFromString(String lightSettingsColor) { - this.lightSettingsColor = LightSettingsColor.fromString(lightSettingsColor); + public Builder setColorFromString(String color) { + this.color = LightSettingsColor.fromString(color); return this; } @@ -75,8 +75,8 @@ public Builder setLightSettingsColorFromString(String lightSettingsColor) { * @param lightSettingsColor Color to be used in the light settings. * @return This builder. */ - public Builder setLightSettingsColor(LightSettingsColor lightSettingsColor) { - this.lightSettingsColor = lightSettingsColor; + public Builder setColor(LightSettingsColor color) { + this.color = color; return this; } diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index c5d0bb464..74f133a53 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -802,7 +802,7 @@ public void testImageInApnsNotification() throws IOException { public void testInvalidColorInAndroidNotificationLightSettings() throws IOException { try { LightSettings.Builder lightSettingsBuilder = LightSettings.builder() - .setLightSettingsColorFromString("#01020K") + .setColorFromString("#01020K") .setLightOnDurationInMillis(1002L) .setLightOffDurationInMillis(1003L); @@ -831,7 +831,7 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .setDefaultVibrateTimings(false) .setDefaultSound(false) .setLightSettings(LightSettings.builder() - .setLightSettingsColorFromString("#336699") + .setColorFromString("#336699") .setLightOnDurationInMillis(1002L) .setLightOffDurationInMillis(1003L) .build()) From 0c5e8bb279b377d7bc7d4e6afd76d507da14c5b3 Mon Sep 17 00:00:00 2001 From: Chong Shao Date: Mon, 28 Oct 2019 12:26:01 -0700 Subject: [PATCH 15/15] Parse timestamp with a timezone 'Z' so that in the MessageTest, the expected value of eventTime does not depend on the machine's local timezone. --- .../java/com/google/firebase/messaging/MessageTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/google/firebase/messaging/MessageTest.java b/src/test/java/com/google/firebase/messaging/MessageTest.java index 74f133a53..7c8f528df 100644 --- a/src/test/java/com/google/firebase/messaging/MessageTest.java +++ b/src/test/java/com/google/firebase/messaging/MessageTest.java @@ -29,6 +29,8 @@ import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -846,13 +848,15 @@ public void testExtendedAndroidNotificationParameters() throws IOException { .put("title", "title") .put("body", "body") .build(); + String eventTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'") + .format(new Date(1546304523123L)); Map androidConfig = ImmutableMap.builder() .put("notification", ImmutableMap.builder() .put("title", "android-title") .put("body", "android-body") .put("ticker", "ticker") .put("sticky", true) - .put("event_time", "2019-01-01T01:02:03.000000123Z") + .put("event_time", eventTime) .put("local_only", true) .put("notification_priority", "PRIORITY_HIGH") .put("vibrate_timings", ImmutableList.of("1s", "1.001000000s"))