|  | // | 
|  | // Copyright 2005 The Android Open Source Project | 
|  | // | 
|  | // Class that manages the simulated device. | 
|  | // | 
|  | #ifndef _SIM_DEVICE_MANAGER_H | 
|  | #define _SIM_DEVICE_MANAGER_H | 
|  |  | 
|  | #include "UserEvent.h" | 
|  |  | 
|  | #include "Shmem.h" | 
|  | #include "MessageStream.h" | 
|  | #include "SimRuntime.h" | 
|  |  | 
|  | #include "ui/PixelFormat.h" | 
|  | #include "ui/KeycodeLabels.h" | 
|  |  | 
|  | #include <sys/stat.h> | 
|  |  | 
|  | /* | 
|  | * Manage the simulated device.  This includes starting/stopping as well | 
|  | * as sending messages to it and receiving events from it. | 
|  | * | 
|  | * The object may span multiple invocations of a specific device.  If | 
|  | * the simulator is reconfigured to use a device with different | 
|  | * characteristics, the object should be destroyed and recreated (which | 
|  | * guarantees that the runtime is restarted). | 
|  | */ | 
|  | class DeviceManager { | 
|  | public: | 
|  | DeviceManager(void); | 
|  | virtual ~DeviceManager(void); | 
|  |  | 
|  | /* | 
|  | * Initialize the object.  Call this once. | 
|  | * | 
|  | * "numDisplays" is the number of displays that the simulated hardware | 
|  | * supports.  The displays themselves are configured with separate calls. | 
|  | * | 
|  | * "statusWindow" should be the main frame.  Messages indicating runtime | 
|  | * startup/shutdown are sent, as well as error messages that should be | 
|  | * displayed in message boxes. | 
|  | */ | 
|  | bool Init(int numDisplays, wxWindow* statusWindow); | 
|  | bool IsInitialized(void) const; | 
|  |  | 
|  | /* | 
|  | * Tell the device manager that the windows used to display its output | 
|  | * are closing down. | 
|  | */ | 
|  | void WindowsClosing(void); | 
|  |  | 
|  | /* | 
|  | * "displayWindow" is the window to notify when a new frame of graphics | 
|  | * data is available.  This can be set independently for each display. | 
|  | */ | 
|  | bool SetDisplayConfig(int displayIndex, wxWindow* window, | 
|  | int width, int height, android::PixelFormat format, int refresh); | 
|  |  | 
|  | /* | 
|  | * set the key map | 
|  | */ | 
|  | bool SetKeyboardConfig(const char *keymap); | 
|  |  | 
|  | /* | 
|  | * Return the number of displays we're configured for. | 
|  | */ | 
|  | int GetNumDisplays(void) const { return mNumDisplays; } | 
|  |  | 
|  | /* | 
|  | * Return the shmem key for the Nth display. | 
|  | */ | 
|  | //int GetShmemKey(int displayIndex); | 
|  |  | 
|  | /* | 
|  | * Is the runtime process still running? | 
|  | */ | 
|  | bool IsRunning(void) const { | 
|  | if (mThread != NULL) | 
|  | return mThread->IsRunning(); | 
|  | return false; | 
|  | } | 
|  | bool IsKillable(void) const { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // (Re-)configure the device, e.g. when #of displays changes because | 
|  | // a different phone model has been selected.  Call this before doing | 
|  | // any display-specific setup.  DO NOT call this if the runtime is active. | 
|  | //    void Configure(int numDisplays); | 
|  |  | 
|  | // start the runtime, acting as parent | 
|  | bool StartRuntime(void); | 
|  | // start the runtime, acting as peer | 
|  | bool StartRuntime(android::Pipe* reader, android::Pipe* writer); | 
|  | // politely ask the runtime to stop | 
|  | bool StopRuntime(void); | 
|  | // kill the runtime with extreme prejudice | 
|  | void KillRuntime(void); | 
|  |  | 
|  | #if 0 | 
|  | // Returns if the executable is new | 
|  | bool RefreshRuntime(void); | 
|  | // Update the time of the current runtime because the user cancelled a | 
|  | // refresh | 
|  | void UserCancelledRefresh(void); | 
|  | #endif | 
|  |  | 
|  | // send a key-up or key-down event to the runtime | 
|  | void SendKeyEvent(int32_t keyCode, bool down); | 
|  | // send touch-screen events | 
|  | void SendTouchEvent(android::Simulator::TouchMode mode, int x, int y); | 
|  |  | 
|  | wxBitmap* GetImageData(int displayIndex); | 
|  |  | 
|  | void BroadcastEvent(UserEvent &userEvent); | 
|  |  | 
|  | private: | 
|  | /* | 
|  | * Threads in wxWidgets use sub-classing to define interfaces and | 
|  | * entry points.  We use this to create the thread that interacts | 
|  | * with the runtime. | 
|  | * | 
|  | * The "reader" and "writer" arguments may be NULL.  If they are, | 
|  | * we will launch the runtime ourselves.  If not, we will use them | 
|  | * to speak with an externally-launched runtime process.  The thread | 
|  | * will own the pipes, shutting them down when it exits. | 
|  | */ | 
|  | class DeviceThread : public wxThread { | 
|  | public: | 
|  | DeviceThread(DeviceManager* pDM, wxWindow* pStatusWindow, | 
|  | android::Pipe* reader, android::Pipe* writer) | 
|  | : wxThread(wxTHREAD_JOINABLE), mpStatusWindow(pStatusWindow), | 
|  | mReader(reader), mWriter(writer), | 
|  | mpDeviceManager(pDM), /*mTerminalFollowsChild(false), | 
|  | mSlowExit(false), mIsExternal(false), mLastModified(0),*/ | 
|  | mRuntimeProcessGroup(0) | 
|  | {} | 
|  | virtual ~DeviceThread(void) { | 
|  | delete mReader; | 
|  | delete mWriter; | 
|  | } | 
|  |  | 
|  | /* thread entry point */ | 
|  | virtual void* Entry(void); | 
|  |  | 
|  | // wxThread class supplies an IsRunning() method | 
|  |  | 
|  | /* | 
|  | * This kills the runtime process to force this thread to exit. | 
|  | * If the thread doesn't exit after a short period of time, it | 
|  | * is forcibly terminated. | 
|  | */ | 
|  | void KillChildProcesses(void); | 
|  |  | 
|  | #if 0 | 
|  | /* | 
|  | * Return if the runtime executable is new | 
|  | */ | 
|  | bool IsRuntimeNew(void); | 
|  |  | 
|  | void UpdateLastModified(void); | 
|  | #endif | 
|  |  | 
|  | android::MessageStream* GetStream(void) { return &mStream; } | 
|  |  | 
|  | static bool LaunchProcess(wxWindow* statusWindow); | 
|  |  | 
|  | private: | 
|  | void WaitForDeath(int delay); | 
|  | void ResetProperties(void); | 
|  |  | 
|  | android::MessageStream  mStream; | 
|  | wxWindow*       mpStatusWindow; | 
|  | android::Pipe*  mReader; | 
|  | android::Pipe*  mWriter; | 
|  | DeviceManager*  mpDeviceManager; | 
|  | pid_t           mRuntimeProcessGroup; | 
|  | //time_t          mLastModified; | 
|  | wxString        mRuntimeExe; | 
|  | }; | 
|  |  | 
|  | friend class DeviceThread; | 
|  |  | 
|  | /* | 
|  | * We need one of these for each display on the device.  Most devices | 
|  | * only have one, but some flip phones have two. | 
|  | */ | 
|  | class Display { | 
|  | public: | 
|  | Display(void) | 
|  | : mDisplayWindow(NULL), mpShmem(NULL), mShmemKey(0), | 
|  | mImageData(NULL), mDisplayNum(-1), mWidth(-1), mHeight(-1), | 
|  | mFormat(android::PIXEL_FORMAT_UNKNOWN), mRefresh(0) | 
|  | {} | 
|  | ~Display() { | 
|  | delete mpShmem; | 
|  | delete[] mImageData; | 
|  | } | 
|  |  | 
|  | /* initialize goodies */ | 
|  | bool Create(int displayNum, wxWindow* window, int width, int height, | 
|  | android::PixelFormat format, int refresh); | 
|  |  | 
|  | /* call this if we're shutting down soon */ | 
|  | void Uncreate(void); | 
|  |  | 
|  | /* copy & convert data from shared memory */ | 
|  | void CopyFromShared(void); | 
|  |  | 
|  | /* get image data in the form of a 24bpp bitmap */ | 
|  | wxBitmap* GetImageData(void); | 
|  |  | 
|  | /* get a pointer to our display window */ | 
|  | wxWindow* GetWindow(void) const { return mDisplayWindow; } | 
|  |  | 
|  | /* get our shared memory key */ | 
|  | int GetShmemKey(void) const { return mShmemKey; } | 
|  |  | 
|  | int GetWidth(void) const { return mWidth; } | 
|  | int GetHeight(void) const { return mHeight; } | 
|  | android::PixelFormat GetFormat(void) const { return mFormat; } | 
|  | int GetRefresh(void) const { return mRefresh; } | 
|  |  | 
|  | private: | 
|  | int GenerateKey(int displayNum) { | 
|  | return 0x41544d00 | displayNum; | 
|  | } | 
|  |  | 
|  | // control access to image data shared between runtime mgr and UI | 
|  | wxMutex         mImageDataLock; | 
|  | // we send an event here when we get stuff to display | 
|  | wxWindow*       mDisplayWindow; | 
|  |  | 
|  | // shared memory segment | 
|  | android::Shmem* mpShmem; | 
|  | int             mShmemKey; | 
|  |  | 
|  | // local copy of data from shared mem, converted to 24bpp | 
|  | unsigned char*  mImageData; | 
|  |  | 
|  | // mainly for debugging -- which display are we? | 
|  | int             mDisplayNum; | 
|  |  | 
|  | // display characteristics | 
|  | int             mWidth; | 
|  | int             mHeight; | 
|  | android::PixelFormat mFormat; | 
|  | int             mRefresh;       // fps | 
|  | }; | 
|  |  | 
|  | Display* GetDisplay(int dispNum) { return &mDisplay[dispNum]; } | 
|  |  | 
|  | const char* GetKeyMap() { return mKeyMap ? mKeyMap : "qwerty"; } | 
|  |  | 
|  | void ShowFrame(int displayIndex); | 
|  |  | 
|  | void Vibrate(int vibrateOn); | 
|  |  | 
|  | // get the message stream from the device thread | 
|  | android::MessageStream* GetStream(void); | 
|  |  | 
|  | // send a request to set the visible layers | 
|  | void SendSetVisibleLayers(void); | 
|  |  | 
|  | // points at the runtime's thread (while it's running) | 
|  | DeviceThread*   mThread; | 
|  |  | 
|  | // array of Displays, one per display on the device | 
|  | Display*        mDisplay; | 
|  | int             mNumDisplays; | 
|  |  | 
|  | // the key map | 
|  | const char * mKeyMap; | 
|  |  | 
|  | // which graphics layers are visible? | 
|  | int             mVisibleLayers; | 
|  |  | 
|  | // where to send status messages | 
|  | wxWindow*       mpStatusWindow; | 
|  |  | 
|  | }; | 
|  |  | 
|  | #endif // _SIM_DEVICE_MANAGER_H |