javauis/eswt_qt/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/ercp/swt/mobile/MobileDevice.java
/*******************************************************************************
* Copyright (c) 2004 IBM Corp.
* Portion Copyright (c) 2005, 2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Mark Rogalski (IBM Corp.) - initial API specification
* Nokia Corporation - S60 implementation
* Nokia Corporation - QT implementation
*******************************************************************************/
package org.eclipse.ercp.swt.mobile;
import java.util.Vector;
import org.eclipse.swt.SWT;
import org.eclipse.swt.internal.qt.OS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Internal_PackageSupport;
/**
* Instances of this class represent the device that is being used.
* It provides methods that enable applications to learn more about the device
* specific characteristics and capabilities.
* <p>
* Applications can query what input features and display screens are permanently
* part of the device. These are considered <i>local</i> features. Some devices also
* allow input mechanisms or screens to be attached to the device at runtime. These
* are considered <i>remote</i> features. Since local features do not come and go,
* it is sufficient to query for them once. On the other hand, since remote devices
* can be added or removed at any time, an application needs to add a <code>
* MobileDeviceListener</code> to be informed of these events.
* <p>
* Local features may also be <i>internal</i> or <i>external</i>.
* External features are only available when a device is closed.
* Internal features are only available when a device is opened.
*
* @see Screen
* @see Input
* @see MobileDeviceListener
*/
public class MobileDevice {
private static int handleMobileDevice;
private Vector mobileDeviceListeners;
private Screen[] screens;
private Input[] inputs;
private int alertLevel;
private boolean isOpen;
private static int desktopWidgetHandle;
static MobileDevice currentMobileDevice;
private int activeScreenId;
/**
* feature which is permanently attached to the mobile device and always available
*/
public static final int LOCAL = 0;
/**
* local feature which is only available when mobile device is opened
*/
public static final int INTERNAL = 1;
/**
* local feature which is only available when mobile device is closed
*/
public static final int EXTERNAL = 2;
/**
* feature which is not part of the mobile device unless connected via wire or wireless signal
*/
public static final int REMOTE = 3;
/**
* alert level indicating simple notification (ex. e-mail arrival)
*/
public static final int ALERT_LOW_IMPORTANCE = 1;
/**
* alert level indicating user attention desired (ex. instant message arrival)
*/
public static final int ALERT_HIGH_IMPORTANCE = 2;
/**
* alert level indicating immediate attention is required (ex. battery level at 1%)
*/
public static final int ALERT_CRITICAL = 3;
/**
* virtual keyboard status indicating normal show and hide operation
*/
public static final int VK_NORMAL = 1;
/**
* virtual keyboard status indicating keyboard is always visible
*/
public static final int VK_ALWAYS_ON = 2;
/**
* virtual keyboard status indicating keyboard is always hidden
*/
public static final int VK_ALWAYS_OFF = 3;
/**
* Constructs a new instance of this class. Non-public to prevent
* instantiation outside this package.
*
*/
MobileDevice () {
(getDisplay()).syncExec(new Runnable() {
public void run() {
handleMobileDevice = Internal_PackageSupport.initializeMobileDevice(
Internal_PackageSupport.getDisplayInstance());
if (handleMobileDevice == 0) {
SWT.error(SWT.ERROR_NO_HANDLES);
}
OS.MobileDevice_createFlipWatch(handleMobileDevice);
}
});
mobileDeviceListeners = new Vector();
isOpen = true;
}
private static Display getDisplay(){
Display display = Internal_PackageSupport.getDisplayInstance();
// Following if-statement (getting default display) should be removed
// if agreed that MobileDevice shouldn't create the display.
if(display==null){
display = Display.getDefault();
}
if(display == null || display.isDisposed()){
SWT.error(SWT.ERROR_DEVICE_DISPOSED);
}
return display;
}
private void sendMobileDeviceChangedEvent(int eventType) {
// MobileDevice changed event for open and closed
int count = mobileDeviceListeners.size();
for (int i = 0; i <count; ++i) {
MobileDeviceEvent event = new MobileDeviceEvent(this);
event.type = eventType;
MobileDeviceListener listener = (MobileDeviceListener) mobileDeviceListeners.elementAt(i);
listener.deviceChanged(event);
}
}
void qt_swt_event_mobiledevice_changed(boolean aStatus) {
// update MobileDevice status to opened/closed
isOpen = aStatus;
if(isOpen){
sendMobileDeviceChangedEvent(MobileDeviceEvent.OPENED);
}else{
sendMobileDeviceChangedEvent(MobileDeviceEvent.CLOSED);
}
}
void qt_swt_event_mobiledevice_screen_activate(boolean aStatus) {
if(screens.length > 0 && activeScreenId<screens.length){
if(aStatus){
// update the active screen
activeScreenId = OS.getScreenDeviceNumber();
//forward to screen activated event to new active screen
screens[activeScreenId].internal_sendScreenEventActivated();
}else {
//forward to screen deactivated event to old active screen
screens[activeScreenId].internal_sendScreenEventDeactivated();
}
}
}
void qt_swt_event_mobiledevice_orientationchanged() {
activeScreenId = OS.getScreenDeviceNumber();
if(activeScreenId<screens.length){
// forward to orientation change event to active screen
screens[activeScreenId].internal_sendOrientationScreenChanged();
}
}
private void sendMobileDeviceScreenChangedEvent(int eventType, Screen screen) {
int count = mobileDeviceListeners.size();
for (int i = 0; i <count; ++i) {
MobileDeviceEvent event = new MobileDeviceEvent(this);
event.type = eventType;
event.data = screen;
event.feature = screen;
MobileDeviceListener listener = (MobileDeviceListener) mobileDeviceListeners.elementAt(i);
listener.screenChanged(event);
}
}
void qt_signal_screen_changed(int aCount) {
int type = 0;
Screen screen = null;
Screen []newScreens = new Screen[aCount];
// if getScreen is not called and if still want
// screen changed event in the MobileDevice
if(screens.length==0){
getScreens();
}
if(screens.length > aCount){
// screen removed
int screenHandle = 0;
for(int j=0; j<screens.length; j++) {
// found removed screen
boolean found = false;
for(int i=0; i<aCount; i++) {
screenHandle = OS.QDesktopWidget_screen(desktopWidgetHandle, i);
if(screens[j].screenHandle== screenHandle){
newScreens[i] = screens[j];
newScreens[i].id = i;
found = true;
break;
}
}
if(!found){
screen = screens[j];
screens[j].internal_dispose();
}
}
screens = new Screen[aCount];
// remove detached screen from 'screens'
System.arraycopy(newScreens, 0, screens, 0, aCount);
type = MobileDeviceEvent.REMOVED;
} else if( screens.length < aCount){
// screen attached
for(int i=0; i<aCount; i++) {
// found added screen
int screenHandle = OS.QDesktopWidget_screen(desktopWidgetHandle, i);
boolean found=false;
for(int j=0; j<screens.length; j++) {
if(screens[j].screenHandle== screenHandle){
newScreens[i] = screens[j];
newScreens[i].id = i;
found = true;
break;
}
}
if(!found){
screen = screens[i];
newScreens[i] = new Screen(i, desktopWidgetHandle);
}
}
screens = new Screen[aCount];
// add attached screen to 'screens'
System.arraycopy(newScreens, 0, screens, 0, aCount);
type = MobileDeviceEvent.ADDED;
}
sendMobileDeviceScreenChangedEvent(type, screen);
activeScreenId = OS.getScreenDeviceNumber();
}
private static void hookEvents() {
int screenSignalProxy = OS.SignalHandler_new(desktopWidgetHandle, OS.QSIGNAL_QDESKTOPWIDGET_SCREENCOUNTCHANGED);
OS.QObject_connectOrThrow(desktopWidgetHandle, "screenCountChanged(int)", screenSignalProxy,
"widgetSignal(int)", OS.QT_AUTOCONNECTION);
}
/**
* Adds the listener to the collection of listeners who will be notified when a device
* configuration change occurs, by calling one of the methods defined in the
* <code>MobileDeviceListener</code> interface.
* <p>
* <code>screenChanged</code> is called when a monitor configuration changes.<br>
* <code>inputChanged</code> is called when an input configuration changes.<br>
* <code>deviceChanged</code> is called when the device is opened or closed.<br>
*
* @param listener instance called when device events occur
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTError <ul>
* <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
* </ul>
*
* @see #removeMobileDeviceListener
* @see MobileDeviceListener
*/
public void addMobileDeviceListener(MobileDeviceListener listener) {
if (listener == null) {
SWT.error (SWT.ERROR_NULL_ARGUMENT);
}
mobileDeviceListeners.addElement(listener);
}
/**
* Alerts the user using device specific mechanisms such as sounds, flashing, or
* vibration. <code>Level</code> must be one of ALERT_LOW_IMPORTANCE,
* ALERT_HIGH_IMPORTANCE, or ALERT_CRITICAL. The method maps these levels to
* device specific features that may also be dependent upon user configuration
* or current profile.
*
* @param level
* constant describing the importance of the alert
*
* @exception IllegalArgumentException
* <ul>
* <li>ERROR_INVALID_ARGUMENT - if level is not one of the
* allowed class constants</li>
* </ul>
*
* @see #ALERT_LOW_IMPORTANCE
* @see #ALERT_HIGH_IMPORTANCE
* @see #ALERT_CRITICAL
*/
public void alert(int level) {
if ( level != ALERT_LOW_IMPORTANCE &&
level != ALERT_HIGH_IMPORTANCE &&
level != ALERT_CRITICAL) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
alertLevel = level;
(getDisplay()).syncExec(new Runnable() {
public void run() {
if(alertLevel == ALERT_LOW_IMPORTANCE){
OS.QApplication_beep();
}else if(alertLevel == ALERT_HIGH_IMPORTANCE){
OS.MobileDevice_flashLights(handleMobileDevice, 3000);
OS.MobileDevice_vibration(handleMobileDevice, 3000);
}else if(alertLevel == ALERT_CRITICAL){
OS.QApplication_beep();
OS.MobileDevice_flashLights(handleMobileDevice, 3000);
OS.MobileDevice_vibration(handleMobileDevice, 3000);
}
}
});
}
/**
* Returns an array of Input objects describing the input features available to the device.
* The return value may be <code>null</code> if there are no input features available.
*
* @exception SWTError <ul>
* <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because
* of an operating system failure</li>
* </ul>
*
* @see Input
*/
public Input[] getInputs() {
if(inputs == null) {
try {
(getDisplay()).syncExec(new Runnable() {
public void run() {
int mask = OS.getHwInputs();
int nbInputs = 0;
// finding out number of keyboards available
if((mask & OS.SYMBIAN_KEYBOARD_FULL)!=0){
nbInputs+=2;
}
if((mask & OS.SYMBIAN_KEYBOARD_KEYPAD)!=0){
nbInputs+=2;
}
// create java counter part of Inputs and
// add location and type
inputs = new Input[nbInputs];
int i=0;
int location;
if((mask & OS.SYMBIAN_KEYBOARD_FULL)!=0){
if((mask & OS.SYMBIAN_KEYBOARD_KEYPAD)!=0){
location = MobileDevice.INTERNAL;
} else {
location = MobileDevice.LOCAL;
}
inputs[i] = new Input(i);
inputs[i].setLocation(location);
inputs[i].setType(Input.SOFTKEYS);
i+=1;
inputs[i] = new Input(i);
inputs[i].setLocation(location);
inputs[i].setType(Input.FULL_KEYBOARD);
i+=1;
}
if((mask & OS.SYMBIAN_KEYBOARD_KEYPAD)!=0){
if((mask & OS.SYMBIAN_KEYBOARD_FULL)!=0){
location = MobileDevice.EXTERNAL;
} else {
location = MobileDevice.LOCAL;
}
inputs[i] = new Input(i);
inputs[i].setLocation(location);
inputs[i].setType(Input.SOFTKEYS);
i+=1;
inputs[i] = new Input(i);
inputs[i].setLocation(location);
inputs[i].setType(Input.KEYPAD);
}
}
});
} catch(Throwable e) {
SWT.error(SWT.ERROR_CANNOT_GET_SELECTION);
}
}
return inputs;
}
/**
* Returns an array of Screen objects describing the display features available to the device.
* The return value may be <code>null</code> if there are no display screens available.
*
* @exception SWTError <ul>
* <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because
* of an operating system failure</li>
* </ul>
*
* @see Screen
*/
public Screen[] getScreens() {
if(screens == null) {
try {
(getDisplay()).syncExec(new Runnable() {
public void run() {
int nbScreens = OS.QDesktopWidget_screenCount(desktopWidgetHandle);
activeScreenId = OS.getScreenDeviceNumber();
screens = new Screen[nbScreens];
for(int i=0; i<nbScreens; i++) {
screens[i] = new Screen(i, desktopWidgetHandle);
}
}
});
} catch(Throwable e) {
SWT.error(SWT.ERROR_CANNOT_GET_SELECTION);
}
}
return screens;
}
/**
* Returns singleton instance of MobileDevice class.
*
* @return singleton of MobileDevice class. Must not be Null.
*
* @exception SWTError <ul>
* <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of
* an operating system failure</li>
* </ul>
*/
public static MobileDevice getMobileDevice() {
if(currentMobileDevice == null) {
try {
currentMobileDevice = new MobileDevice();
Internal_PackageSupport.setMobileDevice(getDisplay(),currentMobileDevice);
desktopWidgetHandle = OS.QApplication_desktop();
hookEvents();
} catch (Throwable e) {
SWT.error(SWT.ERROR_CANNOT_GET_SELECTION);
}
}
return currentMobileDevice;
}
/**
* Returns whether device is opened. For devices that have no internal screens
* or input features, the method always returns <code>true</code>.
*/
public boolean isOpen() {
getDisplay();
return isOpen;
}
/**
* Call to dispose the Screen object.
*
*/
void internal_dispose() {
if (inputs != null) {
for (int i = 0; i < inputs.length; i++) {
if (inputs[i] != null) {
inputs[i].internal_dispose();
}
}
}
if (screens != null) {
for (int i = 0; i < screens.length; i++) {
if (screens[i] != null) {
screens[i].internal_dispose();
}
}
}
// actual native counter part is deleted in display
currentMobileDevice = null;
handleMobileDevice = 0;
inputs = null;
screens = null;
desktopWidgetHandle = 0;
}
/**
* Removes the listener from the collection of listeners who will be notified when a device
* configuration change occurs.
*
* @param listener instance called when device events occur
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTError <ul>
* <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because
* of an operating system failure</li>
* </ul>
*
* @see #addMobileDeviceListener
* @see MobileDeviceListener
*/
public void removeMobileDeviceListener(MobileDeviceListener listener) {
if (listener == null) {
SWT.error (SWT.ERROR_NULL_ARGUMENT);
}
//remove listener
//Remove method of Vector class never fails,
//so ERROR_ITEM_NOT_REMOVED could never be thrown.
mobileDeviceListeners.removeElement(listener);
}
/**
* Sets the status of the system virtual keyboard (if one is available).
* By default, or when status is set to VK_NORMAL, a system virtual keyboard
* is displayed when a widget capable of text input gains focus and is
* hidden when that widget looses focus. However, there are cases where
* an application may wish to continuously display the virtual keyboard
* or always keep it hidden. Setting the status to VK_ALWAYS_ON or VK_ALWAYS_OFF
* will accomplish this and the effect is immediate. Changing focus will
* then have no affect on the virtual keyboard. Note: By default, widgets which
* normally accept input but are set to <i>read only</i> do not cause the
* the virtual keyboard to display.
*
* @param status virtual keyboard mode. One of VK_NORMAL, VK_ALWAYS_ON, VK_ALWAYS_OFF
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_INVALID_ARGUMENT - if the status parameter is not valid</li>
* </ul>
*
* @see #VK_NORMAL
* @see #VK_ALWAYS_ON
* @see #VK_ALWAYS_OFF
*/
public void setVKStatus(int status){
}
}