/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package blackberry.system;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.io.Connection;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.io.file.FileSystemRegistry;
import org.w3c.dom.Document;
import net.rim.blackberry.api.homescreen.HomeScreen;
import net.rim.device.api.applicationcontrol.ApplicationPermissions;
import net.rim.device.api.applicationcontrol.ApplicationPermissionsManager;
import net.rim.device.api.browser.field2.BrowserField;
import net.rim.device.api.gps.GPSInfo;
import net.rim.device.api.script.ScriptEngine;
import net.rim.device.api.system.CodeModuleManager;
import net.rim.device.api.system.CoverageInfo;
import net.rim.device.api.system.DeviceInfo;
import net.rim.device.api.system.RadioInfo;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.Touchscreen;
import net.rim.device.api.util.SimpleSortingVector;
import net.rim.device.api.web.WidgetConfig;
import net.rim.device.api.web.WidgetException;
import blackberry.common.util.JSUtilities;
import blackberry.common.util.json4j.JSONObject;
import blackberry.core.IJSExtension;
import blackberry.core.JSExtensionRequest;
import blackberry.core.JSExtensionResponse;
import blackberry.core.JSExtensionReturnValue;
/**
* JavaScript extension for blackberry.system
*/
public class SystemExtension implements IJSExtension, ISystemExtensionConstants {
private static Vector SUPPORTED_METHODS;
static {
SUPPORTED_METHODS = new Vector();
SUPPORTED_METHODS.addElement( FUNCTION_HAS_PERMISSION );
SUPPORTED_METHODS.addElement( FUNCTION_HAS_CAPABILITY );
SUPPORTED_METHODS.addElement( FUNCTION_HAS_DATA_COVERAGE );
SUPPORTED_METHODS.addElement( FUNCTION_IS_MASS_STORAGE_ACTIVE );
SUPPORTED_METHODS.addElement( FUNCTION_SET_HOME_SCREEN );
SUPPORTED_METHODS.addElement( FUNCTION_GET );
SUPPORTED_METHODS.addElement( SOFTWARE_VERSION );
SUPPORTED_METHODS.addElement( SCRIPT_API_VERSION );
SUPPORTED_METHODS.addElement( MODEL );
}
private static String[] JS_FILES = { "system_dispatcher.js", "system_ns.js" };
public String[] getFeatureList() {
String[] featureList;
featureList = new String[ 1 ];
featureList[ 0 ] = FEATURE_ID;
return featureList;
}
/**
* @param capability is the ability that the device can perform </br>
* Possible values are:</br><code>
* input.keyboard.issuretype input.touch</br>
* media.audio.capture media.video.capture media.recording</br>
* location.gps location.maps storage.memorycard</br>
* network.bluetooth network.wlan (WLAN wireless family includes 802.11, 802.11a, 802.11b, 802.11g)</br>
* network.3gpp (3GPP wireless family includes GPRS, EDGE, UMTS, GERAN, UTRAN, and GAN)</br>
* network.cdma (CDMA wireless family includes CDMA1x and EVDO)</br>
* network.iden</br></code>
* @return if has the capability, return true; or return false.
*/
public boolean hasCapability( String capability ) {
return isCapable( capability );
}
/**
* Check if device has network coverage
* @return Returns true if the device is in coverage, otherwise return false
*/
public boolean hasDataCoverage() {
return CoverageInfo.getCoverageStatus() != CoverageInfo.COVERAGE_NONE;
}
/**
* Determines the level of access to the requested module.
* @param module
* @return 0 - ALLOW, 1 - DENY, 2 - PROMPT, 3 - NOTSET
*/
public int hasPermission( String module ) {
switch( checkPermission( module ) ) {
case ApplicationPermissions.VALUE_ALLOW:
return ALLOW_VALUE;
case ApplicationPermissions.VALUE_DENY:
return DENY_VALUE;
case ApplicationPermissions.VALUE_PROMPT:
return PROMPT_VALUE;
default:
return NOTSET_VALUE;
}
}
private String[] checkAllPermissions() {
Vector permissions = new Vector();
String[] result = null;
for( int i = 0; i < ALL_PERMISSIONS.length; i++ ) {
if( hasPermission( ALL_PERMISSIONS[ i ] ) == ALLOW_VALUE ) {
permissions.addElement( ALL_PERMISSIONS[ i ] );
}
}
result = new String[ permissions.size() ];
if( !permissions.isEmpty() ) {
permissions.copyInto( result );
}
return result;
}
private String getSoftwareVersion() {
return DeviceInfo.getSoftwareVersion();
}
private String getModel() {
return DeviceInfo.getDeviceName();
}
/**
* Implements invoke() of interface IJSExtension. Methods of extension will be called here.
* @throws WidgetException if specified method cannot be recognized
*/
public void invoke( JSExtensionRequest request, JSExtensionResponse response ) throws WidgetException {
String method = request.getMethodName();
Object[] args = request.getArgs();
String msg = "";
int code = JSExtensionReturnValue.SUCCESS;
JSONObject data = new JSONObject();
JSONObject returnValue = null;
if( !SUPPORTED_METHODS.contains( method ) ) {
throw new WidgetException("Undefined method: " + method);
}
try {
if( method.equals( FUNCTION_HAS_PERMISSION ) ) {
String module = (String) args[ 0 ];
data.put( ARG_MODULE, module );
data.put( FUNCTION_HAS_PERMISSION, hasPermission( module ) );
} else if( method.equals( FUNCTION_HAS_CAPABILITY ) ) {
String capability = (String) args[ 0 ];
data.put( ARG_CAPABILITY, capability );
data.put( FUNCTION_HAS_CAPABILITY, hasCapability( capability ) );
} else if( method.equals( FUNCTION_HAS_DATA_COVERAGE ) ) {
data.put( FUNCTION_HAS_DATA_COVERAGE, hasDataCoverage() );
} else if( method.equals( FUNCTION_IS_MASS_STORAGE_ACTIVE ) ) {
data.put( FUNCTION_IS_MASS_STORAGE_ACTIVE, isMassStorageActive() );
} else if( method.equals( FUNCTION_SET_HOME_SCREEN ) ) {
String picture = (String) args[ 0 ];
data.put( ARG_PICTURE, picture );
setHomeScreenBackground( picture );
} else if( method.equals( SOFTWARE_VERSION ) ) {
data.put( SOFTWARE_VERSION, getSoftwareVersion() );
} else if( method.equals( SCRIPT_API_VERSION ) ) {
data.put( SCRIPT_API_VERSION, getSoftwareVersion() );
} else if( method.equals( MODEL ) ) {
data.put( MODEL, getModel() );
} else if ( method.equals( FUNCTION_GET ) ) {
data.put( FUNCTION_HAS_CAPABILITY, checkAllCapabilties() );
data.put( SOFTWARE_VERSION, getSoftwareVersion() );
data.put( FUNCTION_HAS_PERMISSION, checkAllPermissions() );
data.put( MODEL, getModel() );
data.put( FUNCTION_HAS_DATA_COVERAGE, hasDataCoverage() );
data.put( SCRIPT_API_VERSION, getSoftwareVersion() );
data.put( FUNCTION_IS_MASS_STORAGE_ACTIVE, isMassStorageActive() );
}
} catch( Exception e ) {
msg = e.getMessage();
code = JSExtensionReturnValue.FAIL;
}
returnValue = new JSExtensionReturnValue( msg, code, data ).getReturnValue();
response.setPostData( returnValue.toString().getBytes() );
}
/**
* Returns whether USB MassStorage mode is active.
* This method is not implemented yet
* @return false
*/
private boolean isMassStorageActive() {
return false;
}
// Not sure if it's a published API, there is no this API in WebWorks
// API reference. It returns UNDEFINED in old style java code.
/**
* Set background of home screen
* @param filepath - path of image file
* @throws Exception
*/
public void setHomeScreenBackground( String filePath ) throws Exception {
FileConnection fileConnection = null;
try {
Connection con = Connector.open( filePath );
if( con != null && con instanceof FileConnection ) {
fileConnection = (FileConnection) con;
if( !fileConnection.exists() || fileConnection.isDirectory() ) {
throw new Exception( "Invalid file URI" );
}
// set home screen background
HomeScreen.setBackgroundImage( filePath );
}
} finally {
if( fileConnection != null ) {
fileConnection.close();
}
}
}
private int checkPermission( String module ) {
ApplicationPermissionsManager apm = ApplicationPermissionsManager.getInstance();
if( module.equals( BLACKBERRY_APP ) ) {
return apm.getPermission( ApplicationPermissions.PERMISSION_APPLICATION_MANAGEMENT );
} else if( module.equals( BLACKBERRY_INVOKE ) || module.equals( BLACKBERRY_INVOKE_ADDRESSBOOKARGUMENTS )
|| module.equals( BLACKBERRY_INVOKE_BROWSERARGUMENTS ) || module.equals( BLACKBERRY_INVOKE_CALENDARARGUMENTS )
|| module.equals( BLACKBERRY_INVOKE_CAMERAARGUMENTS ) || module.equals( BLACKBERRY_INVOKE_JAVAARGUMENTS )
|| module.equals( BLACKBERRY_INVOKE_MAPSARGUMENTS ) || module.equals( BLACKBERRY_INVOKE_MESSAGEARGUMENTS )
|| module.equals( BLACKBERRY_INVOKE_PHONEARGUMENTS ) || module.equals( BLACKBERRY_INVOKE_SEARCHARGUMENTS )
|| module.equals( BLACKBERRY_INVOKE_TASKARGUMENTS ) ) {
return apm.getPermission( ApplicationPermissions.PERMISSION_CROSS_APPLICATION_COMMUNICATION );
} else if( module.equals( BLACKBERRY_IO_DIR ) || module.equals( BLACKBERRY_IO_FILE ) ) {
return apm.getPermission( ApplicationPermissions.PERMISSION_FILE_API );
} else if( module.equals( BLACKBERRY_MESSAGE ) ) {
return apm.getPermission( ApplicationPermissions.PERMISSION_EMAIL );
} else if( module.equals( BLACKBERRY_PIM_ADDRESS ) || module.equals( BLACKBERRY_PIM_APPOINTMENT )
|| module.equals( BLACKBERRY_PIM_ATTENDEE ) || module.equals( BLACKBERRY_PIM_CATEGORY )
|| module.equals( BLACKBERRY_PIM_CONTACT ) || module.equals( BLACKBERRY_PIM_MEMO )
|| module.equals( BLACKBERRY_PIM_RECURRENCE ) || module.equals( BLACKBERRY_PIM_REMINDER )
|| module.equals( BLACKBERRY_PIM_TASK ) ) {
return apm.getPermission( ApplicationPermissions.PERMISSION_ORGANIZER_DATA );
} else if( module.equals( BLACKBERRY_PUSH ) ) {
return apm.getPermission( ApplicationPermissions.PERMISSION_INTERNET );
}
return ApplicationPermissions.VALUE_ALLOW;
}
private boolean isCapable( String capability ) {
// Is the current keyboard a sure type?
if( capability.equals( C_INPUT_KEYBOARD_ISSURETYPE ) ) {
switch( Keypad.getHardwareLayout() ) {
case Keypad.HW_LAYOUT_REDUCED:
case Keypad.HW_LAYOUT_REDUCED_24:
case Keypad.HW_LAYOUT_TOUCHSCREEN_24:
return true;
default:
return false;
}
}
// Are we using a touch device?
else if( capability.equals( C_INPUT_TOUCH ) ) {
return Touchscreen.isSupported();
}
// Use System.getProperty() to determine
else if( capability.equals( C_MEDIA_AUDIO_CAPTURE ) ) {
return System.getProperty( "supports.audio.capture" ).equals( "true" );
} else if( capability.equals( C_MEDIA_VIDEO_CAPTURE ) ) {
return System.getProperty( "supports.video.capture" ).equals( "true" );
} else if( capability.equals( C_MEDIA_RECORDING ) ) {
return System.getProperty( "supports.recording" ).equals( "true" );
} else if( capability.equals( C_LOCATION_MAPS ) ) {
return ( CodeModuleManager.getModuleHandle( "net_rim_bb_maps" ) != 0 );
} else if( capability.equals( C_LOCATION_GPS ) ) {
return ( GPSInfo.getDefaultGPSMode() != GPSInfo.GPS_MODE_NONE );
}
// Is there an SD card inserted into the device?
else if( capability.equals( C_STORAGE_MEMORYCARD ) ) {
return sdCardInserted();
}
// Is the device bluetooth capable
else if( capability.equals( C_NETWORK_BLUETOOTH ) ) {
// Bluetooth has been on every device since 4.0
return true;
}
// Check if the wireless family is supported by this device
else if( capability.equals( C_NETWORK_WLAN ) ) {
return RadioInfo.areWAFsSupported( RadioInfo.WAF_WLAN );
} else if( capability.equals( C_NETWORK_CDMA ) ) {
return RadioInfo.areWAFsSupported( RadioInfo.WAF_CDMA );
} else if( capability.equals( C_NETWORK_3GPP ) ) {
return RadioInfo.areWAFsSupported( RadioInfo.WAF_3GPP );
} else if( capability.equals( C_NETWORK_IDEN ) ) {
return RadioInfo.areWAFsSupported( RadioInfo.WAF_IDEN );
}
return false;
}
private String[] checkAllCapabilties() {
Vector capabilities = new Vector();
String[] result = null;
for( int i = 0; i < ALL_CAPABILITIES.length; i++ ) {
if( hasCapability( ALL_CAPABILITIES[ i ] ) ) {
capabilities.addElement( ALL_CAPABILITIES[ i ] );
}
}
result = new String[capabilities.size()];
if (!capabilities.isEmpty()) {
capabilities.copyInto( result );
}
return result;
}
private boolean sdCardInserted() {
String root = null;
Enumeration e = FileSystemRegistry.listRoots();
// loop through the file system roots and look for the SD card prefix
while( e.hasMoreElements() ) {
root = (String) e.nextElement();
if( root.equalsIgnoreCase( "sdcard/" ) ) {
// device has a microSD inserted
return true;
}
}
return false;
}
public void loadFeature( String feature, String version, Document document, ScriptEngine scriptEngine,
SimpleSortingVector jsInjectionPaths ) {
JSUtilities.loadJS( scriptEngine, JS_FILES, jsInjectionPaths );
}
public void register( WidgetConfig widgetConfig, BrowserField browserField ) {
}
public void unloadFeatures() {
}
}