Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #31077 from luke-chang/1182189_separate_hierarchy_…
Browse files Browse the repository at this point in the history
…focus

Bug 1182189 - Accessibility Regression in Utility tray exclusive visibility, r=johnhu
  • Loading branch information
Luke Chang committed Jul 28, 2015
2 parents 7691b37 + adba942 commit 5a049cc
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 67 deletions.
5 changes: 4 additions & 1 deletion apps/system/js/app_window_manager.js
Expand Up @@ -120,6 +120,10 @@
},

setHierarchy: function(active) {
this._activeApp && this._activeApp.setVisibleForScreenReader(active);
},

setFocus: function(active) {
if (!this._activeApp) {
this.debug('No active app.');
return false;
Expand All @@ -134,7 +138,6 @@
this._activeApp.blur();
this._activeApp.setNFCFocus(false);
}
this._activeApp.setVisibleForScreenReader(active);
return true;
},

Expand Down
22 changes: 12 additions & 10 deletions apps/system/js/hierarchy_manager.js
Expand Up @@ -107,17 +107,21 @@
this.debug('next top most is null.');
}

if (this._topMost && this._topMost.setHierarchy &&
this._topMost.setHierarchy(true)) {
if (this._topMost && this._topMost.setFocus &&
this._topMost.setFocus(true)) {
// Blur previous module only when current module is successfully
// focused.
lastTopMost && lastTopMost.setHierarchy &&
lastTopMost.setHierarchy(false);

lastTopMost && lastTopMost.setFocus &&
lastTopMost.setFocus(false);
this._topMost && this._topMost.setFocus &&
this._topMost.setFocus(true);
}

lastTopMost && lastTopMost.setHierarchy &&
lastTopMost.setHierarchy(false);
this._topMost && this._topMost.setHierarchy &&
this._topMost.setHierarchy(true);
this._topMost.setHierarchy(true);

this.publish('changed');
} else {
this.debug('top most is the same.', this._topMost ?
Expand All @@ -136,10 +140,8 @@
},

focus: function(module) {
if (!module) {
this._topMost.setHierarchy(true);
} else if (this._topMost === module) {
module.setHierarchy(true);
if (!module || module === this._topMost) {
this._topMost.setFocus && this._topMost.setFocus(true);
}
},

Expand Down
6 changes: 4 additions & 2 deletions apps/system/js/rocketbar.js
Expand Up @@ -58,11 +58,13 @@
},

setHierarchy: function(active) {
this.searchWindow && this.searchWindow.setVisibleForScreenReader(active);
},

setFocus: function(active) {
if (active) {
this.focus();
}
this.searchWindow &&
this.searchWindow.setVisibleForScreenReader(active);
return true;
},

Expand Down
6 changes: 5 additions & 1 deletion apps/system/js/secure_window_manager.js
Expand Up @@ -64,13 +64,17 @@
SecureWindowManager.prototype.HIERARCHY_MANAGER = 'SecureWindowManager';

SecureWindowManager.prototype.setHierarchy = function(active) {
if (this.states.activeApp) {
this.states.activeApp.setVisibleForScreenReader(active);
}
};
SecureWindowManager.prototype.setFocus = function(active) {
if (!this.states.activeApp) {
return false;
}
if (active) {
this.states.activeApp.focus();
}
this.states.activeApp.setVisibleForScreenReader(active);
return true;
};
SecureWindowManager.prototype.getActiveWindow = function() {
Expand Down
7 changes: 6 additions & 1 deletion apps/system/js/system_dialog_manager.js
Expand Up @@ -76,13 +76,18 @@
};

SystemDialogManager.prototype.setHierarchy = function(active) {
if (this.states.activeDialog) {
this.states.activeDialog._setVisibleForScreenReader(active);
}
};

SystemDialogManager.prototype.setFocus = function(active) {
if (!this.states.activeDialog) {
return false;
}
if (active) {
this.states.activeDialog.focus();
}
this.states.activeDialog._setVisibleForScreenReader(active);
return true;
};

Expand Down
2 changes: 1 addition & 1 deletion apps/system/js/task_manager.js
Expand Up @@ -120,7 +120,7 @@
TaskManager.prototype.EVENT_PREFIX = 'taskmanager';
TaskManager.prototype.name = 'TaskManager';

TaskManager.prototype.setHierarchy = function() {
TaskManager.prototype.setFocus = function() {
return true;
};
/**
Expand Down
2 changes: 1 addition & 1 deletion apps/system/js/utility_tray.js
Expand Up @@ -139,7 +139,7 @@ window.UtilityTray = {
ambientHeight: 0,
hideStartCallback: null,

setHierarchy: function() {
setFocus: function() {
return false;
},

Expand Down
3 changes: 1 addition & 2 deletions apps/system/test/marionette/hierarchy_test.js
Expand Up @@ -129,8 +129,7 @@
client.apps.launch('app://' + CALLER_APP);
utilityTray.open();
assert.equal(getTopMost(), 'UtilityTray');
// Don't blur current app when utilityTray is pulled down.
assert.equal(getActiveAppWindowAriaHidden(), 'false');
assert.equal(getActiveAppWindowAriaHidden(), 'true');
utilityTray.close();
assert.equal(getTopMost(), 'AppWindowManager');
assert.equal(getActiveAppWindowAriaHidden(), 'false');
Expand Down
37 changes: 16 additions & 21 deletions apps/system/test/unit/app_window_manager_test.js
Expand Up @@ -1138,44 +1138,39 @@ suite('system/AppWindowManager', function() {
this.sinon.stub(MockWrapperFactory, 'isLaunchingWindow').returns(false);
this.sinon.stub(MockAppWindowFactory, 'isLaunchingWindow').returns(false);
subject._activeApp = app1;
this.sinon.stub(app1, 'focus');
this.sinon.stub(app1, 'blur');
this.sinon.stub(app1, 'setVisibleForScreenReader');
this.sinon.stub(app1, 'setNFCFocus');

subject.setHierarchy(true);
assert.isTrue(app1.focus.called);
assert.isTrue(app1.setVisibleForScreenReader.calledWith(true));
assert.isTrue(app1.setNFCFocus.calledWith(true));

subject.setHierarchy(false);
assert.isTrue(app1.blur.calledOnce);
assert.isTrue(app1.setVisibleForScreenReader.calledWith(false));
});

test('setHierarchy(true) while launching a new window', function() {
this.sinon.stub(MockWrapperFactory, 'isLaunchingWindow').returns(true);
test('setFocus', function() {
this.sinon.stub(MockWrapperFactory, 'isLaunchingWindow').returns(false);
this.sinon.stub(MockAppWindowFactory, 'isLaunchingWindow').returns(false);
subject._activeApp = app1;
this.sinon.stub(app1, 'focus');

subject.setHierarchy(true);
assert.isFalse(app1.focus.called);
});

test('setHierarchy', function() {
subject._activeApp = app1;
this.sinon.stub(app1, 'focus');
this.sinon.stub(app1, 'blur');
this.sinon.stub(app1, 'setVisibleForScreenReader');
this.sinon.stub(app1, 'setNFCFocus');
subject.setHierarchy(true);

subject.setFocus(true);
assert.isTrue(app1.focus.called);
assert.isTrue(app1.setVisibleForScreenReader.calledWith(true));
assert.isTrue(app1.setNFCFocus.calledWith(true));

subject.setHierarchy(false);
subject.setFocus(false);
assert.isTrue(app1.blur.calledOnce);
assert.isTrue(app1.setVisibleForScreenReader.calledWith(false));
});

test('setHierarchy(true) while launching a new window', function() {
this.sinon.stub(MockWrapperFactory, 'isLaunchingWindow').returns(true);
this.sinon.stub(MockAppWindowFactory, 'isLaunchingWindow').returns(false);
subject._activeApp = app1;
this.sinon.stub(app1, 'focus');

subject.setHierarchy(true);
assert.isFalse(app1.focus.called);
});

test('focus is redirected', function() {
Expand Down
65 changes: 53 additions & 12 deletions apps/system/test/unit/hierarchy_manager_test.js
Expand Up @@ -23,6 +23,7 @@ suite('system/HierarchyManager', function() {
isActive: function() {},
getActiveWindow: function() {},
setHierarchy: function() {},
setFocus: function() {},
respondToHierarchyEvent: function() {}
};
var fakeAppWindowManager = {
Expand All @@ -31,6 +32,7 @@ suite('system/HierarchyManager', function() {
isActive: function() {},
getActiveWindow: function() {},
setHierarchy: function() {},
setFocus: function() {},
respondToHierarchyEvent: function() {}
};
var fakeActionMenu = {
Expand All @@ -39,13 +41,15 @@ suite('system/HierarchyManager', function() {
isActive: function() {},
getActiveWindow: function() {},
setHierarchy: function() {},
setFocus: function() {},
respondToHierarchyEvent: function() {}
};
var fakeSystemDialogManager = {
name: 'SystemDialogManager',
EVENT_PREFIX: 'sdm',
isActive: function() {},
setHierarchy: function() {},
setFocus: function() {},
respondToHierarchyEvent: function() {}
};
var fakeRocketbar = {
Expand All @@ -54,20 +58,23 @@ suite('system/HierarchyManager', function() {
isActive: function() {},
getActiveWindow: function() {},
setHierarchy: function() {},
setFocus: function() {},
respondToHierarchyEvent: function() {}
};
var fakeInitLogoHandler = {
name: 'InitLogoHandler',
EVENT_PREFIX: 'il',
isActive: function() {},
setHierarchy: function() {},
setFocus: function() {},
respondToHierarchyEvent: function() {}
};
var fakeTaskManager = {
name: 'TaskManager',
EVENT_PREFIX: 'tm',
isActive: function() {},
setHierarchy: function() {},
setFocus: function() {},
respondToHierarchyEvent: function() {}
};

Expand Down Expand Up @@ -194,6 +201,52 @@ suite('system/HierarchyManager', function() {
});
});

suite('setHierarchy and setFocus in updateHierarchy', function() {
setup(function() {
this.sinon.stub(fakeAppWindowManager, 'isActive').returns(true);
this.sinon.stub(fakeAppWindowManager, 'setHierarchy');
this.sinon.stub(fakeAppWindowManager, 'setFocus').returns(true);
this.sinon.stub(fakeSystemDialogManager, 'isActive').returns(true);
this.sinon.stub(fakeSystemDialogManager, 'setHierarchy');
this.sinon.stub(fakeSystemDialogManager, 'setFocus');
subject.registerHierarchy(fakeAppWindowManager);
});

teardown(function() {
subject.unregisterHierarchy(fakeAppWindowManager);
subject.unregisterHierarchy(fakeSystemDialogManager);
});

test('should invoke "setHierarchy" of modules', function() {
assert.isTrue(fakeAppWindowManager.setHierarchy.calledWith(true));
fakeAppWindowManager.setHierarchy.reset();

subject.registerHierarchy(fakeSystemDialogManager);
assert.isTrue(fakeAppWindowManager.setHierarchy.calledWith(false));
assert.isTrue(fakeSystemDialogManager.setHierarchy.calledWith(true));
});

test('should invoke "setFocus" of modules', function() {
assert.isTrue(fakeAppWindowManager.setFocus.calledWith(true));
fakeAppWindowManager.setFocus.reset();
fakeSystemDialogManager.setFocus.returns(true);
subject.registerHierarchy(fakeSystemDialogManager);
assert.isTrue(fakeAppWindowManager.setFocus.calledWith(false));
assert.isTrue(fakeSystemDialogManager.setFocus.calledWith(true));
assert.isTrue(fakeSystemDialogManager.setFocus.calledTwice);
});

test('should not blur lower priority module when higher priority module ' +
'is not focused successfully', function() {
fakeAppWindowManager.setFocus.reset();
fakeSystemDialogManager.setFocus.returns(false);
subject.registerHierarchy(fakeSystemDialogManager);
assert.isTrue(fakeSystemDialogManager.setFocus.calledWith(true));
assert.isTrue(fakeSystemDialogManager.setFocus.calledOnce);
assert.isFalse(fakeAppWindowManager.setFocus.called);
});
});

suite('focus request', function() {
test('should not focus when lower priority module ' +
'requests to be focused', function() {
Expand All @@ -218,18 +271,6 @@ suite('system/HierarchyManager', function() {
assert.isTrue(fakeSystemDialogManager.setHierarchy.calledWith(true));
});

test('should not blur lower priority module ' +
'when higher priority module is not focused successfully', function() {
this.sinon.stub(fakeAppWindowManager, 'setHierarchy');
this.sinon.stub(fakeAppWindowManager, 'isActive').returns(true);
this.sinon.stub(fakeSystemDialogManager, 'isActive').returns(true);
this.sinon.stub(fakeSystemDialogManager, 'setHierarchy').returns(false);
subject.registerHierarchy(fakeAppWindowManager);
subject.registerHierarchy(fakeSystemDialogManager);
subject.focus(fakeAppWindowManager);
assert.isFalse(fakeAppWindowManager.setHierarchy.calledOnce);
});

test('should focus top most without a module', function() {
this.sinon.stub(fakeAppWindowManager, 'setHierarchy');
this.sinon.stub(fakeAppWindowManager, 'isActive').returns(true);
Expand Down
11 changes: 6 additions & 5 deletions apps/system/test/unit/rocketbar_test.js
Expand Up @@ -55,22 +55,23 @@ suite('system/Rocketbar', function() {
});

suite('Hierarchy functions', function() {
test('setHierarchy: false', function() {
test('setHierarchy', function() {
var searchWindow = new MockSearchWindow();
subject.searchWindow = searchWindow;
this.sinon.stub(searchWindow, 'setVisibleForScreenReader');
subject.setHierarchy(false);
assert.isTrue(searchWindow.setVisibleForScreenReader.calledWith(false));
searchWindow.setVisibleForScreenReader.reset();
subject.setHierarchy(true);
assert.isTrue(searchWindow.setVisibleForScreenReader.calledWith(true));
});

test('setHierarchy: true', function() {
test('setFocus', function() {
var searchWindow = new MockSearchWindow();
subject.searchWindow = searchWindow;
this.sinon.stub(searchWindow, 'setVisibleForScreenReader');
this.sinon.stub(subject, 'focus');
subject.setHierarchy(true);
subject.setFocus(true);
assert.isTrue(subject.focus.called);
assert.isTrue(searchWindow.setVisibleForScreenReader.calledWith(true));
});

test('Should register hierarchy on start', function() {
Expand Down
16 changes: 12 additions & 4 deletions apps/system/test/unit/secure_window_manager_test.js
Expand Up @@ -55,16 +55,24 @@ suite('system/SecureWindowManager', function() {
var fakeSecureWindow = new MockSecureWindow();
this.sinon.stub(fakeSecureWindow, 'setVisibleForScreenReader');
this.sinon.stub(fakeSecureWindow, 'isActive').returns(true);
this.sinon.stub(fakeSecureWindow, 'focus');
window.secureWindowManager.activateApp(fakeSecureWindow);
assert.isTrue(window.secureWindowManager.setHierarchy(true));
window.secureWindowManager.setHierarchy(true);
assert.isTrue(
fakeSecureWindow.setVisibleForScreenReader.calledWith(true));
assert.isTrue(fakeSecureWindow.focus.called);
fakeSecureWindow.setVisibleForScreenReader.reset();
window.secureWindowManager.setHierarchy(false);
assert.isTrue(
fakeSecureWindow.setVisibleForScreenReader.calledWith(false));
});

test('setFocus', function() {
var fakeSecureWindow = new MockSecureWindow();
this.sinon.stub(fakeSecureWindow, 'isActive').returns(true);
this.sinon.stub(fakeSecureWindow, 'focus');
window.secureWindowManager.activateApp(fakeSecureWindow);
assert.isTrue(window.secureWindowManager.setFocus(true));
assert.isTrue(fakeSecureWindow.focus.called);
});
});

suite('Handle events', function() {
Expand Down Expand Up @@ -97,7 +105,7 @@ suite('system/SecureWindowManager', function() {
assert.isNull(
window.secureWindowManager.states.activeApp,
'the app was still activated');
assert.isFalse(window.secureWindowManager.setHierarchy(true));
assert.isFalse(window.secureWindowManager.setFocus(true));
assert.isUndefined(window.secureWindowManager
.states.runningApps[appFake.instanceID],
'the app was still registered in the maanger');
Expand Down

0 comments on commit 5a049cc

Please sign in to comment.