Bug 1322114 - Add test cases for MediaControlService
Also refactor MediaControlService to be test-friendly.
MozReview-Commit-ID: 344cEEuVroG
--- a/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
@@ -14,16 +14,17 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.CheckResult;
+import android.support.annotation.VisibleForTesting;
import android.support.v4.app.NotificationManagerCompat;
import android.util.Log;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.R;
@@ -367,30 +368,41 @@ public class MediaControlService extends
} else {
stopForeground(false);
NotificationManagerCompat.from(this)
.notify(MEDIA_CONTROL_ID, notification);
}
}
private Notification.Action createNotificationAction() {
- boolean isPlayAction = mMediaState.equals(State.PAUSED);
+ final Intent intent = createIntentUponState(mMediaState);
+ boolean isPlayAction = intent.getAction().equals(ACTION_RESUME);
int icon = isPlayAction ? R.drawable.ic_media_play : R.drawable.ic_media_pause;
String title = getString(isPlayAction ? R.string.media_play : R.string.media_pause);
- String action = isPlayAction ? ACTION_RESUME : ACTION_PAUSE;
- final Intent intent = new Intent(getApplicationContext(), MediaControlService.class);
- intent.setAction(action);
final PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, intent, 0);
//noinspection deprecation - The new constructor is only for API > 23
return new Notification.Action.Builder(icon, title, pendingIntent).build();
}
+ /**
+ * This method encapsulated UI logic. For PLAYING state, UI should display a PAUSE icon.
+ * @param state The expected current state of MediaControlService
+ * @return corresponding Intent to be used for Notification
+ */
+ @VisibleForTesting
+ protected Intent createIntentUponState(State state) {
+ String action = state.equals(State.PLAYING) ? ACTION_PAUSE : ACTION_RESUME;
+ final Intent intent = new Intent(getApplicationContext(), MediaControlService.class);
+ intent.setAction(action);
+ return intent;
+ }
+
private PendingIntent createContentIntent(int tabId) {
Intent intent = new Intent(getApplicationContext(), BrowserApp.class);
intent.setAction(GeckoApp.ACTION_SWITCH_TAB);
intent.putExtra("TabId", tabId);
return PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private PendingIntent createDeleteIntent() {
new file mode 100644
--- /dev/null
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/media/TestMediaControlService.java
@@ -0,0 +1,78 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+package org.mozilla.gecko.media;
+
+import android.content.Intent;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.internal.util.reflection.Whitebox;
+import org.mozilla.gecko.Tab;
+import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.background.testhelpers.TestRunner;
+import org.mozilla.gecko.media.MediaControlService.State;
+import org.robolectric.Robolectric;
+
+import java.lang.ref.WeakReference;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+@RunWith(TestRunner.class)
+public class TestMediaControlService {
+
+ private MediaControlService mSpyService;
+ private Tab mMockTab;
+
+ @Before
+ public void setUp() {
+ MediaControlService service = Robolectric.buildService(MediaControlService.class).get();
+ mSpyService = spy(service);
+ mMockTab = mock(Tab.class);
+ // We should use White-box as less as possible. But this is not avoidable so far.
+ Whitebox.setInternalState(mSpyService, "mInitialize", true);
+ }
+
+ @Test
+ public void testTabPlayingMedia() throws Exception {
+ // If tab is playing media and got another MEDIA_PLAYING_CHANGE
+ // state should be PLAYING
+ Whitebox.setInternalState(mSpyService, "mTabReference", new WeakReference<>(mMockTab));
+ doReturn(true).when(mMockTab).isMediaPlaying();
+
+ mSpyService.onTabChanged(mMockTab, Tabs.TabEvents.MEDIA_PLAYING_CHANGE, "");
+ State state = (State) Whitebox.getInternalState(mSpyService, "mMediaState");
+ Assert.assertEquals(state, State.PLAYING);
+ }
+
+ @Test
+ public void testTabNotPlayingMedia() throws Exception {
+ // If tab is not playing media and got another MEDIA_PLAYING_CHANGE
+ // state should be STOPPED
+ Whitebox.setInternalState(mSpyService, "mTabReference", new WeakReference<>(mMockTab));
+ doReturn(false).when(mMockTab).isMediaPlaying();
+
+ mSpyService.onTabChanged(mMockTab, Tabs.TabEvents.MEDIA_PLAYING_CHANGE, "");
+ State state = (State) Whitebox.getInternalState(mSpyService, "mMediaState");
+ Assert.assertEquals(state, State.STOPPED);
+ }
+
+ @Test
+ public void testIntentForPlayingState() throws Exception {
+ // For PLAYING state, should create an PAUSE intent for notification
+ Intent intent = mSpyService.createIntentUponState(State.PLAYING);
+ Assert.assertEquals(intent.getAction(), MediaControlService.ACTION_PAUSE);
+ }
+
+ @Test
+ public void testIntentForPausedState() throws Exception {
+ // For PAUSED state, should create an RESUME intent for notification
+ Intent intent = mSpyService.createIntentUponState(State.PAUSED);
+ Assert.assertEquals(intent.getAction(), MediaControlService.ACTION_RESUME);
+ }
+}