Skip to content

Commit

Permalink
Add viewport utilities for Alexa Presentation Language
Browse files Browse the repository at this point in the history
  • Loading branch information
nikhilym committed Oct 30, 2018
1 parent 1875b5b commit 48667c2
Show file tree
Hide file tree
Showing 14 changed files with 795 additions and 15 deletions.
9 changes: 9 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ boiler-plate code.
.. |Docs| image:: https://img.shields.io/readthedocs/alexa-skills-kit-python-sdk.svg?style=flat
:target: https://alexa-skills-kit-python-sdk.readthedocs.io
:alt: Read the docs
.. |Runtime Version| image:: http://img.shields.io/pypi/v/ask-sdk-runtime.svg?style=flat
:target: https://pypi.python.org/pypi/ask-sdk-runtime/
:alt: Version
.. |Runtime Downloads| image:: https://pepy.tech/badge/ask-sdk-runtime
:target: https://pepy.tech/project/ask-sdk-runtime
:alt: Downloads
.. |Core Version| image:: http://img.shields.io/pypi/v/ask-sdk-core.svg?style=flat
:target: https://pypi.python.org/pypi/ask-sdk-core/
:alt: Version
Expand Down Expand Up @@ -56,6 +62,7 @@ Package Versions
==================================== ==================
Package Version
------------------------------------ ------------------
ask-sdk-runtime |Runtime Version| |Runtime Downloads|
ask-sdk-core |Core Version| |Core Downloads|
ask-sdk-dynamodb-persistence-adapter |DynamoDb Version| |DynamoDb Downloads|
ask-sdk |Standard Version| |Standard Downloads|
Expand Down Expand Up @@ -236,6 +243,8 @@ Preview

* `Connections <https://developer.amazon.com/blogs/alexa/post/7b332b32-893e-4cad-be07-a5877efcbbb4/skill-connections-preview-now-skills-can-work-together-to-help-customers-get-more-done>`__

* `Alexa Presentation Language <https://developer.amazon.com/blogs/alexa/post/1dee3fa0-8c5f-4179-ab7a-74545ead24ce/introducing-the-alexa-presentation-language-preview>`__


Got Feedback?
-------------
Expand Down
26 changes: 26 additions & 0 deletions ask-sdk-core/ask_sdk_core/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
#
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights
# Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License").
# You may not use this file except in compliance with the License.
# A copy of the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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.
#
import sys

from ..__version__ import __version__
from .predicate import is_intent_name, is_request_type
from ask_sdk_runtime.utils import user_agent_info


SDK_VERSION = __version__
RESPONSE_FORMAT_VERSION = "1.0"
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,10 @@
import typing

from ask_sdk_model import IntentRequest
from ask_sdk_runtime.utils import user_agent_info

from .__version__ import __version__

if typing.TYPE_CHECKING:
from typing import Callable
from .handler_input import HandlerInput


SDK_VERSION = __version__
RESPONSE_FORMAT_VERSION = "1.0"
from ..handler_input import HandlerInput


def is_intent_name(name):
Expand Down
246 changes: 246 additions & 0 deletions ask-sdk-core/ask_sdk_core/utils/viewport.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
# -*- coding: utf-8 -*-
#
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights
# Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License").
# You may not use this file except in compliance with the License.
# A copy of the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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 enum import Enum
from ask_sdk_model import RequestEnvelope
from ask_sdk_model.interfaces.viewport import Shape

from ..exceptions import AskSdkException


class OrderedEnum(Enum):
def __ge__(self, other):
if self.__class__ is other.__class__:
return self.value >= other.value
return NotImplemented

def __gt__(self, other):
if self.__class__ is other.__class__:
return self.value > other.value
return NotImplemented

def __le__(self, other):
if self.__class__ is other.__class__:
return self.value <= other.value
return NotImplemented

def __lt__(self, other):
if self.__class__ is other.__class__:
return self.value < other.value
return NotImplemented


class Density(OrderedEnum):
XLOW = 0
LOW = 1
MEDIUM = 2
HIGH = 3
XHIGH = 4
XXHIGH = 5


class Orientation(OrderedEnum):
LANDSCAPE = 0
EQUAL = 1
PORTRAIT = 2


class Size(OrderedEnum):
XSMALL = 0
SMALL = 1
MEDIUM = 2
LARGE = 3
XLARGE = 4


class ViewportProfile(Enum):
HUB_ROUND_SMALL = "HUB_ROUND_SMALL"
HUB_LANDSCAPE_MEDIUM = "HUB_LANDSCAPE_MEDIUM"
HUB_LANDSCAPE_LARGE = "HUB_LANDSCAPE_LARGE"
MOBILE_LANDSCAPE_SMALL = "MOBILE_LANDSCAPE_SMALL"
MOBILE_PORTRAIT_SMALL = "MOBILE_PORTRAIT_SMALL"
MOBILE_LANDSCAPE_MEDIUM = "MOBILE_LANDSCAPE_MEDIUM"
MOBILE_PORTRAIT_MEDIUM = "MOBILE_PORTRAIT_MEDIUM"
TV_LANDSCAPE_XLARGE = "TV_LANDSCAPE_XLARGE"
TV_PORTRAIT_MEDIUM = "TV_PORTRAIT_MEDIUM"
TV_LANDSCAPE_MEDIUM = "TV_LANDSCAPE_MEDIUM"
UNKNOWN_VIEWPORT_PROFILE = "UNKNOWN_VIEWPORT_PROFILE"


def get_orientation(width, height):
# type: (int, int) -> Orientation
"""Get viewport orientation from given width and height.
:type width: int
:type height: int
:return viewport orientation enum
:rtype: Orientation
"""
if width > height:
return Orientation.LANDSCAPE
elif width < height:
return Orientation.PORTRAIT
else:
return Orientation.EQUAL


def get_size(size):
# type: (int) -> Size
"""Get viewport size from given size.
:type size: int
:return viewport size enum
:rtype: Size
"""
if size in range(0, 600):
return Size.XSMALL
elif size in range(600, 960):
return Size.SMALL
elif size in range(960, 1280):
return Size.MEDIUM
elif size in range(1280, 1920):
return Size.LARGE
elif size >= 1920:
return Size.XLARGE

raise AskSdkException("Unknown size group value: {}".format(size))


def get_dpi_group(dpi):
# type: (int) -> Density
"""Get viewport density group from given dpi.
:type dpi: int
:return viewport density group enum
:rtype: Density
"""
if dpi in range(0, 121):
return Density.XLOW
elif dpi in range(121, 161):
return Density.LOW
elif dpi in range(161, 241):
return Density.MEDIUM
elif dpi in range(241, 321):
return Density.HIGH
elif dpi in range(321, 481):
return Density.XHIGH
elif dpi >= 481:
return Density.XXHIGH

raise AskSdkException("Unknown dpi group value: {}".format(dpi))


def get_viewport_profile(request_envelope):
# type: (RequestEnvelope) -> ViewportProfile
"""Utility method, to get viewport profile.
The viewport profile is calculated using the shape, current pixel
width and height, along with the dpi.
If there is no `viewport`
value in `request_envelope.context`, then an
`ViewportProfile.UNKNOWN_VIEWPORT_PROFILE` is returned.
:param request_envelope: The alexa request envelope object
:type request_envelope: ask_sdk_model.request_envelope.RequestEnvelope
:return Calculated Viewport Profile enum
:rtype ViewportProfile
"""
viewport_state = request_envelope.context.viewport
if viewport_state:
shape = viewport_state.shape
current_pixel_width = int(viewport_state.current_pixel_width)
current_pixel_height = int(viewport_state.current_pixel_height)
dpi = int(viewport_state.dpi)

orientation = get_orientation(
width=current_pixel_width, height=current_pixel_height)
dpi_group = get_dpi_group(dpi=dpi)
pixel_width_size_group = get_size(size=current_pixel_width)
pixel_height_size_group = get_size(size=current_pixel_height)

if (shape is Shape.ROUND
and orientation is Orientation.EQUAL
and dpi_group is Density.LOW
and pixel_width_size_group is Size.XSMALL
and pixel_height_size_group is Size.XSMALL):
return ViewportProfile.HUB_ROUND_SMALL

elif (shape is Shape.RECTANGLE
and orientation is Orientation.LANDSCAPE
and dpi_group is Density.LOW
and pixel_width_size_group <= Size.MEDIUM
and pixel_height_size_group <= Size.SMALL):
return ViewportProfile.HUB_LANDSCAPE_MEDIUM

elif (shape is Shape.RECTANGLE
and orientation is Orientation.LANDSCAPE
and dpi_group is Density.LOW
and pixel_width_size_group >= Size.LARGE
and pixel_height_size_group >= Size.SMALL):
return ViewportProfile.HUB_LANDSCAPE_LARGE

elif (shape is Shape.RECTANGLE
and orientation is Orientation.LANDSCAPE
and dpi_group is Density.MEDIUM
and pixel_width_size_group >= Size.MEDIUM
and pixel_height_size_group >= Size.SMALL):
return ViewportProfile.MOBILE_LANDSCAPE_MEDIUM

elif (shape is Shape.RECTANGLE
and orientation is Orientation.PORTRAIT
and dpi_group is Density.MEDIUM
and pixel_width_size_group >= Size.SMALL
and pixel_height_size_group >= Size.MEDIUM):
return ViewportProfile.MOBILE_PORTRAIT_MEDIUM

elif (shape is Shape.RECTANGLE
and orientation is Orientation.LANDSCAPE
and dpi_group is Density.MEDIUM
and pixel_width_size_group >= Size.SMALL
and pixel_height_size_group >= Size.XSMALL):
return ViewportProfile.MOBILE_LANDSCAPE_SMALL

elif (shape is Shape.RECTANGLE
and orientation is Orientation.PORTRAIT
and dpi_group is Density.MEDIUM
and pixel_width_size_group >= Size.XSMALL
and pixel_height_size_group >= Size.SMALL):
return ViewportProfile.MOBILE_PORTRAIT_SMALL

elif (shape is Shape.RECTANGLE
and orientation is Orientation.LANDSCAPE
and dpi_group >= Density.HIGH
and pixel_width_size_group >= Size.XLARGE
and pixel_height_size_group >= Size.MEDIUM):
return ViewportProfile.TV_LANDSCAPE_XLARGE

elif (shape is Shape.RECTANGLE
and orientation is Orientation.PORTRAIT
and dpi_group >= Density.HIGH
and pixel_width_size_group is Size.XSMALL
and pixel_height_size_group is Size.XLARGE):
return ViewportProfile.TV_PORTRAIT_MEDIUM

elif (shape is Shape.RECTANGLE
and orientation is Orientation.LANDSCAPE
and dpi_group >= Density.HIGH
and pixel_width_size_group is Size.MEDIUM
and pixel_height_size_group is Size.SMALL):
return ViewportProfile.TV_LANDSCAPE_MEDIUM

return ViewportProfile.UNKNOWN_VIEWPORT_PROFILE
4 changes: 2 additions & 2 deletions ask-sdk-core/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
requests
python_dateutil
ask-sdk-model
ask-sdk-runtime
ask-sdk-model>=1.0.0
ask-sdk-runtime>=1.1.0
Loading

0 comments on commit 48667c2

Please sign in to comment.