Project: titanium
Issue TIMOB-23476: Android: constants are writable
Constants in Android are able to be "overwritten". Things like Ti.App.EVENT_ACCESSIBILITY_ANNOUNCEMENT should be truly constant and the user shouldn't be able to overwrite the value or delete the property. Currently you can "overwrite" the value: {code:javascript} Ti.API.info('original value: ' + Ti.App.EVENT_ACCESSIBILITY_ANNOUNCEMENT); Ti.App.EVENT_ACCESSIBILITY_ANNOUNCEMENT = 'my very own made-up value'; Ti.API.info('modified value: ' + Ti.App.EVENT_ACCESSIBILITY_ANNOUNCEMENT); {code}' I think the underlying cause here is actually different than TIMOB-23475. I Believe this is because we hang 'constants' on the prototype of the proxy (i.e. {{Object.getPrototypeOf(Ti.App);}}) while the global object living at {{Ti.App}} is an instance. So what's happening looks to be "property shadowing" where we're actually adding a new {{EVENT_ACCESSIBILITY_ANNOUNCEMENT}} property with our own value onto the instance of {{Ti.App}} that lives in the global namespace at {{Ti.App}}. This instance property "shadows" the original constant declared on the prototype. To prove my point, calling Object.getPrototypeOf(Ti.App) gives: {code:javascript} {"Properties":{"apiName":"Ti.App.Properties","bubbleParent":true},"Android":{"bubbleParent":true,"launchIntent":{"action":null,"bubbleParent":true,"packageName":"dfg.df","data":null,"type":null,"apiName":"Ti.Android.Intent","className":"dfg.df.ExampleActivity","flags":268435456},"appVersionCode":1,"appVersionName":"1.0","apiName":"Ti.App.Android","R":{"bubbleParent":true,"apiName":"Ti.Android.R"}},"EVENT_ACCESSIBILITY_ANNOUNCEMENT":"accessibilityannouncement","EVENT_ACCESSIBILITY_CHANGED":"accessibilitychanged"} {code} You can clearly see the constants there. It makes sense to hang the constants at the "prototype" level since they're supposed to be "class-level/static" constants and we shouldn't need to have every instance hold a copy. However, it looks like we're not preventing shadowing properly (even though it appears we're setting the constant property attributes to ReadOnly|DontDelete). See https://github.com/getify/You-Dont-Know-JS/issues/91 for discussion on cases where there seems to be prevented shadowing. One possible solution may be to do an Object.seal() on all our proxies after they're set up. This marks all properties as DontDelete and prevents new properties from being added.
Story points: 5