Repository: line/line-bot-sdk-python

Issue:
Support Flex Message Update 2
News: https://developers.line.biz/en/news/2020/10/08/flex-message-update-2-released/

1. - [ ] [Changed the maximum number of bubbles that can be included in a carousel](https://developers.line.biz/en/reference/messaging-api/#f-carousel)
2. - [ ] [Box component has justifyContent and alignItems property](https://developers.line.biz/en/reference/messaging-api/#box)
3. - [ ] [Use linear gradient as the background image for a box component by setting its background.type property equal to linearGradient.](https://developers.line.biz/en/reference/messaging-api/#box)
4. - [ ] [Allowed an empty array to be specified as the value of a box's contents property](https://developers.line.biz/en/reference/messaging-api/#box)
5. - [ ] [Added support for animated images](https://developers.line.biz/en/reference/messaging-api/#f-image)
6. - [ ] [Changed how sizes are specified](https://developers.line.biz/en/news/2020/10/08/flex-message-update-2-released/#update-size)
	1. - [ ] [Image component](https://developers.line.biz/en/docs/messaging-api/flex-message-layout/#image-size)
	2. - [ ] [Icon, text, and span components](https://developers.line.biz/en/docs/messaging-api/flex-message-layout/#other-component-size) 
7. - [ ] [Allowed text to automatically shrink to fit a component's width](https://developers.line.biz/en/news/2020/10/08/flex-message-update-2-released/#update-adjust-mode) - [Text](https://developers.line.biz/en/reference/messaging-api/#f-text) and [Button](https://developers.line.biz/en/reference/messaging-api/#button)
8. - [ ] [Spacer has been discontinued](https://developers.line.biz/en/news/2020/10/08/flex-message-update-2-released/#update-spacer)

Discussion:
louis70109: Thanks for @cryeo -san details review!!
I have fixed these.

Patch:
diff --git a/examples/flask-kitchensink/app.py b/examples/flask-kitchensink/app.py
index 2316df2..ba1e864 100644
--- a/examples/flask-kitchensink/app.py
+++ b/examples/flask-kitchensink/app.py
@@ -44,7 +44,7 @@ from linebot.models import (
     UnfollowEvent, FollowEvent, JoinEvent, LeaveEvent, BeaconEvent,
     MemberJoinedEvent, MemberLeftEvent,
     FlexSendMessage, BubbleContainer, ImageComponent, BoxComponent,
-    TextComponent, SpacerComponent, IconComponent, ButtonComponent,
+    TextComponent, IconComponent, ButtonComponent,
     SeparatorComponent, QuickReply, QuickReplyButton,
     ImageSendMessage)
 
@@ -309,8 +309,6 @@ def handle_text_message(event):
                 layout='vertical',
                 spacing='sm',
                 contents=[
-                    # callAction, separator, websiteAction
-                    SpacerComponent(size='sm'),
                     # callAction
                     ButtonComponent(
                         style='link',
diff --git a/linebot/models/__init__.py b/linebot/models/__init__.py
index cbaf9da..be0140e 100644
--- a/linebot/models/__init__.py
+++ b/linebot/models/__init__.py
@@ -78,7 +78,6 @@ from .flex_message import (  # noqa
     IconComponent,
     ImageComponent,
     SeparatorComponent,
-    SpacerComponent,
     TextComponent,
     SpanComponent
 )
@@ -196,3 +195,8 @@ from .things import (  # noqa
     ActionResult,
     Things,
 )
+
+from .background import (  # noqa
+    Background,
+    LinearGradientBackground,
+)
diff --git a/linebot/models/background.py b/linebot/models/background.py
new file mode 100644
index 0000000..a758a73
--- /dev/null
+++ b/linebot/models/background.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+
+#  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
+#
+#       https://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.
+
+"""linebot.models.emojis module."""
+
+from __future__ import unicode_literals
+
+from abc import ABCMeta
+
+from future.utils import with_metaclass
+
+from .base import Base
+
+
+class Background(with_metaclass(ABCMeta, Base)):
+    """Background."""
+
+    def __init__(self, **kwargs):
+        """__init__ method.
+
+        :param kwargs:
+        """
+        super(Background, self).__init__(**kwargs)
+
+        self.type = None
+
+
+class LinearGradientBackground(Background):
+    """LinearGradientBackground."""
+
+    def __init__(self, angle, start_color, end_color,
+                 center_color=None, center_position=None, **kwargs):
+        """__init__ method.
+
+        :param str type: The type of background used
+        :param str angle: The angle at which a linear gradient moves
+        :param str start_color: The color at the gradient's starting point
+        :param str end_color: The color at the gradient's ending point
+        :param str center_color: The color in the middle of the gradient
+        :param str center_position: The position of the intermediate color stop
+        :param kwargs:
+        """
+        super(LinearGradientBackground, self).__init__(**kwargs)
+        self.type = 'linearGradient'
+        self.angle = angle
+        self.start_color = start_color
+        self.end_color = end_color
+        self.center_color = center_color
+        self.center_position = center_position
diff --git a/linebot/models/flex_message.py b/linebot/models/flex_message.py
index bd95169..4a7cdce 100644
--- a/linebot/models/flex_message.py
+++ b/linebot/models/flex_message.py
@@ -20,6 +20,7 @@ from abc import ABCMeta
 
 from future.utils import with_metaclass
 
+from .background import Background, LinearGradientBackground
 from .actions import get_action
 from .base import Base
 from .send_messages import SendMessage
@@ -234,6 +235,9 @@ class BoxComponent(FlexComponent):
                  border_color=None,
                  border_width=None,
                  corner_radius=None,
+                 justify_content=None,
+                 align_items=None,
+                 background=None,
                  width=None,
                  height=None,
                  flex=None,
@@ -260,6 +264,12 @@ class BoxComponent(FlexComponent):
         :param str border_color: Color of box border
         :param str border_width: Width of box border
         :param str corner_radius: Radius at the time of rounding the corners of the border
+        :param str justify_content: How child elements are aligned along the main axis of
+            the parent element
+        :param str align_items: How child elements are aligned along the cross axis of
+            the parent element
+        :param background: Background object
+        :type background: T <= :py:class:`linebot.models.background.Background`
         :param str width: Width of the box
         :param str height: Height of the box
         :param float flex: The ratio of the width or height of this box within the parent box
@@ -291,6 +301,8 @@ class BoxComponent(FlexComponent):
         self.border_color = border_color
         self.border_width = border_width
         self.corner_radius = corner_radius
+        self.justify_content = justify_content
+        self.align_items = align_items
         self.width = width
         self.height = height
         self.flex = flex
@@ -307,6 +319,9 @@ class BoxComponent(FlexComponent):
         self.offset_start = offset_start
         self.offset_end = offset_end
         self.action = get_action(action)
+        self.background = Background.get_or_new_from_json_dict_with_types(
+            background, {'linearGradient': LinearGradientBackground}
+        )
 
         new_contents = []
         if contents:
@@ -320,7 +335,6 @@ class BoxComponent(FlexComponent):
                         'image': ImageComponent,
                         'span': SpanComponent,
                         'separator': SeparatorComponent,
-                        'spacer': SpacerComponent,
                         'text': TextComponent
                     }
                 ))
@@ -349,6 +363,7 @@ class ButtonComponent(FlexComponent):
                  style=None,
                  color=None,
                  gravity=None,
+                 adjust_mode=None,
                  **kwargs):
         """__init__ method.
 
@@ -368,6 +383,7 @@ class ButtonComponent(FlexComponent):
             Background color when the style property is primary or secondary.
             Use a hexadecimal color code
         :param str gravity: Vertical alignment style
+        :param str adjust_mode: The method by which to adjust the text font size
         :param kwargs:
         """
         super(ButtonComponent, self).__init__(**kwargs)
@@ -384,6 +400,7 @@ class ButtonComponent(FlexComponent):
         self.style = style
         self.color = color
         self.gravity = gravity
+        self.adjust_mode = adjust_mode
 
 
 class FillerComponent(FlexComponent):
@@ -541,26 +558,6 @@ class SeparatorComponent(FlexComponent):
         self.color = color
 
 
-class SpacerComponent(FlexComponent):
-    """SpacerComponent.
-
-    https://developers.line.biz/en/reference/messaging-api/#spacer
-
-    This is an invisible component that places a fixed-size space
-    at the beginning or end of the box
-    """
-
-    def __init__(self, size=None, **kwargs):
-        """__init__ method.
-
-        :param str size: Size of the space
-        :param kwargs:
-        """
-        super(SpacerComponent, self).__init__(**kwargs)
-        self.type = 'spacer'
-        self.size = size
-
-
 class SpanComponent(FlexComponent):
     """SpanComponent.
 


Test patch:
diff --git a/tests/models/serialize_test_case.py b/tests/models/serialize_test_case.py
index 7784dcd..13de0bc 100644
--- a/tests/models/serialize_test_case.py
+++ b/tests/models/serialize_test_case.py
@@ -41,7 +41,6 @@ class SerializeTestCase(unittest.TestCase):
     AGE = "age"
     AREA = "area"
     SUBSCRIPTION_PERIOD = "subscriptionPeriod"
-    SPACER = 'spacer'
     SPAN = 'span'
     BUBBLE = 'bubble'
     CAROUSEL = 'carousel'
@@ -60,6 +59,7 @@ class SerializeTestCase(unittest.TestCase):
     BUTTONS = 'buttons'
     CONFIRM = 'confirm'
     IMAGE_CAROUSEL = 'image_carousel'
+    LINEAR_GRADIENT = 'linearGradient'
 
     def serialize_as_dict(self, obj, type=None):
         if isinstance(obj, Base):
diff --git a/tests/models/test_background.py b/tests/models/test_background.py
new file mode 100644
index 0000000..7cc68e7
--- /dev/null
+++ b/tests/models/test_background.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+
+#  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
+#
+#       https://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.
+
+from __future__ import unicode_literals, absolute_import
+
+import unittest
+
+from linebot.models import LinearGradientBackground
+from tests.models.serialize_test_case import SerializeTestCase
+
+
+class TestBackground(SerializeTestCase):
+    def test_background(self):
+        arg = {
+            "type": "linearGradient",
+            "angle": "0deg",
+            "start_color": "#ff0000",
+            "end_color": "#0000ff"
+        }
+        self.assertEqual(
+            self.serialize_as_dict(arg, type=self.LINEAR_GRADIENT),
+            LinearGradientBackground(**arg).as_json_dict()
+        )
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/models/test_flex_message.py b/tests/models/test_flex_message.py
index 9fe7c29..4618002 100644
--- a/tests/models/test_flex_message.py
+++ b/tests/models/test_flex_message.py
@@ -29,9 +29,9 @@ from linebot.models import (
     ButtonComponent,
     FillerComponent,
     IconComponent,
-    SpacerComponent,
     SpanComponent,
     URIAction,
+    LinearGradientBackground,
 )
 from tests.models.serialize_test_case import SerializeTestCase
 
@@ -158,6 +158,28 @@ class TestFlexMessage(SerializeTestCase):
             BoxComponent(**arg).as_json_dict()
         )
 
+    def test_box_component_with_linear_gradient(self):
+        arg = {
+            'layout': 'vertical',
+            'contents': [],
+            'background_color': '#00000000',
+            'border_width': 'light',
+            'corner_radius': 'xs',
+            'flex': 2,
+            'background': LinearGradientBackground(
+                angle='0deg',
+                start_color='#ff0000',
+                center_color='#0000ff',
+                end_color='#00ff00',
+                center_position='10%'
+            )
+        }
+
+        self.assertEqual(
+            self.serialize_as_dict(arg, type=self.BOX),
+            BoxComponent(**arg).as_json_dict()
+        )
+
     def test_button_component(self):
         arg = {
             'action':
@@ -212,15 +234,6 @@ class TestFlexMessage(SerializeTestCase):
             SeparatorComponent(**arg).as_json_dict()
         )
 
-    def test_spacer_component(self):
-        arg = {
-            'size': 'md'
-        }
-        self.assertEqual(
-            self.serialize_as_dict(arg, type=self.SPACER),
-            SpacerComponent(**arg).as_json_dict()
-        )
-
     def test_span_component(self):
         arg = {
             'type': 'span',