Bug 936724 - Implement addInput/removeInput in InputMethod API. r=yxl, r=khuey

This commit is contained in:
Tim Chien 2014-12-09 14:20:40 -05:00
Родитель 4e5dbde020
Коммит 7086ef24a8
4 изменённых файлов: 210 добавлений и 22 удалений

Просмотреть файл

@ -725,6 +725,8 @@ var CustomEventManager = {
CaptivePortalLoginHelper.handleEvent(detail);
break;
case 'inputmethod-update-layouts':
case 'inputregistry-add':
case 'inputregistry-remove':
KeyboardHelper.handleEvent(detail);
break;
case 'do-command':
@ -868,7 +870,17 @@ let IndexedDBPromptHelper = {
let KeyboardHelper = {
handleEvent: function keyboard_handleEvent(detail) {
Keyboard.setLayouts(detail.layouts);
switch (detail.type) {
case 'inputmethod-update-layouts':
Keyboard.setLayouts(detail.layouts);
break;
case 'inputregistry-add':
case 'inputregistry-remove':
Keyboard.inputRegistryGlue.returnMessage(detail);
break;
}
}
};

Просмотреть файл

@ -19,6 +19,36 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");
XPCOMUtils.defineLazyGetter(this, "appsService", function() {
return Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
});
let Utils = {
getMMFromMessage: function u_getMMFromMessage(msg) {
let mm;
try {
mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader.messageManager;
} catch(e) {
mm = msg.target;
}
return mm;
},
checkPermissionForMM: function u_checkPermissionForMM(mm, permName) {
let testing = false;
try {
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
} catch (e) { }
if (testing) {
return true;
}
return mm.assertPermission(permName);
}
};
this.Keyboard = {
_formMM: null, // The current web page message manager.
_keyboardMM: null, // The keyboard app message manager.
@ -72,6 +102,8 @@ this.Keyboard = {
for (let name of this._systemMessageName) {
ppmm.addMessageListener('System:' + name, this);
}
this.inputRegistryGlue = new InputRegistryGlue();
},
observe: function keyboardObserve(subject, topic, data) {
@ -122,12 +154,7 @@ this.Keyboard = {
return;
}
try {
mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader.messageManager;
} catch(e) {
mm = msg.target;
}
mm = Utils.getMMFromMessage(msg);
// That should never happen.
if (!mm) {
@ -135,16 +162,10 @@ this.Keyboard = {
return;
}
let testing = false;
try {
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
} catch (e) {
}
let perm = (msg.name.indexOf("Keyboard:") === 0) ? "input"
: "input-manage";
if (!isKeyboardRegistration && !testing &&
!mm.assertPermission(perm)) {
if (!isKeyboardRegistration && !Utils.checkPermissionForMM(mm, perm)) {
dump("Keyboard message " + msg.name +
" from a content process with no '" + perm + "' privileges.");
return;
@ -364,4 +385,93 @@ this.Keyboard = {
}
};
function InputRegistryGlue() {
this._messageId = 0;
this._msgMap = new Map();
ppmm.addMessageListener('InputRegistry:Add', this);
ppmm.addMessageListener('InputRegistry:Remove', this);
};
InputRegistryGlue.prototype.receiveMessage = function(msg) {
let mm = Utils.getMMFromMessage(msg);
if (!Utils.checkPermissionForMM(mm, 'input')) {
dump("InputRegistryGlue message " + msg.name +
" from a content process with no 'input' privileges.");
return;
}
switch (msg.name) {
case 'InputRegistry:Add':
this.addInput(msg, mm);
break;
case 'InputRegistry:Remove':
this.removeInput(msg, mm);
break;
}
};
InputRegistryGlue.prototype.addInput = function(msg, mm) {
let msgId = this._messageId++;
this._msgMap.set(msgId, {
mm: mm,
requestId: msg.data.requestId
});
let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId);
SystemAppProxy.dispatchEvent({
type: 'inputregistry-add',
id: msgId,
manifestURL: manifestURL,
inputId: msg.data.inputId,
inputManifest: msg.data.inputManifest
});
};
InputRegistryGlue.prototype.removeInput = function(msg, mm) {
let msgId = this._messageId++;
this._msgMap.set(msgId, {
mm: mm,
requestId: msg.data.requestId
});
let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId);
SystemAppProxy.dispatchEvent({
type: 'inputregistry-remove',
id: msgId,
manifestURL: manifestURL,
inputId: msg.data.inputId
});
};
InputRegistryGlue.prototype.returnMessage = function(detail) {
if (!this._msgMap.has(detail.id)) {
return;
}
let { mm, requestId } = this._msgMap.get(detail.id);
this._msgMap.delete(detail.id);
if (Cu.isDeadWrapper(mm)) {
return;
}
if (!('error' in detail)) {
mm.sendAsyncMessage('InputRegistry:Result:OK', {
requestId: requestId
});
} else {
mm.sendAsyncMessage('InputRegistry:Result:Error', {
error: detail.error,
requestId: requestId
});
}
};
this.Keyboard.init();

Просмотреть файл

@ -149,6 +149,8 @@ MozInputMethodManager.prototype = {
function MozInputMethod() { }
MozInputMethod.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
_inputcontext: null,
_wrappedInputContext: null,
_layouts: {},
@ -196,6 +198,8 @@ MozInputMethod.prototype = {
cpmm.addWeakMessageListener('Keyboard:SelectionChange', this);
cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this);
cpmm.addWeakMessageListener('Keyboard:LayoutsChange', this);
cpmm.addWeakMessageListener('InputRegistry:Result:OK', this);
cpmm.addWeakMessageListener('InputRegistry:Result:Error', this);
},
uninit: function mozInputMethodUninit() {
@ -210,21 +214,26 @@ MozInputMethod.prototype = {
cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this);
cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this);
cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this);
cpmm.removeWeakMessageListener('InputRegistry:Result:OK', this);
cpmm.removeWeakMessageListener('InputRegistry:Result:Error', this);
this.setActive(false);
},
receiveMessage: function mozInputMethodReceiveMsg(msg) {
if (!WindowMap.isActive(this._window)) {
if (!msg.name.startsWith('InputRegistry') &&
!WindowMap.isActive(this._window)) {
return;
}
let json = msg.json;
let data = msg.data;
let resolver = ('requestId' in data) ?
this.takePromiseResolver(data.requestId) : null;
switch(msg.name) {
case 'Keyboard:FocusChange':
if (json.type !== 'blur') {
if (data.type !== 'blur') {
// XXX Bug 904339 could receive 'text' event twice
this.setInputContext(json);
this.setInputContext(data);
}
else {
this.setInputContext(null);
@ -232,14 +241,24 @@ MozInputMethod.prototype = {
break;
case 'Keyboard:SelectionChange':
if (this.inputcontext) {
this._inputcontext.updateSelectionContext(json, false);
this._inputcontext.updateSelectionContext(data, false);
}
break;
case 'Keyboard:GetContext:Result:OK':
this.setInputContext(json);
this.setInputContext(data);
break;
case 'Keyboard:LayoutsChange':
this._layouts = json;
this._layouts = data;
break;
case 'InputRegistry:Result:OK':
resolver.resolve();
break;
case 'InputRegistry:Result:Error':
resolver.reject(data.error);
break;
}
},
@ -330,6 +349,31 @@ MozInputMethod.prototype = {
}
},
addInput: function(inputId, inputManifest) {
return this._sendPromise(function(resolverId) {
let appId = this._window.document.nodePrincipal.appId;
cpmm.sendAsyncMessage('InputRegistry:Add', {
requestId: resolverId,
inputId: inputId,
inputManifest: inputManifest,
appId: appId
});
}.bind(this));
},
removeInput: function(inputId) {
return this._sendPromise(function(resolverId) {
let appId = this._window.document.nodePrincipal.appId;
cpmm.sendAsyncMessage('InputRegistry:Remove', {
requestId: resolverId,
inputId: inputId,
appId: appId
});
}.bind(this));
},
setValue: function(value) {
this._ensureIsSystem();
cpmm.sendAsyncMessage('System:SetValue', {
@ -361,6 +405,14 @@ MozInputMethod.prototype = {
throw new this._window.DOMError("Security",
"Should have 'input-manage' permssion.");
}
},
_sendPromise: function(callback) {
let self = this;
return this.createPromise(function(resolve, reject) {
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
callback(resolverId);
});
}
};

Просмотреть файл

@ -29,6 +29,20 @@ interface MozInputMethod : EventTarget {
// Activate or decactive current input method window.
void setActive(boolean isActive);
// Add a dynamically declared input.
//
// The id must not be the same with any statically declared input in the app
// manifest. If an input of the same id is already declared, the info of that
// input will be updated.
Promise<void> addInput(DOMString inputId, object inputManifest);
// Remove a dynamically declared input.
//
// The id must not be the same with any statically declared input in the app
// manifest. Silently resolves if the input is not previously declared;
// rejects if attempt to remove a statically declared input.
Promise<void> removeInput(DOMString id);
// The following are internal methods for Firefox OS system app only.
// Set the value on the currently focused element. This has to be used