diff --git a/app/browser/reducers/autoplayReducer.js b/app/browser/reducers/autoplayReducer.js index d18c14f06c0..21f856d342b 100644 --- a/app/browser/reducers/autoplayReducer.js +++ b/app/browser/reducers/autoplayReducer.js @@ -7,31 +7,26 @@ const appConstants = require('../../../js/constants/appConstants') const {makeImmutable} = require('../../common/state/immutableUtil') const {ipcMain, webContents} = require('electron') -const AppStore = require('../../../js/stores/appStore') const siteSettings = require('../../../js/state/siteSettings') -const settings = require('../../../js/constants/settings') const appActions = require('../../../js/actions/appActions') const {getOrigin} = require('../../../js/state/siteUtil') const locale = require('../../locale') const messages = require('../../../js/constants/messages') -const getSetting = require('../../../js/settings').getSetting -const {autoplayOption} = require('../../common/constants/settingsEnums') -const showAutoplayMessageBox = (tabId) => { +let notificationCallbacks = [] + +const showAutoplayMessageBox = (state, tabId) => { const tab = webContents.fromTabID(tabId) if (!tab || tab.isDestroyed()) { return } const location = tab.getURL() const origin = getOrigin(location) - if (getSetting(settings.AUTOPLAY_MEDIA) === autoplayOption.ALWAYS_ALLOW) { - appActions.changeSiteSetting(origin, 'autoplay', true) - return - } - const originSettings = siteSettings.getSiteSettingsForURL(AppStore.getState().get('siteSettings'), origin) + const originSettings = siteSettings.getSiteSettingsForURL(state.get('siteSettings'), origin) if (originSettings && originSettings.get('autoplay') === false) { return } + const message = locale.translation('allowAutoplay', {origin}) appActions.showNotification({ @@ -46,33 +41,60 @@ const showAutoplayMessageBox = (tabId) => { } }) - ipcMain.once(messages.NOTIFICATION_RESPONSE, (e, msg, buttonIndex, persist) => { - if (msg === message) { - appActions.hideNotification(message) - if (buttonIndex === 0) { - appActions.changeSiteSetting(origin, 'autoplay', true) - if (tab && !tab.isDestroyed()) { - tab.reload() - tab.on('destroyed', function temporaryAllow (e) { - if (!persist) { - appActions.removeSiteSetting(origin, 'autoplay') + if (!notificationCallbacks[tabId]) { + notificationCallbacks[tabId] = (e, msg, buttonIndex, persist) => { + if (msg === message) { + appActions.hideNotification(message) + if (buttonIndex === 0) { + appActions.changeSiteSetting(origin, 'autoplay', true) + if (tab && !tab.isDestroyed()) { + tab.reload() + const temporaryAllow = (e) => { + tab.removeListener('media-started-playing', temporaryAllow) + if (!persist) { + appActions.removeSiteSetting(origin, 'autoplay') + } } - }) + tab.on('media-started-playing', temporaryAllow) + } + } else { + if (persist) { + appActions.changeSiteSetting(origin, 'autoplay', false) + } } - } else { - if (persist) { - appActions.changeSiteSetting(origin, 'autoplay', false) + if (notificationCallbacks[tabId]) { + ipcMain.removeListener(messages.NOTIFICATION_RESPONSE, notificationCallbacks[tabId]) + delete notificationCallbacks[tabId] } } } - }) + ipcMain.on(messages.NOTIFICATION_RESPONSE, notificationCallbacks[tabId]) + } +} + +const hideAutoplayMessageBox = (tabId) => { + const tab = webContents.fromTabID(tabId) + if (!tab || tab.isDestroyed()) { + return + } + const location = tab.getURL() + const origin = getOrigin(location) + const message = locale.translation('allowAutoplay', {origin}) + appActions.hideNotification(message) + if (notificationCallbacks[tabId]) { + ipcMain.removeListener(messages.NOTIFICATION_RESPONSE, notificationCallbacks[tabId]) + delete notificationCallbacks[tabId] + } } const autoplayReducer = (state, action, immutableAction) => { action = immutableAction || makeImmutable(action) switch (action.get('actionType')) { case appConstants.APP_AUTOPLAY_BLOCKED: - showAutoplayMessageBox(action.get('tabId')) + showAutoplayMessageBox(state, action.get('tabId')) + break + case appConstants.APP_AUTOPLAY_DISMISSED: + hideAutoplayMessageBox(action.get('tabId')) break } return state diff --git a/app/renderer/components/frame/frame.js b/app/renderer/components/frame/frame.js index 5ad3ef64eff..a6d59b624a2 100644 --- a/app/renderer/components/frame/frame.js +++ b/app/renderer/components/frame/frame.js @@ -779,6 +779,7 @@ class Frame extends React.Component { if (this.frame.isEmpty()) { return } + appActions.autoplayDismissed(this.props.tabId) windowActions.setAudioPlaybackActive(this.frame, true) }) this.webview.addEventListener('media-paused', ({title}) => { diff --git a/js/actions/appActions.js b/js/actions/appActions.js index dba81112cdd..3ecc3ac8531 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -1292,6 +1292,17 @@ const appActions = { }) }, + /** + * Notifies autoplay notification can be dismissed + * @param {number} tabId - Tab id of current frame + */ + autoplayDismissed: function (tabId) { + dispatch({ + actionType: appConstants.APP_AUTOPLAY_DISMISSED, + tabId + }) + }, + /** * Handle 'save-password' event from muon */ diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index f8e12793899..761c4dcf9af 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -125,6 +125,7 @@ const appConstants = { APP_ON_GO_BACK_LONG: _, APP_ON_GO_FORWARD_LONG: _, APP_AUTOPLAY_BLOCKED: _, + APP_AUTOPLAY_DISMISSED: _, APP_SAVE_PASSWORD: _, APP_UPDATE_PASSWORD: _, APP_ADD_PASSWORD: _, /** @param {Object} passwordDetail */ diff --git a/js/state/contentSettings.js b/js/state/contentSettings.js index 0c94ff98f53..e94e4acf912 100644 --- a/js/state/contentSettings.js +++ b/js/state/contentSettings.js @@ -17,6 +17,7 @@ const urlParse = require('../../app/common/urlParse') const siteSettings = require('./siteSettings') const {registerUserPrefs} = require('./userPrefs') const {getSetting} = require('../settings') +const {autoplayOption} = require('../../app/common/constants/settingsEnums') const {getFlashResourceId} = require('../flash') const net = require('net') @@ -70,7 +71,7 @@ const getDefaultUserPrefContentSettings = (braveryDefaults, appSettings, appConf braveryDefaults = makeImmutable(braveryDefaults) return Immutable.fromJS({ autoplay: [{ - setting: 'block', + setting: getSetting(settings.AUTOPLAY_MEDIA) === autoplayOption.ALWAYS_ALLOW ? 'allow' : 'block', primaryPattern: '*' }], cookies: getDefault3rdPartyStorageSettings(braveryDefaults, appSettings, appConfig), diff --git a/test/bravery-components/notificationBarTest.js b/test/bravery-components/notificationBarTest.js index ee65f65839c..c756df1494f 100644 --- a/test/bravery-components/notificationBarTest.js +++ b/test/bravery-components/notificationBarTest.js @@ -285,211 +285,379 @@ describe('Autoplay test', function () { yield setup(this.app.client) }) - it('default always ask and block', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - }) + describe('autoplay', function () { + it('default always ask and block', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + }) - it('always allow', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .changeSetting('security.autoplay.media', autoplayOption.ALWAYS_ALLOW) - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - }) + it('always allow', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .changeSetting('security.autoplay.media', autoplayOption.ALWAYS_ALLOW) + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + }) - it('allow autoplay until tab closed', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - .click('button=Yes') - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .activateURLMode() - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .newTab({ url }) - .waitForTabCount(2) - .waitForUrl(url) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .closeTabByIndex(0) - .activateURLMode() - .click(reloadButton) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - }) + it('allow autoplay once', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('button=Yes') + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + }) - it('allow autoplay and remember', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - .click('[data-l10n-id=rememberDecision]') - .click('button=Yes') - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .activateURLMode() - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .newTab({ url }) - .waitForTabCount(2) - .waitForUrl(url) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .closeTabByIndex(0) - .activateURLMode() - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - }) + it('allow autoplay and remember', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('[data-l10n-id=rememberDecision]') + .click('button=Yes') + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .newTab({ url }) + .waitForTabCount(2) + .waitForUrl(url) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .closeTabByIndex(0) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + }) - it('keep blocking autoplay', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - .click('button=No') - .windowByUrl(Brave.browserWindowUrl) - .activateURLMode() - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) + it('keep blocking autoplay', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('button=No') + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + }) + + it('keep blocking autoplay and remember', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('[data-l10n-id=rememberDecision]') + .click('button=No') + .windowByUrl(Brave.browserWindowUrl) + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForElementCount('.notificationItem', 0) + }) }) - it('keep blocking autoplay and remember', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - .click('[data-l10n-id=rememberDecision]') - .click('button=No') - .windowByUrl(Brave.browserWindowUrl) - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForElementCount('.notificationItem', 0) + describe('auto-click-play', function () { + it('default always ask and block', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + }) + + it('always allow', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .changeSetting('security.autoplay.media', autoplayOption.ALWAYS_ALLOW) + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + }) + + it('allow autoplay once', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('button=Yes') + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + }) + + it('allow autoplay and remember', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('[data-l10n-id=rememberDecision]') + .click('button=Yes') + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .newTab({ url }) + .waitForTabCount(2) + .waitForUrl(url) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .closeTabByIndex(0) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + }) + + it('keep blocking autoplay', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('button=No') + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + }) + + it('keep blocking autoplay and remember', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('[data-l10n-id=rememberDecision]') + .click('button=No') + .windowByUrl(Brave.browserWindowUrl) + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForElementCount('.notificationItem', 0) + }) }) }) diff --git a/test/fixtures/auto-click-play.html b/test/fixtures/auto-click-play.html new file mode 100644 index 00000000000..55581055530 --- /dev/null +++ b/test/fixtures/auto-click-play.html @@ -0,0 +1,29 @@ + + +
+ +