Bug 1290467 - part3 : notify MediaControlService with event 'MEDIA_PLAYING_CHANGE'.
The 'MEDIA_PLAYING_CHANGE' is used for controling media control interface and
the 'AUDIO_PLAYING_CHANGE' is used for showing the tab sound indicator.
MozReview-Commit-ID: 8hZjC77Ju71
--- a/mobile/android/base/java/org/mozilla/gecko/Tab.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tab.java
@@ -79,16 +79,17 @@ public class Tab {
private Bitmap mThumbnailBitmap;
private boolean mDesktopMode;
private boolean mEnteringReaderMode;
private final Context mAppContext;
private ErrorType mErrorType = ErrorType.NONE;
private volatile int mLoadProgress;
private volatile int mRecordingCount;
private volatile boolean mIsAudioPlaying;
+ private volatile boolean mIsMediaPlaying;
private String mMostRecentHomePanel;
private boolean mShouldShowToolbarWithoutAnimationOnFirstSelection;
/*
* Bundle containing restore data for the panel referenced in mMostRecentHomePanel. This can be
* e.g. the most recent folder for the bookmarks panel, or any other state that should be
* persisted. This is then used e.g. when returning to homepanels via history.
*/
@@ -807,16 +808,36 @@ public class Tab {
mRecordingCount--;
}
}
public boolean isRecording() {
return mRecordingCount > 0;
}
+ /**
+ * The "MediaPlaying" is used for controling media control interface and
+ * means the tab has playing media.
+ *
+ * @param isMediaPlaying the tab has any playing media or not
+ */
+ public void setIsMediaPlaying(boolean isMediaPlaying) {
+ mIsMediaPlaying = isMediaPlaying;
+ }
+
+ public boolean isMediaPlaying() {
+ return mIsMediaPlaying;
+ }
+
+ /**
+ * The "AudioPlaying" is used for showing the tab sound indicator and means
+ * the tab has playing media and the media is audible.
+ *
+ * @param isAudioPlaying the tab has any audible playing media or not
+ */
public void setIsAudioPlaying(boolean isAudioPlaying) {
mIsAudioPlaying = isAudioPlaying;
}
public boolean isAudioPlaying() {
return mIsAudioPlaying;
}
--- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java
@@ -118,17 +118,18 @@ public class Tabs implements GeckoEventL
"Link:Favicon",
"Link:Touchicon",
"Link:Feed",
"Link:OpenSearch",
"DesktopMode:Changed",
"Tab:ViewportMetadata",
"Tab:StreamStart",
"Tab:StreamStop",
- "Tab:AudioPlayingChange");
+ "Tab:AudioPlayingChange",
+ "Tab:MediaPlaybackChange");
mPrivateClearColor = Color.RED;
}
public synchronized void attachToContext(Context context, LayerView layerView) {
final Context appContext = context.getApplicationContext();
if (mAppContext == appContext) {
@@ -561,16 +562,19 @@ public class Tabs implements GeckoEventL
tab.setRecording(true);
notifyListeners(tab, TabEvents.RECORDING_CHANGE);
} else if (event.equals("Tab:StreamStop")) {
tab.setRecording(false);
notifyListeners(tab, TabEvents.RECORDING_CHANGE);
} else if (event.equals("Tab:AudioPlayingChange")) {
tab.setIsAudioPlaying(message.getBoolean("isAudioPlaying"));
notifyListeners(tab, TabEvents.AUDIO_PLAYING_CHANGE);
+ } else if (event.equals("Tab:MediaPlaybackChange")) {
+ tab.setIsMediaPlaying(message.getBoolean("active"));
+ notifyListeners(tab, TabEvents.MEDIA_PLAYING_CHANGE);
}
} catch (Exception e) {
Log.w(LOGTAG, "handleMessage threw for " + event, e);
}
}
public void refreshThumbnails() {
@@ -621,16 +625,17 @@ public class Tabs implements GeckoEventL
SECURITY_CHANGE,
DESKTOP_MODE_CHANGE,
VIEWPORT_CHANGE,
RECORDING_CHANGE,
BOOKMARK_ADDED,
BOOKMARK_REMOVED,
AUDIO_PLAYING_CHANGE,
OPENED_FROM_TABS_TRAY,
+ MEDIA_PLAYING_CHANGE,
}
public void notifyListeners(Tab tab, TabEvents msg) {
notifyListeners(tab, msg, "");
}
public void notifyListeners(final Tab tab, final TabEvents msg, final String data) {
if (tab == null &&
--- a/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
@@ -99,35 +99,31 @@ public class MediaControlService extends
}
@Override
public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) {
if (!mIsInitMediaSession) {
return;
}
+ final Tab playingTab = mTabReference.get();
switch (msg) {
- case AUDIO_PLAYING_CHANGE:
- if (tab == mTabReference.get()) {
- return;
+ case MEDIA_PLAYING_CHANGE:
+ if (playingTab != tab && tab.isMediaPlaying()) {
+ mTabReference = new WeakReference<>(tab);
+ mController.getTransportControls().sendCustomAction(ACTION_START, null);
+ } else if (playingTab == tab && !tab.isMediaPlaying()) {
+ mController.getTransportControls().stop();
}
-
- if (!tab.isAudioPlaying()) {
- return;
- }
-
- mTabReference = new WeakReference<>(tab);
- notifyControlInterfaceChanged(ACTION_PAUSE);
break;
case CLOSED:
- final Tab playingTab = mTabReference.get();
if (playingTab == null || playingTab == tab) {
- // The playing tab disappeared or was closed. Remove the controls and stop the service.
- notifyControlInterfaceChanged(ACTION_REMOVE_CONTROL);
+ // Remove the controls when the playing tab disappeared or was closed.
+ mController.getTransportControls().stop();
}
break;
}
}
private boolean isAndroidVersionLollopopOrHigher() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
@@ -231,16 +227,17 @@ public class MediaControlService extends
@Override
public void onStop() {
Log.d(LOGTAG, "Controller, onStop");
super.onStop();
notifyControlInterfaceChanged(ACTION_STOP);
notifyObservers("MediaControl", "mediaControlStopped");
mActionState = ACTION_STOP;
+ mTabReference = new WeakReference<>(null);
stopSelf();
}
});
mIsInitMediaSession = true;
}
private void notifyObservers(String topic, String data) {
GeckoAppShell.notifyObservers(topic, data);
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3561,16 +3561,17 @@ Tab.prototype = {
this.browser.addEventListener("TabPreZombify", this, true);
// Note that the XBL binding is untrusted
this.browser.addEventListener("PluginBindingAttached", this, true, true);
this.browser.addEventListener("VideoBindingAttached", this, true, true);
this.browser.addEventListener("VideoBindingCast", this, true, true);
Services.obs.addObserver(this, "before-first-paint", false);
+ Services.obs.addObserver(this, "media-playback", false);
// Always intialise new tabs with basic session store data to avoid
// problems with functions that always expect it to be present
this.browser.__SS_data = {
entries: [{
url: aURL,
title: truncate(title, MAX_TITLE_LENGTH)
}],
@@ -3670,16 +3671,17 @@ Tab.prototype = {
this.browser.removeEventListener("MozApplicationManifest", this, true);
this.browser.removeEventListener("TabPreZombify", this, true);
this.browser.removeEventListener("PluginBindingAttached", this, true, true);
this.browser.removeEventListener("VideoBindingAttached", this, true, true);
this.browser.removeEventListener("VideoBindingCast", this, true, true);
Services.obs.removeObserver(this, "before-first-paint");
+ Services.obs.removeObserver(this, "media-playback", false);
// Make sure the previously selected panel remains selected. The selected panel of a deck is
// not stable when panels are removed.
let selectedPanel = BrowserApp.deck.selectedPanel;
BrowserApp.deck.removeChild(this.browser);
BrowserApp.deck.selectedPanel = selectedPanel;
this.browser = null;
@@ -4447,16 +4449,31 @@ Tab.prototype = {
}
this.contentDocumentIsDisplayed = true;
if (contentDocument instanceof Ci.nsIImageDocument) {
contentDocument.shrinkToFit();
}
}
break;
+
+ case "media-playback":
+ if (!aSubject) {
+ return;
+ }
+
+ let winId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
+ if (this.browser.outerWindowID == winId) {
+ Messaging.sendRequest({
+ type: "Tab:MediaPlaybackChange",
+ tabID: this.id,
+ active: aData === "active"
+ });
+ }
+ break;
}
},
// nsIBrowserTab
get window() {
if (!this.browser)
return null;
return this.browser.contentWindow;