From 2d000b424a7527d985716bdf1778a6e8d5f3f097 Mon Sep 17 00:00:00 2001 From: Desiree Creel Date: Fri, 14 Apr 2017 14:42:00 -0700 Subject: [PATCH] Fire App Builder v1.0.3 --- Application/app/build.gradle | 4 +- .../helper/AnalyticsHelper.java | 36 +++++--- .../ContentContainerTranslatorTest.java | 6 +- .../translators/ContentTranslatorTest.java | 38 +++++--- .../android/uamp/ui/PlaybackActivity.java | 86 ++++++++++++------- .../uamp/ui/PlaybackOverlayFragment.java | 11 ++- .../android/model/AModelTranslatorTest.java | 24 +++--- .../android/model/AModelTranslator.java | 2 +- 8 files changed, 124 insertions(+), 83 deletions(-) diff --git a/Application/app/build.gradle b/Application/app/build.gradle index 5d831d3..5857549 100644 --- a/Application/app/build.gradle +++ b/Application/app/build.gradle @@ -44,8 +44,8 @@ android { applicationId "com.amazon.android.calypso" minSdkVersion 21 targetSdkVersion 23 - versionCode 6 - versionName "1.0.2" + versionCode 7 + versionName "1.0.3" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true } diff --git a/ContentBrowser/src/main/java/com/amazon/android/contentbrowser/helper/AnalyticsHelper.java b/ContentBrowser/src/main/java/com/amazon/android/contentbrowser/helper/AnalyticsHelper.java index 7c11e7f..ee4072d 100644 --- a/ContentBrowser/src/main/java/com/amazon/android/contentbrowser/helper/AnalyticsHelper.java +++ b/ContentBrowser/src/main/java/com/amazon/android/contentbrowser/helper/AnalyticsHelper.java @@ -194,12 +194,13 @@ public static void trackContentDetailsAction(Content content, int actionId) { /** - * Track that the given content started/resumed playback. + * Track that the given content started or resumed playback. * - * @param content Content that started/resumed playback. - * @param duration Total duration of the content. + * @param content Content that started/resumed playback. + * @param duration Total duration of the content. + * @param currentPosition The current playback position. */ - public static void trackContentStarted(Content content, long duration) { + public static void trackPlaybackStarted(Content content, long duration, long currentPosition) { Map attributes = getBasicAnalyticsAttributesForContent(content); attributes.putAll(getDetailedContentAttributes(content)); @@ -207,21 +208,27 @@ public static void trackContentStarted(Content content, long duration) { // Get Content extras attributes.putAll(ExtraContentAttributes.getExtraAttributes(content.getExtras())); attributes.put(AnalyticsTags.ATTRIBUTE_VIDEO_DURATION, duration); + attributes.put(AnalyticsTags.ATTRIBUTE_VIDEO_CURRENT_POSITION, currentPosition); sendAnalytics(AnalyticsTags.ACTION_PLAYBACK_STARTED, attributes); } /** - * Tracks the ending of a content. + * Tracks that a content's playback finished. This could be that the content was played to + * completion or that the player was exited. * - * @param content Content to track. - * @param duration The duration for which the content was played. + * @param content Content to track. + * @param startingPosition The position that this playback session started at. + * @param currentPosition The current playback position. */ - public static void trackContentFinished(Content content, long duration) { + public static void trackPlaybackFinished(Content content, long startingPosition, + long currentPosition) { // Get the attributes for the selected movie. Map attributes = getBasicAnalyticsAttributesForContent(content); - attributes.put(AnalyticsTags.ATTRIBUTE_VIDEO_SECONDS_WATCHED, duration); + attributes.put(AnalyticsTags.ATTRIBUTE_VIDEO_SECONDS_WATCHED, + currentPosition - startingPosition); + attributes.put(AnalyticsTags.ATTRIBUTE_VIDEO_CURRENT_POSITION, currentPosition); sendAnalytics(AnalyticsTags.ACTION_PLAYBACK_FINISHED, attributes); } @@ -242,13 +249,14 @@ public static void trackPurchaseResult(String sku, boolean purchaseResult) { } /** - * Tracks playback actions of the content. + * Tracks when users interact with the playback controls of the player. * * @param action Action taken on this content. * @param content Content on which the action was taken. * @param currentPosition Current position in the content playback that the ad finished. */ - public static void trackContentAction(String action, Content content, long currentPosition) { + public static void trackPlaybackControlAction(String action, Content content, + long currentPosition) { // Get the attributes for the selected content. Map attributes = getBasicAnalyticsAttributesForContent(content); @@ -357,15 +365,15 @@ public static void trackAppEntry() { /** * Tracks requests received from launcher to play content * - * @param contentId contentId of the content requested to be played - * @param content content corresponding to the contentId + * @param contentId contentId of the content requested to be played + * @param content content corresponding to the contentId * @param requestSource Source of request, it could be Catalog integration or Recommendations */ public static void trackLauncherRequest(String contentId, Content content, String requestSource) { HashMap attributes = new HashMap<>(); - if(requestSource != null) { + if (requestSource != null) { attributes.put(AnalyticsTags.ATTRIBUTE_REQUEST_SOURCE, requestSource); } if (content != null) { diff --git a/ContentModel/src/androidTest/java/com/amazon/android/model/translators/ContentContainerTranslatorTest.java b/ContentModel/src/androidTest/java/com/amazon/android/model/translators/ContentContainerTranslatorTest.java index 0abca1f..8ad913a 100644 --- a/ContentModel/src/androidTest/java/com/amazon/android/model/translators/ContentContainerTranslatorTest.java +++ b/ContentModel/src/androidTest/java/com/amazon/android/model/translators/ContentContainerTranslatorTest.java @@ -32,6 +32,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** @@ -180,14 +181,15 @@ public void testMapToModel() throws Exception { * Tests the {@link ContentContainerTranslator#mapToModel(Map, Recipe)} method with a bad * recipe. */ - @Test(expected = AModelTranslator.TranslationException.class) + @Test public void testMapToModelWithBadRecipe() throws Exception { Recipe badRecipe = Recipe.newInstance(FileHelper.readFile(InstrumentationRegistry .getContext(), "BadContainerRecipe.json")); - mTranslator.mapToModel(createValidMap(), badRecipe); + ContentContainer container = mTranslator.mapToModel(createValidMap(), badRecipe); + assertNull("ContentContainer should be null", container); } /** diff --git a/ContentModel/src/androidTest/java/com/amazon/android/model/translators/ContentTranslatorTest.java b/ContentModel/src/androidTest/java/com/amazon/android/model/translators/ContentTranslatorTest.java index 724d9fe..47da3e5 100644 --- a/ContentModel/src/androidTest/java/com/amazon/android/model/translators/ContentTranslatorTest.java +++ b/ContentModel/src/androidTest/java/com/amazon/android/model/translators/ContentTranslatorTest.java @@ -16,10 +16,8 @@ import com.amazon.android.model.content.Content; import com.amazon.android.recipe.Recipe; -import com.amazon.android.model.AModelTranslator; import com.amazon.android.utils.FileHelper; -import org.json.JSONException; import org.junit.Before; import org.junit.Test; @@ -33,6 +31,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** @@ -321,60 +320,69 @@ public void testMapToModel() throws Exception { * Tests the {@link ContentTranslator#mapToModel(Map, Recipe)} with a recipe that's missing the * title field. */ - @Test(expected = AModelTranslator.TranslationException.class) + @Test public void testMapToModelWithBadRecipeTitle() throws Exception { Recipe badRecipe = Recipe.newInstance(getBadContentRecipeJsonString("title")); - mContentTranslator.mapToModel(createValidMap(), badRecipe); + Content content = mContentTranslator.mapToModel(createValidMap(), badRecipe); + assertNull("Content should be null due to bad translation", content); + } /** * Tests the {@link ContentTranslator#mapToModel(Map, Recipe)} with a recipe that's missing the * description field. */ - @Test(expected = AModelTranslator.TranslationException.class) + @Test public void testMapToModelWithBadRecipeDescription() throws Exception { Recipe badRecipe = Recipe.newInstance(getBadContentRecipeJsonString("description")); - mContentTranslator.mapToModel(createValidMap(), badRecipe); + Content content = mContentTranslator.mapToModel(createValidMap(), badRecipe); + assertNull("Content should be null due to bad translation", content); + } /** * Tests the {@link ContentTranslator#mapToModel(Map, Recipe)} with a recipe that's missing the * url field. */ - @Test(expected = AModelTranslator.TranslationException.class) + @Test public void testMapToModelWithBadRecipeUrl() throws Exception { Recipe badRecipe = Recipe.newInstance(getBadContentRecipeJsonString("url")); - mContentTranslator.mapToModel(createValidMap(), badRecipe); + Content content = mContentTranslator.mapToModel(createValidMap(), badRecipe); + assertNull("Content should be null due to bad translation", content); } /** * Tests the {@link ContentTranslator#mapToModel(Map, Recipe)} with a recipe that's missing the * cardImageUrl field. */ - @Test(expected = AModelTranslator.TranslationException.class) + @Test public void testMapToModelWithBadRecipeCardImageUrl() throws Exception { Recipe badRecipe = Recipe.newInstance(getBadContentRecipeJsonString("cardImageUrl")); - mContentTranslator.mapToModel(createValidMap(), badRecipe); + Content content = mContentTranslator.mapToModel(createValidMap(), badRecipe); + assertNull("Content should be null due to bad translation", content); + } /** * Tests the {@link ContentTranslator#mapToModel(Map, Recipe)} with a recipe that's missing the * backgroundImageUrl field. */ - @Test(expected = AModelTranslator.TranslationException.class) + @Test public void testMapToModelWithBadRecipeBackgroundImageUrl() throws Exception { Recipe badRecipe = Recipe.newInstance(getBadContentRecipeJsonString("backgroundImageUrl")); - mContentTranslator.mapToModel(createValidMap(), badRecipe); + Content content = mContentTranslator.mapToModel(createValidMap(), badRecipe); + assertNull("Content should be null due to bad translation", content); + } /** @@ -447,13 +455,15 @@ private String getBadContentRecipeJsonString(String skipMatchItem, String extraM * Tests the {@link ContentTranslator#mapToModel(Map, Recipe)} with a bad map argument. The map * is missing the title field so the model should not be valid at the end of translation. */ - @Test(expected = AModelTranslator.TranslationException.class) + @Test public void testMapToModelWithBadMap() throws Exception { Map map = createValidMap(); map.remove("title"); - mContentTranslator.mapToModel(map, mGoodRecipe); + Content content = mContentTranslator.mapToModel(map, mGoodRecipe); + assertNull("Content should be null due to bad translation", content); + } /** diff --git a/TVUIComponent/lib/src/main/java/com/amazon/android/uamp/ui/PlaybackActivity.java b/TVUIComponent/lib/src/main/java/com/amazon/android/uamp/ui/PlaybackActivity.java index f3d17f0..e4ec0f7 100755 --- a/TVUIComponent/lib/src/main/java/com/amazon/android/uamp/ui/PlaybackActivity.java +++ b/TVUIComponent/lib/src/main/java/com/amazon/android/uamp/ui/PlaybackActivity.java @@ -79,8 +79,6 @@ import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; -import static com.amazon.android.model.content.Content.AD_ID_FIELD_NAME; - /** * PlaybackOverlayActivity for content playback that loads PlaybackOverlayFragment */ @@ -117,6 +115,7 @@ public class PlaybackActivity extends Activity implements private ProgressBar mProgressBar; private Window mWindow; private long mCurrentPlaybackPosition; + private long mStartingPlaybackPosition; private AudioManager mAudioManager; private AudioFocusState mAudioFocusState = AudioFocusState.NoFocusNoDuck; @@ -174,7 +173,6 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Create video position tracking handler. mVideoPositionTrackingHandler = new Handler(); @@ -245,6 +243,7 @@ public void run() { protected void onStart() { super.onStart(); + registerHDMIUnpluggedStateChangeBroadcast(); requestAudioFocus(); openSelectedContent(); @@ -286,7 +285,7 @@ public void onResume() { if (!isContentLive(mSelectedContent)) { loadContentPlaybackState(); } - + mStartingPlaybackPosition = mCurrentPlaybackPosition; mIsActivityResumed = true; Log.d(TAG, "onResume() current state is " + mCurrentState); switch (mCurrentState) { @@ -306,6 +305,13 @@ public void onResume() { break; } + long duration = getDuration(); + // Duration wasn't found using the player, try getting it directly from the content. + if (duration == 0) { + duration = mSelectedContent.getDuration(); + } + AnalyticsHelper.trackPlaybackStarted(mSelectedContent, duration, mCurrentPlaybackPosition); + // Let ads implementation track player activity lifecycle. if (mAdsImplementation != null) { mAdsImplementation.setActivityState(IAds.ActivityState.RESUME); @@ -327,6 +333,10 @@ public void onPause() { if (mPlayer.getCurrentPosition() > 0) { storeContentPlaybackState(); + // User has stopped watching content so track it with analytics + AnalyticsHelper.trackPlaybackFinished(mSelectedContent, mStartingPlaybackPosition, + getCurrentPosition()); + // After the user has stopped watching the content, send recommendations for related // content of the selected content if any exist. if (mSelectedContent.getRecommendations().size() > 0) { @@ -564,6 +574,10 @@ public void changeContent(Content content) { // Save previous content's state before changing. storeContentPlaybackState(); + // User has stopped watching this content so track it with analytics. + AnalyticsHelper.trackPlaybackFinished(mSelectedContent, mStartingPlaybackPosition, + getCurrentPosition()); + // Since the user is done watching this content, send recommendations for related // content of the selected content (if any exist) before changing to the next content. if (mSelectedContent.getRecommendations().size() > 0) { @@ -577,6 +591,10 @@ public void changeContent(Content content) { mSelectedContent = content; loadContentPlaybackState(); + mStartingPlaybackPosition = mCurrentPlaybackPosition; + // User will start watching this new content so track it with analytics. + AnalyticsHelper.trackPlaybackStarted(mSelectedContent, mStartingPlaybackPosition, + mCurrentPlaybackPosition); if (mPlayer != null) { mPlayer.close(); @@ -619,7 +637,7 @@ private void storeContentPlaybackState() { // Save the recently played content to database ContentDatabaseHelper database = ContentDatabaseHelper.getInstance(getApplicationContext()); - if (database != null) { + if (database != null && !isContentLive(mSelectedContent)) { // Calculate if the content has finished playing boolean isFinished = (mPlayer.getDuration() - ContentBrowser.GRACE_TIME_MS) <= mPlayer.getCurrentPosition(); @@ -838,24 +856,30 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_MEDIA_PLAY: playbackOverlayFragment.togglePlayback(false); - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_PLAY, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags + .ACTION_PLAYBACK_CONTROL_PLAY, + mSelectedContent, getCurrentPosition()); return true; case KeyEvent.KEYCODE_MEDIA_PAUSE: playbackOverlayFragment.togglePlayback(false); - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_PAUSE, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags + .ACTION_PLAYBACK_CONTROL_PAUSE, + mSelectedContent, getCurrentPosition()); return true; case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: if (mPlaybackState == LeanbackPlaybackState.PLAYING) { playbackOverlayFragment.togglePlayback(false); - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_PAUSE, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags + .ACTION_PLAYBACK_CONTROL_PAUSE, + mSelectedContent, + getCurrentPosition()); } else { playbackOverlayFragment.togglePlayback(true); - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_PLAY, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags + .ACTION_PLAYBACK_CONTROL_PLAY, + mSelectedContent, + getCurrentPosition()); } return true; case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: @@ -865,8 +889,8 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { else { playbackOverlayFragment.fastForward(); } - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_FF, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_FF, + mSelectedContent, getCurrentPosition()); return true; case KeyEvent.KEYCODE_MEDIA_REWIND: if (mIsLongPress) { @@ -875,8 +899,9 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { else { playbackOverlayFragment.fastRewind(); } - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_REWIND, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags + .ACTION_PLAYBACK_CONTROL_REWIND, + mSelectedContent, getCurrentPosition()); return true; case KeyEvent.KEYCODE_BUTTON_R1: if (mIsLongPress) { @@ -885,8 +910,8 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { else { playbackOverlayFragment.fastForward(); } - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_FF, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_FF, + mSelectedContent, getCurrentPosition()); return true; case KeyEvent.KEYCODE_BUTTON_L1: if (mIsLongPress) { @@ -895,8 +920,9 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { else { playbackOverlayFragment.fastRewind(); } - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_REWIND, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags + .ACTION_PLAYBACK_CONTROL_REWIND, + mSelectedContent, getCurrentPosition()); return true; default: return super.onKeyUp(keyCode, event); @@ -917,7 +943,8 @@ private void unregisterHDMIUnpluggedStateChangeBroadcast() { private BroadcastReceiver mHDMIUnpluggedStateChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - Log.d(TAG, "mHDMIUnpluggedStateChangeReceiver "+intent); + + Log.d(TAG, "mHDMIUnpluggedStateChangeReceiver " + intent); if (isInitialStickyBroadcast()) { // Ignore initial sticky broadcast. return; @@ -1202,7 +1229,6 @@ private AMZNMediaPlayer.EncryptionSchema getAmznMediaEncryptionSchema(DrmProvide private void openSelectedContent() { - AnalyticsHelper.trackContentStarted(mSelectedContent, getDuration()); Log.d(TAG, "Open content"); mAdsImplementation.setIAdsEvents(mIAdsEvents); @@ -1223,6 +1249,7 @@ private void openSelectedContent() { // Usually required by ads support. // As Player interface doesn't know about video model, we are using Bundles. mPlayer.getExtra().putBundle("video", videoExtras); + // Set Ads video extras. mAdsImplementation.getExtra().putBundle("video", videoExtras); // Show pre roll ad. @@ -1260,8 +1287,8 @@ public void onPlayerStateChange(PlayerState oldState, PlayerState newState, Bund } // If buffering stopped if (mPrevState == PlayerState.BUFFERING && mCurrentState != PlayerState.BUFFERING) { - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_BUFFER_END, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags.ACTION_PLAYBACK_BUFFER_END, + mSelectedContent, getCurrentPosition()); } switch (newState) { case IDLE: @@ -1345,8 +1372,9 @@ else if (mAudioFocusState == AudioFocusState.NoFocusNoDuck) { break; case BUFFERING: showProgress(); - AnalyticsHelper.trackContentAction(AnalyticsTags.ACTION_PLAYBACK_BUFFER_START, - mSelectedContent, getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(AnalyticsTags + .ACTION_PLAYBACK_BUFFER_START, + mSelectedContent, getCurrentPosition()); break; case SEEKING: showProgress(); @@ -1364,13 +1392,9 @@ else if (mAudioFocusState == AudioFocusState.NoFocusNoDuck) { } break; case CLOSING: - if (mPlaybackOverlayFragment != null) { mPlaybackOverlayFragment.stopProgressAutomation(); } - if (!isContentLive(mSelectedContent)) { - AnalyticsHelper.trackContentFinished(mSelectedContent, getCurrentPosition()); - } break; case ERROR: hideProgress(); diff --git a/TVUIComponent/lib/src/main/java/com/amazon/android/uamp/ui/PlaybackOverlayFragment.java b/TVUIComponent/lib/src/main/java/com/amazon/android/uamp/ui/PlaybackOverlayFragment.java index da36ccd..e046ca3 100755 --- a/TVUIComponent/lib/src/main/java/com/amazon/android/uamp/ui/PlaybackOverlayFragment.java +++ b/TVUIComponent/lib/src/main/java/com/amazon/android/uamp/ui/PlaybackOverlayFragment.java @@ -367,16 +367,16 @@ public void onActionClicked(Action action) { } } else if (action.getId() == mSkipNextAction.getId()) { - next(); trackAnalyticsAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_NEXT); + next(); } else if (action.getId() == mClosedCaptioningAction.getId()) { toggleCloseCaption(); trackAnalyticsAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_TOGGLE_CC); } else if (action.getId() == mSkipPreviousAction.getId()) { - prev(); trackAnalyticsAction(AnalyticsTags.ACTION_PLAYBACK_CONTROL_PRE); + prev(); } else if (action.getId() == mFastForwardAction.getId()) { fastForward(); @@ -448,9 +448,9 @@ private void trackAnalyticsAction(String action, Content content) { if (isAdded() && getActivity() != null) { - AnalyticsHelper.trackContentAction(action, content, - ((PlaybackActivity) getActivity()) - .getCurrentPosition()); + AnalyticsHelper.trackPlaybackControlAction(action, content, + ((PlaybackActivity) getActivity()) + .getCurrentPosition()); } } @@ -824,7 +824,6 @@ public void playbackFinished() { togglePlaybackUI(false); next(); - AnalyticsHelper.trackContentFinished(mSelectedContent, mCallback.getDuration()); } /** diff --git a/Utils/src/androidTest/java/com/amazon/android/model/AModelTranslatorTest.java b/Utils/src/androidTest/java/com/amazon/android/model/AModelTranslatorTest.java index 7da8753..bbddc73 100644 --- a/Utils/src/androidTest/java/com/amazon/android/model/AModelTranslatorTest.java +++ b/Utils/src/androidTest/java/com/amazon/android/model/AModelTranslatorTest.java @@ -29,6 +29,7 @@ import java.util.Map; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; /** * This class tests the {@link AModelTranslator} interface. @@ -66,7 +67,7 @@ public void setUp() throws Exception { mMap.put("field2", "field2"); mRecipe = Recipe.newInstance(FileHelper.readFile(InstrumentationRegistry.getContext(), - "TestObjectRecipe.json")); + "TestObjectRecipe.json")); } @@ -104,37 +105,34 @@ public void testMapToModelList() throws Exception { /** * Tests the {@link DummyModelTranslator#mapToModel(Map, Recipe)} method with a bad match list - * in the {@link Recipe}. A {@link AModelTranslator.TranslationException} is - * expected. + * in the {@link Recipe}. A {@link AModelTranslator.TranslationException} is expected. */ @Test(expected = AModelTranslator.TranslationException.class) public void testMapToModelWithBadMatchList() throws Exception { - Recipe badRecipe = Recipe.newInstance(FileHelper.readFile(InstrumentationRegistry - .getContext(), - "TestObjectRecipeBadMatchList" + - ".json")); + Recipe badRecipe = Recipe.newInstance( + FileHelper.readFile(InstrumentationRegistry.getContext(), + "TestObjectRecipeBadMatchList.json")); mTranslator.mapToModel(mMap, badRecipe); } /** * Tests the {@link DummyModelTranslator#mapToModel(Map, Recipe)} method with a match list that * doesn't match all mandatory fields of {@link com.amazon.android.model.testresources - * .DummyModelTranslator.TestObject}. A {@link AModelTranslator - * .TranslationException} is expected. + * .DummyModelTranslator.TestObject}. */ - @Test(expected = AModelTranslator.TranslationException.class) + @Test public void testMapToModelWithUnfinishedMatchList() throws Exception { Recipe badRecipe = Recipe.newInstance( FileHelper.readFile(InstrumentationRegistry.getContext(), - "TestObjectRecipeUnfinishedMatchList.json")); - mTranslator.mapToModel(mMap, badRecipe); + "TestObjectRecipeUnfinishedMatchList.json")); + DummyModelTranslator.TestObject object = mTranslator.mapToModel(mMap, badRecipe); + assertNull("Object should be null due to bad translation", object); } /** * Tests the {@link DummyModelTranslator#getName()} method. - * @throws Exception */ @Test public void testGetName() throws Exception { diff --git a/Utils/src/main/java/com/amazon/android/model/AModelTranslator.java b/Utils/src/main/java/com/amazon/android/model/AModelTranslator.java index 77c54e6..f19f9d8 100644 --- a/Utils/src/main/java/com/amazon/android/model/AModelTranslator.java +++ b/Utils/src/main/java/com/amazon/android/model/AModelTranslator.java @@ -129,7 +129,7 @@ public E mapToModel(Map map, Recipe recipe) throws TranslationEx // Check that the model was properly translated. if (!validateModel(object)) { Log.e(TAG, "Model object not valid: " + object.toString()); - throw new TranslationException("Model object not valid: " + object.toString()); + return null; } return object;