/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.lcdui;
import com.sun.midp.events.EventQueue;
import com.sun.midp.lcdui.DisplayContainer;
import com.sun.midp.lcdui.DisplayDeviceContainer;
import com.sun.midp.lcdui.DisplayAccess;
import com.sun.midp.lcdui.DisplayEventHandler;
import com.sun.midp.lcdui.DisplayEventProducer;
import com.sun.midp.lcdui.ForegroundController;
import com.sun.midp.lcdui.RepaintEventProducer;
import com.sun.midp.lcdui.ItemEventConsumer;
/**
* This class has dual functiopnality:
*
* First, it implements DisplayEventHandler I/F and thus provides access
* to display objects (creation, preemption, set/get IDs and other properties).
*
* Second, it implements ItemEventConsumer I/F and thus processes
* LCDUI events that due to different reasons can't be associated with
* Display instance specific DisplayEventConsumer objects,
* but need to be processed by isolate-wide handler.
* TBD: These are subjects for futher investigation to move them
* to DisplayEventConsumer.
*
* In addition, it implements a number of package private methods that work
* with Display and are called locally by display/DisplayAccessor.
* TBD: These are subjects for further investination to move them closer
* to end users: Display & displayAccessor classes.
*
*/
class DisplayEventHandlerImpl implements DisplayEventHandler,
ItemEventConsumer {
/** Cached reference to Active Displays Container. */
private DisplayContainer displayContainer;
/** Cached reference to the ForegroundController. */
private ForegroundController foregroundController;
/** The preempting display. */
private DisplayAccess preemptingDisplay;
/** If request to end preemption was called */
private boolean preemptionDoneCalled = false;
/** Package private constructor restrict creation to LCDUI package. */
DisplayEventHandlerImpl() {
}
/**
* Initialize Display Event Handler.
* DisplayEventHandler I/F method.
*
* @param theDisplayEventProducer producer for display events
* @param theForegroundController controls which display has the foreground
* @param theRepaintEventProducer producer for repaint events events
* @param theDisplayContainer container for display objects
* @param theDisplayDeviceContainer container for display device objects
*/
public void initDisplayEventHandler(
DisplayEventProducer theDisplayEventProducer,
ForegroundController theForegroundController,
RepaintEventProducer theRepaintEventProducer,
DisplayContainer theDisplayContainer,
DisplayDeviceContainer theDisplayDeviceContainer) {
foregroundController = theForegroundController;
displayContainer = theDisplayContainer;
/*
* TBD: not a good idea to call static initializer
* from non-static method ...
* Maybe to create a separate method:
* DisplayEventHandler.initDisplayClass(token,...)
* for these purposes and call it from Suite Loader's main() ?
* displayEventHandlerImpl I/F miplementor will call
* Display.initClass() from itsinitDisplayClass() method ?
*/
Display.initClass(
theForegroundController,
theDisplayEventProducer,
theRepaintEventProducer,
theDisplayContainer,
theDisplayDeviceContainer);
}
/**
* Sets the trusted state of the display event handler.
* DisplayEventHandler I/F method.
*
* @param drawTrustedIcon true, to draw the trusted icon in the upper
* status bar for every display of this suite
*/
public void setTrustedState(boolean drawTrustedIcon) {
Display.setTrustedState(drawTrustedIcon);
}
/**
* Preempt the current displayable with
* the given displayable until donePreempting is called.
* To avoid dead locking the event thread his method
* MUST NOT be called in the event thread.
* DisplayEventHandler I/F method.
*
* @param d displayable to show the user
* @param waitForDisplay if true this method will wait if the
* screen is being preempted by another thread, however
* if this is called in the event dispatch thread this
* method will return null regardless of the value
* of <code>waitForDisplay</code>
*
* @return an preempt token object to pass to donePreempting done if
* prempt will happen, else null
*
* @exception InterruptedException if another thread interrupts the
* calling thread while this method is waiting to preempt the
* display.
*/
public Object preemptDisplay(Displayable d, boolean waitForDisplay)
throws InterruptedException {
Display tempDisplay;
String title;
if (d == null) {
throw new NullPointerException(
"The displayable can't be null");
}
title = d.getTitle();
if (title == null) {
throw new NullPointerException(
"The title of the displayable can't be null");
}
if (EventQueue.isDispatchThread()) {
// Developer programming error
throw new RuntimeException(
"Blocking call performed in the event thread");
}
/**
* This sync protects preempt related local fields:
* preemptingDisplay and destroyPreemptingDisplay.
*/
synchronized (this) {
if (preemptingDisplay != null) {
if (!waitForDisplay) {
return null;
}
this.wait();
}
// This class will own the display.
tempDisplay =
new Display("com.sun.midp.lcdui.DisplayEventHandlerImpl");
foregroundController.startPreempting(tempDisplay.displayId);
tempDisplay.setCurrent(d);
preemptingDisplay = tempDisplay.accessor;
return preemptingDisplay;
}
}
/**
* Display the displayable that was being displayed before
* preemptDisplay was called.
* DisplayEventHandler I/F method.
*
* @param preemptToken the token returned from preemptDisplay
*/
public void donePreempting(Object preemptToken) {
/**
* This sync protects preempt related local fields:
* preemptingDisplay and destroyPreemptingDisplay.
*/
synchronized (this) {
if (preemptingDisplay != null &&
(preemptToken == preemptingDisplay || preemptToken == null)) {
preemptionDoneCalled = true;
foregroundController.stopPreempting(
preemptingDisplay.getDisplayId());
}
}
}
/**
* Called by Display to notify DisplayEventHandler that
* Display has been sent to the background to finish
* preempt process if any.
*
* @param displayId id of Display
*/
public void onDisplayBackgroundProcessed(int displayId) {
synchronized (this) {
if (preemptionDoneCalled && preemptingDisplay != null &&
preemptingDisplay.getDisplayId() == displayId) {
displayContainer.removeDisplaysByOwner(
preemptingDisplay.getOwner());
preemptingDisplay = null;
preemptionDoneCalled = false;
// A midlet may be waiting to preempt
this.notify();
}
}
}
/**
* Called by event delivery to process an Item state change.
* ItemEventConsumer I/F method.
*
* @param item the Item which has changed state
*/
public void handleItemStateChangeEvent(Item item) {
if (item.owner != null) {
item.owner.uCallItemStateChanged(item);
}
}
/**
* Called by event delivery to refresh a CustomItem's size information.
* ItemEventConsumer I/F method.
*
* @param ci the custom item whose size information has to be changed
*/
public void handleItemSizeRefreshEvent(CustomItem ci) {
ci.customItemLF.uCallSizeRefresh();
}
/*
* private methods
*/
static {
// Instantiate link with MMAPI video player for repaint hooks
new MMHelperImpl();
}
}