Initial Contribution
diff --git a/simulator/app/MainFrame.cpp b/simulator/app/MainFrame.cpp
new file mode 100644
index 0000000..b13caab
--- /dev/null
+++ b/simulator/app/MainFrame.cpp
@@ -0,0 +1,1462 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+// Main window, menu bar, and associated goodies.
+//
+
+// For compilers that support precompilation, include "wx/wx.h".
+#include "wx/wxprec.h"
+
+// Otherwise, include all standard headers
+#ifndef WX_PRECOMP
+# include "wx/wx.h"
+#endif
+#include "wx/button.h"
+#include "wx/help.h"
+#include "wx/filedlg.h"
+#include "wx/slider.h"
+#include "wx/textctrl.h"
+
+#include "MainFrame.h"
+#include "MyApp.h"
+#include "Resource.h"
+#include "PhoneCollection.h"
+#include "PhoneData.h"
+#include "PhoneWindow.h"
+#include "DeviceWindow.h"
+#include "UserEventMessage.h"
+#include "PrefsDialog.h"
+
+#include "SimRuntime.h"
+
+
+static wxString kStatusNotRunning = wxT("Idle");
+static wxString kStatusRunning = wxT("Run");
+
+static wxString kDeviceMenuString = wxT("&Device");
+
+static const wxString gStdJavaApps[] = {
+ wxT(""),
+ wxT("com.android.testharness.TestList"),
+ wxT("com.android.apps.contacts.ContactsList"),
+ wxT("mikeapp")
+};
+
+
+BEGIN_EVENT_TABLE(MainFrame::MainFrame, wxFrame)
+ EVT_CLOSE(MainFrame::OnClose)
+ EVT_TIMER(kHalfSecondTimerId, MainFrame::OnTimer)
+ //EVT_IDLE(MainFrame::OnIdle)
+
+ EVT_ACTIVATE(MainFrame::OnActivate)
+ EVT_ACTIVATE_APP(MainFrame::OnActivate)
+ EVT_COMBOBOX(IDC_MODE_SELECT, MainFrame::OnComboBox)
+ EVT_COMBOBOX(IDC_JAVA_VM, MainFrame::OnComboBox)
+ EVT_CHECKBOX(IDC_USE_GDB, MainFrame::OnCheckBox)
+ EVT_CHECKBOX(IDC_USE_VALGRIND, MainFrame::OnCheckBox)
+ EVT_CHECKBOX(IDC_CHECK_JNI, MainFrame::OnCheckBox)
+ EVT_CHECKBOX(IDC_OVERLAY_ONION_SKIN, MainFrame::OnCheckBox)
+ EVT_TEXT(IDC_JAVA_APP_NAME, MainFrame::OnText)
+ EVT_TEXT_ENTER(IDC_ONION_SKIN_FILE_NAME, MainFrame::OnTextEnter)
+ EVT_BUTTON(IDC_ONION_SKIN_BUTTON, MainFrame::OnButton)
+ EVT_COMMAND_SCROLL(IDC_ONION_SKIN_ALPHA_VAL, MainFrame::OnSliderChange)
+
+ EVT_MENU(IDM_FILE_PREFERENCES, MainFrame::OnFilePreferences)
+ EVT_MENU(IDM_FILE_EXIT, MainFrame::OnFileExit)
+ EVT_MENU(IDM_RUNTIME_START, MainFrame::OnSimStart)
+ EVT_UPDATE_UI(IDM_RUNTIME_START, MainFrame::OnUpdateSimStart)
+ EVT_MENU(IDM_RUNTIME_STOP, MainFrame::OnSimStop)
+ EVT_UPDATE_UI(IDM_RUNTIME_STOP, MainFrame::OnUpdateSimStop)
+ EVT_MENU(IDM_RUNTIME_RESTART, MainFrame::OnSimRestart)
+ EVT_UPDATE_UI(IDM_RUNTIME_RESTART, MainFrame::OnUpdateSimRestart)
+ EVT_MENU(IDM_RUNTIME_KILL, MainFrame::OnSimKill)
+ EVT_UPDATE_UI(IDM_RUNTIME_KILL, MainFrame::OnUpdateSimKill)
+ EVT_MENU_RANGE(IDM_DEVICE_SEL0, IDM_DEVICE_SELN,
+ MainFrame::OnDeviceSelected)
+ EVT_MENU(IDM_DEVICE_RESCAN, MainFrame::OnDeviceRescan)
+ EVT_UPDATE_UI(IDM_DEBUG_SHOW_LOG, MainFrame::OnUpdateDebugShowLog)
+ EVT_MENU(IDM_DEBUG_SHOW_LOG, MainFrame::OnDebugShowLog)
+ EVT_MENU(IDM_HELP_CONTENTS, MainFrame::OnHelpContents)
+ EVT_MENU(IDM_HELP_ABOUT, MainFrame::OnHelpAbout)
+
+ EVT_USER_EVENT(MainFrame::OnUserEvent)
+END_EVENT_TABLE()
+
+
+/*
+ * Main window constructor.
+ *
+ * Creates menus and status bar.
+ */
+MainFrame::MainFrame(const wxString& title, const wxPoint& pos,
+ const wxSize& size, long style)
+ : wxFrame((wxFrame *)NULL, -1, title, pos, size, style),
+ mSimRunning(false),
+ mRestartRequested(false),
+ mpPhoneWindow(NULL),
+ mPhoneWindowPosn(wxDefaultPosition),
+ mTimer(this, kHalfSecondTimerId)
+{
+ mSimAssetPath = ((MyApp*)wxTheApp)->GetSimAssetPath();
+ mSimAssetPath += wxT("/simulator/default/default");
+
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ int val;
+
+ val = mPhoneWindowPosn.x;
+ pPrefs->GetInt("window-device-x", &val);
+ mPhoneWindowPosn.x = val;
+ val = mPhoneWindowPosn.y;
+ pPrefs->GetInt("window-device-y", &val);
+ mPhoneWindowPosn.y = val;
+
+ /*
+ * Create main menu.
+ */
+ ConstructMenu();
+
+ /*
+ * Create the status bar.
+ */
+ int widths[2] = { -1, 50 };
+ CreateStatusBar(2, wxFULL_REPAINT_ON_RESIZE); // no wxST_SIZEGRIP
+ SetStatusWidths(2, widths);
+ SetStatusText(wxT("Ready"));
+ SetStatusText(kStatusNotRunning, 1);
+
+ /*
+ * Create main window controls.
+ */
+ ConstructControls();
+
+#if 0
+ /*
+ * Use the standard window color for the main frame (which usually
+ * has a darker color). This has a dramatic effect under Windows.
+ */
+ wxColour color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
+ SetOwnBackgroundColour(color);
+#endif
+
+ /*
+ * Create the log window.
+ */
+ wxRect layout = LogWindow::GetPrefWindowRect();
+ mpLogWindow = new LogWindow(this);
+ mpLogWindow->Move(layout.GetTopLeft());
+ mpLogWindow->SetSize(layout.GetSize());
+ bool showLogWindow = true;
+ pPrefs->GetBool("window-log-show", &showLogWindow);
+ if (showLogWindow)
+ mpLogWindow->Show();
+
+ /*
+ * Set up a frequent timer. We use this to keep our "run/idle"
+ * display up to date. (Ideally this will go away.)
+ */
+ mTimer.Start(400); // arg is delay in ms
+
+ /*
+ * Handle auto-power-on by sending ourselves an event. That way it
+ * gets handled after window initialization finishes.
+ */
+ bool autoPowerOn = false;
+ pPrefs->GetBool("auto-power-on", &autoPowerOn);
+ if (autoPowerOn) {
+ printf("Sim: Auto power-up\n");
+ wxCommandEvent startEvent(wxEVT_COMMAND_MENU_SELECTED, IDM_RUNTIME_START);
+ this->AddPendingEvent(startEvent);
+ }
+
+ /*
+ * wxThread wants these to be on the heap -- it will call delete on the
+ * object when the thread exits.
+ */
+ mExternalRuntimeThread = new ExternalRuntime();
+ mExternalRuntimeThread->StartThread();
+ mPropertyServerThread = new PropertyServer();
+ mPropertyServerThread->StartThread();
+}
+
+/*
+ * Construct the main menu. Called from the constructor.
+ */
+void MainFrame::ConstructMenu(void)
+{
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+
+ /*
+ * Scan for available phones.
+ */
+ PhoneCollection* pCollection = PhoneCollection::GetInstance();
+ pCollection->ScanForPhones(mSimAssetPath.ToAscii());
+
+ /*
+ * Create the "File" menu.
+ */
+ wxMenu* menuFile = new wxMenu;
+
+ menuFile->Append(IDM_FILE_PREFERENCES, wxT("&Preferences..."),
+ wxT("Edit simulator preferences"));
+ menuFile->AppendSeparator();
+ menuFile->Append(IDM_FILE_EXIT, wxT("E&xit\tCtrl-Q"),
+ wxT("Stop simulator and exit"));
+
+ /*
+ * Create the "Runtime" menu.
+ */
+ wxMenu* menuRuntime = new wxMenu;
+ menuRuntime->Append(IDM_RUNTIME_START, wxT("&Power On\tCtrl-G"),
+ wxT("Start the device"));
+// menuRuntime->Append(IDM_RUNTIME_STOP, wxT("Power &Off"),
+// wxT("Stop the device"));
+ menuRuntime->AppendSeparator();
+// menuRuntime->Append(IDM_RUNTIME_RESTART, wxT("&Restart"),
+// wxT("Restart the device"));
+ menuRuntime->Append(IDM_RUNTIME_KILL, wxT("&Kill\tCtrl-K"),
+ wxT("Kill the runtime processes"));
+
+ /*
+ * Create "Device" menu.
+ */
+ wxString defaultDevice = wxT("Sooner");
+ pPrefs->GetString("default-device", /*ref*/ defaultDevice);
+ wxMenu* menuDevice = CreateDeviceMenu(defaultDevice.ToAscii());
+
+ /*
+ * Create "Debug" menu.
+ */
+ wxMenu* menuDebug = new wxMenu;
+ menuDebug->AppendCheckItem(IDM_DEBUG_SHOW_LOG, wxT("View &Log Output"),
+ wxT("View log output window"));
+
+ /*
+ * Create the "Help" menu.
+ */
+ wxMenu* menuHelp = new wxMenu;
+ menuHelp->Append(IDM_HELP_CONTENTS, wxT("&Contents...\tF1"),
+ wxT("Simulator help"));
+ menuHelp->AppendSeparator();
+ menuHelp->Append(IDM_HELP_ABOUT, wxT("&About..."),
+ wxT("See the fabulous 'about' box"));
+
+ /*
+ * Create the menu bar.
+ */
+ wxMenuBar *menuBar = new wxMenuBar;
+ menuBar->Append(menuFile, wxT("&File"));
+ menuBar->Append(menuDevice, kDeviceMenuString);
+ menuBar->Append(menuRuntime, wxT("&Runtime"));
+ menuBar->Append(menuDebug, wxT("&Debug"));
+ menuBar->Append(menuHelp, wxT("&Help"));
+
+ SetMenuBar(menuBar);
+
+}
+
+/*
+ * Construct the "device" menu from our phone collection.
+ */
+wxMenu* MainFrame::CreateDeviceMenu(const char* defaultItemName)
+{
+ wxMenu* menuDevice = new wxMenu;
+ PhoneCollection* pCollection = PhoneCollection::GetInstance();
+ int defaultModel = 0;
+
+ for (int i = 0; i < pCollection->GetPhoneCount(); i++) {
+ PhoneData* pPhoneData = pCollection->GetPhoneData(i);
+ assert(pPhoneData != NULL);
+
+ menuDevice->AppendRadioItem(IDM_DEVICE_SEL0 + i,
+ wxString::FromAscii(pPhoneData->GetTitle()));
+
+ // use this one as default if the string matches
+ if (strcasecmp(pPhoneData->GetName(), defaultItemName) == 0)
+ defaultModel = i;
+ }
+
+ menuDevice->Check(IDM_DEVICE_SEL0 + defaultModel, true);
+
+ menuDevice->AppendSeparator();
+ menuDevice->Append(IDM_DEVICE_RESCAN, wxT("Re-scan"));
+
+ return menuDevice;
+}
+
+/*
+ * Create some controls in the main window.
+ *
+ * The main frame doesn't use the normal background color that you find
+ * in dialog windows, so we create a "panel" and put all the controls
+ * on that.
+ */
+void MainFrame::ConstructControls(void)
+{
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ wxPanel* base = new wxPanel(this, wxID_ANY);
+ wxBoxSizer* masterSizer = new wxBoxSizer(wxVERTICAL);
+ wxBoxSizer* tmpSizer;
+ wxStaticBoxSizer* displayOptSizer;
+ wxStaticBoxSizer* runtimeOptSizer;
+ wxStaticBoxSizer* onionSkinOptSizer;
+ wxComboBox* pModeSelection;
+ wxCheckBox* pUseGDB;
+ wxCheckBox* pUseValgrind;
+ wxCheckBox* pCheckJni;
+ wxCheckBox* pOverlayOnionSkin;
+
+ displayOptSizer = new wxStaticBoxSizer(wxHORIZONTAL, base,
+ wxT("Configuration"));
+ runtimeOptSizer = new wxStaticBoxSizer(wxVERTICAL, base,
+ wxT("Runtime Options"));
+ onionSkinOptSizer = new wxStaticBoxSizer(wxVERTICAL, base,
+ wxT("Onion Skin Options"));
+
+ /*
+ * Set up the configuration sizer (nee "display options").
+ */
+ tmpSizer = new wxBoxSizer(wxHORIZONTAL);
+ displayOptSizer->Add(tmpSizer);
+ tmpSizer->Add(
+ new wxStaticText(base, wxID_ANY, wxT("Device mode:"),
+ wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT), 0, wxALIGN_CENTER_VERTICAL);
+ pModeSelection = new wxComboBox(base, IDC_MODE_SELECT, wxT(""),
+ wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY);
+ tmpSizer->AddSpacer(kInterSpacing);
+ tmpSizer->Add(pModeSelection);
+
+ displayOptSizer->AddSpacer(kInterSpacing);
+
+ /*
+ * Configure the runtime options sizer.
+ */
+ wxComboBox* pJavaAppName;
+ tmpSizer = new wxBoxSizer(wxHORIZONTAL);
+ pUseGDB = new wxCheckBox(base, IDC_USE_GDB, wxT("Use &debugger"));
+ tmpSizer->Add(pUseGDB);
+ tmpSizer->AddSpacer(kInterSpacing);
+ pUseValgrind = new wxCheckBox(base, IDC_USE_VALGRIND, wxT("Use &valgrind"));
+ tmpSizer->Add(pUseValgrind);
+ tmpSizer->AddSpacer(kInterSpacing);
+ pCheckJni = new wxCheckBox(base, IDC_CHECK_JNI, wxT("Check &JNI"));
+ tmpSizer->Add(pCheckJni);
+
+ pJavaAppName = new wxComboBox(base, IDC_JAVA_APP_NAME, wxT(""),
+ wxDefaultPosition, wxSize(320, -1), NELEM(gStdJavaApps), gStdJavaApps,
+ wxCB_DROPDOWN);
+ wxBoxSizer* javaAppSizer = new wxBoxSizer(wxHORIZONTAL);
+ javaAppSizer->Add(
+ new wxStaticText(base, wxID_ANY,
+ wxT("Java app:"),
+ wxDefaultPosition, wxDefaultSize,
+ wxALIGN_LEFT),
+ 0, wxALIGN_CENTER_VERTICAL);
+ javaAppSizer->AddSpacer(kInterSpacing);
+ javaAppSizer->Add(pJavaAppName);
+
+ runtimeOptSizer->Add(tmpSizer);
+
+ runtimeOptSizer->AddSpacer(kInterSpacing);
+ runtimeOptSizer->Add(javaAppSizer);
+ runtimeOptSizer->AddSpacer(kInterSpacing);
+
+ wxString tmpStr;
+ SetCheckFromPref(pUseGDB, "debug", false);
+ SetCheckFromPref(pUseValgrind, "valgrind", false);
+ SetCheckFromPref(pCheckJni, "check-jni", false);
+ if (pPrefs->GetString("java-app-name", /*ref*/ tmpStr))
+ pJavaAppName->SetValue(tmpStr);
+
+ /*
+ * Configure the onion skin options sizer.
+ */
+ wxTextCtrl* pOnionSkinFileNameText;
+ wxButton* pOnionSkinFileButton;
+ wxSlider* pOnionSkinAlphaSlider;
+ tmpSizer = new wxBoxSizer(wxHORIZONTAL);
+ pOverlayOnionSkin = new wxCheckBox(base,
+ IDC_OVERLAY_ONION_SKIN, wxT("Overlay &onion skin"));
+ tmpSizer->Add(pOverlayOnionSkin);
+
+ pOnionSkinFileNameText = new wxTextCtrl(base,
+ IDC_ONION_SKIN_FILE_NAME, wxT(""),
+ wxDefaultPosition, wxSize(250, -1),
+ wxTE_PROCESS_ENTER);
+ pOnionSkinFileButton = new wxButton(base, IDC_ONION_SKIN_BUTTON,
+ wxT("Choose"));
+
+ wxBoxSizer* onionSkinFileNameSizer = new wxBoxSizer(wxHORIZONTAL);
+ onionSkinFileNameSizer->Add(
+ new wxStaticText(base, wxID_ANY,
+ wxT("Filename:"),
+ wxDefaultPosition, wxDefaultSize,
+ wxALIGN_LEFT),
+ 0, wxALIGN_CENTER_VERTICAL);
+ onionSkinFileNameSizer->AddSpacer(kInterSpacing);
+ onionSkinFileNameSizer->Add(pOnionSkinFileNameText);
+ onionSkinFileNameSizer->Add(pOnionSkinFileButton);
+
+ wxBoxSizer * onionSkinAlphaSizer = new wxBoxSizer(wxHORIZONTAL);
+ int initialAlphaVal = 127;
+ pPrefs->GetInt("onion-skin-alpha-value", &initialAlphaVal);
+ pOnionSkinAlphaSlider = new wxSlider(base, IDC_ONION_SKIN_ALPHA_VAL,
+ initialAlphaVal, 0, 255, wxDefaultPosition, wxSize(150, 20));
+ onionSkinAlphaSizer->Add(
+ new wxStaticText(base, wxID_ANY,
+ wxT("Transparency:"),
+ wxDefaultPosition, wxDefaultSize,
+ wxALIGN_LEFT),
+ 0, wxALIGN_CENTER_VERTICAL);
+ onionSkinAlphaSizer->AddSpacer(kInterSpacing);
+ onionSkinAlphaSizer->Add(pOnionSkinAlphaSlider, 1, wxCENTRE | wxALL, 5);
+
+ onionSkinOptSizer->Add(tmpSizer);
+ onionSkinOptSizer->AddSpacer(kInterSpacing);
+ onionSkinOptSizer->Add(onionSkinFileNameSizer);
+ onionSkinOptSizer->Add(onionSkinAlphaSizer);
+
+ wxString tmpStr2;
+ SetCheckFromPref(pOverlayOnionSkin, "overlay-onion-skin", false);
+ if (pPrefs->GetString("onion-skin-file-name", /*ref*/ tmpStr2))
+ pOnionSkinFileNameText->SetValue(tmpStr2);
+
+ /*
+ * Add the various components to the master sizer.
+ */
+ masterSizer->Add(displayOptSizer);
+ masterSizer->AddSpacer(kInterSpacing * 2);
+ masterSizer->Add(runtimeOptSizer);
+ masterSizer->AddSpacer(kInterSpacing * 2);
+ masterSizer->Add(onionSkinOptSizer);
+ //masterSizer->AddSpacer(kInterSpacing);
+
+ /*
+ * I don't see a way to guarantee that the window is wide enough to
+ * show the entire menu bar, so just throw some pixels at it.
+ */
+ wxBoxSizer* minWidthSizer = new wxBoxSizer(wxVERTICAL);
+ minWidthSizer->Add(300, kEdgeSpacing); // forces minimum width
+ minWidthSizer->Add(masterSizer);
+ minWidthSizer->AddSpacer(kInterSpacing * 2);
+
+ /* move us a few pixels in from the left */
+ wxBoxSizer* indentSizer = new wxBoxSizer(wxHORIZONTAL);
+ indentSizer->AddSpacer(kEdgeSpacing);
+ indentSizer->Add(minWidthSizer);
+ indentSizer->AddSpacer(kEdgeSpacing);
+
+ base->SetSizer(indentSizer);
+
+ indentSizer->Fit(this);
+ indentSizer->SetSizeHints(this);
+}
+
+/*
+ * Set the value of a checkbox based on a value from the config file.
+ */
+void MainFrame::SetCheckFromPref(wxCheckBox* pControl, const char* prefStr,
+ bool defaultVal)
+{
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ assert(pPrefs != NULL);
+
+ bool val = defaultVal;
+ pPrefs->GetBool(prefStr, &val);
+
+ pControl->SetValue(val);
+}
+
+/*
+ * Destructor.
+ */
+MainFrame::~MainFrame(void)
+{
+ PhoneCollection::DestroyInstance();
+
+ delete mExternalRuntimeThread;
+ delete mPropertyServerThread;
+
+ // don't touch mpModeSelection -- child of window
+}
+
+/*
+ * File->Quit or click on close box.
+ *
+ * If we want an "are you sure you want to quit" box, add it here.
+ */
+void MainFrame::OnClose(wxCloseEvent& event)
+{
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+
+/*
+ if (event.CanVeto())
+ printf("Closing (can veto)\n");
+ else
+ printf("Closing (mandatory)\n");
+*/
+
+ /*
+ * Generally speaking, Close() is not guaranteed to close the window.
+ * However, we want to use it here because (a) our windows are
+ * guaranteed to close, and (b) it provides our windows an opportunity
+ * to tell others that they are about to vanish.
+ */
+ if (mpPhoneWindow != NULL)
+ mpPhoneWindow->Close(true);
+
+ /* save position of main window */
+ wxPoint pos = GetPosition();
+ pPrefs->SetInt("window-main-x", pos.x);
+ pPrefs->SetInt("window-main-y", pos.y);
+
+ /* save default device selection */
+ int idx = GetSelectedDeviceIndex();
+ if (idx >= 0) {
+ PhoneCollection* pCollection = PhoneCollection::GetInstance();
+ PhoneData* pPhoneData = pCollection->GetPhoneData(idx);
+ pPrefs->SetString("default-device", pPhoneData->GetName());
+ }
+
+ if (mpLogWindow != NULL)
+ mpLogWindow->Close(true);
+ Destroy();
+}
+
+/*
+ * File->Preferences
+ */
+void MainFrame::OnFilePreferences(wxCommandEvent& WXUNUSED(event))
+{
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ PrefsDialog dialog(this);
+ int result;
+
+ result = dialog.ShowModal();
+ if (result == wxID_OK) {
+ /*
+ * The dialog handles writing changes to Preferences, so all we
+ * need to deal with here are changes that have an immediate
+ * impact on us. (which is currently nothing)
+ */
+ }
+}
+
+/*
+ * File->Exit
+ */
+void MainFrame::OnFileExit(wxCommandEvent& WXUNUSED(event))
+{
+ Close(FALSE); // false means "allow veto"
+}
+
+/*
+ * Decide whether Simulator->Start should be enabled.
+ */
+void MainFrame::OnUpdateSimStart(wxUpdateUIEvent& event)
+{
+ if (IsRuntimeRunning())
+ event.Enable(FALSE);
+ else
+ event.Enable(TRUE);
+}
+
+/*
+ * Simulator->Start
+ */
+void MainFrame::OnSimStart(wxCommandEvent& WXUNUSED(event))
+{
+ // keyboard equivalents can still get here even if menu item disabled
+ if (IsRuntimeRunning())
+ return;
+
+ int id = GetSelectedDeviceIndex();
+ if (id < 0) {
+ fprintf(stderr, "Sim: could not identify currently selected device\n");
+ return;
+ }
+
+#if 0
+ static int foo = 0;
+ foo++;
+ if (foo == 2) {
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+
+ pPrefs->SetBool("debug", true);
+ }
+#endif
+
+ SetupPhoneUI(id, NULL);
+ if (mpPhoneWindow != NULL)
+ mpPhoneWindow->GetDeviceManager()->StartRuntime();
+}
+
+/*
+ * Decide whether Simulator->Stop should be enabled.
+ */
+void MainFrame::OnUpdateSimStop(wxUpdateUIEvent& event)
+{
+ if (IsRuntimeRunning())
+ event.Enable(TRUE);
+ else
+ event.Enable(FALSE);
+}
+
+/*
+ * Simulator->Stop
+ */
+void MainFrame::OnSimStop(wxCommandEvent& WXUNUSED(event))
+{
+ if (!IsRuntimeRunning())
+ return;
+ assert(mpPhoneWindow != NULL);
+ mpPhoneWindow->GetDeviceManager()->StopRuntime();
+}
+
+/*
+ * Decide whether Simulator->Restart should be enabled.
+ */
+void MainFrame::OnUpdateSimRestart(wxUpdateUIEvent& event)
+{
+ if (IsRuntimeRunning())
+ event.Enable(TRUE);
+ else
+ event.Enable(FALSE);
+}
+
+/*
+ * Simulator->Restart - stop then start the device runtime.
+ */
+void MainFrame::OnSimRestart(wxCommandEvent& WXUNUSED(event))
+{
+ if (!IsRuntimeRunning())
+ return;
+
+ printf("Restart requested\n");
+ mpPhoneWindow->GetDeviceManager()->StopRuntime();
+
+ mRestartRequested = true;
+}
+
+/*
+ * Decide whether Simulator->Kill should be enabled.
+ */
+void MainFrame::OnUpdateSimKill(wxUpdateUIEvent& event)
+{
+ if (IsRuntimeKillable())
+ event.Enable(TRUE);
+ else
+ event.Enable(FALSE);
+}
+
+/*
+ * Simulator->Kill
+ */
+void MainFrame::OnSimKill(wxCommandEvent& WXUNUSED(event))
+{
+ if (!IsRuntimeKillable())
+ return;
+ assert(mpPhoneWindow != NULL);
+ mpPhoneWindow->GetDeviceManager()->KillRuntime();
+}
+
+
+/*
+ * Device->[select]
+ */
+void MainFrame::OnDeviceSelected(wxCommandEvent& event)
+{
+ wxBusyCursor busyc;
+ int id = event.GetId() - IDM_DEVICE_SEL0;
+
+ SetupPhoneUI(id, NULL);
+}
+
+/*
+ * Device->Rescan
+ */
+void MainFrame::OnDeviceRescan(wxCommandEvent& event)
+{
+ wxBusyCursor busyc;
+ wxMenuBar* pMenuBar;
+ PhoneCollection* pCollection;
+ wxMenu* pOldMenu;
+ wxMenu* pNewMenu;
+ const char* curDevName = NULL;
+ int idx;
+
+ /* figure out the current device name */
+ pCollection = PhoneCollection::GetInstance();
+ idx = GetSelectedDeviceIndex();
+ if (idx >= 0) {
+ PhoneData* pPhoneData;
+
+ pPhoneData = pCollection->GetPhoneData(idx);
+ curDevName = pPhoneData->GetName();
+ printf("--- device name is '%s'\n", (const char*) curDevName);
+ }
+
+ /* reconstruct device menu with new data */
+#ifdef BEFORE_ASSET
+ pCollection->ScanForPhones(mSimAssetPath);
+#else
+ pCollection->ScanForPhones(NULL);
+#endif
+
+ pMenuBar = GetMenuBar();
+ idx = pMenuBar->FindMenu(kDeviceMenuString);
+ if (idx == wxNOT_FOUND) {
+ fprintf(stderr, "Sim: couldn't find %s menu\n", (const char*) kDeviceMenuString.ToAscii());
+ return;
+ }
+
+ pNewMenu = CreateDeviceMenu(curDevName);
+
+ pOldMenu = pMenuBar->Replace(idx, pNewMenu, kDeviceMenuString);
+ delete pOldMenu;
+
+ /* tell the PhoneWindow about it; may cause runtime to exit */
+ if (mpPhoneWindow != NULL)
+ mpPhoneWindow->DevicesRescanned();
+}
+
+/*
+ * Set checkbox on menu item.
+ */
+void MainFrame::OnUpdateDebugShowLog(wxUpdateUIEvent& event)
+{
+ if (mpLogWindow == NULL) {
+ event.Enable(false);
+ } else {
+ event.Enable(true);
+ event.Check(mpLogWindow->IsShown());
+ }
+}
+
+/*
+ * Debug->ShowLog toggle.
+ */
+void MainFrame::OnDebugShowLog(wxCommandEvent& WXUNUSED(event))
+{
+ mpLogWindow->Show(!mpLogWindow->IsShown());
+}
+
+/*
+ * Help->Contents
+ */
+void MainFrame::OnHelpContents(wxCommandEvent& WXUNUSED(event))
+{
+ ((MyApp*)wxTheApp)->GetHelpController()->DisplayContents();
+}
+
+/*
+ * Help->About
+ */
+void MainFrame::OnHelpAbout(wxCommandEvent& WXUNUSED(event))
+{
+ wxMessageBox(wxT("Android Simulator v0.1\n"
+ "Copyright 2006 The Android Open Source Project"),
+ wxT("About..."), wxOK | wxICON_INFORMATION, this);
+}
+
+/*
+ * Sent from phonewindow or when activated
+ */
+void MainFrame::OnActivate(wxActivateEvent& event)
+{
+#if 0
+ if (event.GetActive())
+ {
+ if (mpPhoneWindow != NULL &&
+ mpPhoneWindow->GetDeviceManager()->RefreshRuntime())
+ {
+ wxString msg;
+ int sel;
+
+ msg = wxT("Newer runtime executable found. Would you like to reload the device?");
+
+ sel = wxMessageBox(msg, wxT("Android Safety Patrol"),
+ wxYES | wxNO | wxICON_QUESTION, mpPhoneWindow);
+ //printf("BUTTON was %d (yes=%d)\n", sel, wxYES);
+ if (sel == wxYES)
+ {
+ mpPhoneWindow->GetDeviceManager()->StopRuntime();
+ mpPhoneWindow->Close();
+ mpPhoneWindow = NULL;
+ mRestartRequested = true;
+ }
+ else
+ {
+ mpPhoneWindow->GetDeviceManager()->UserCancelledRefresh();
+ }
+ }
+ }
+#endif
+
+ // let wxWidgets do whatever it needs to do
+ event.Skip();
+}
+
+
+/*
+ * Device mode selection box.
+ */
+void MainFrame::OnComboBox(wxCommandEvent& event)
+{
+ const char* pref;
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ assert(pPrefs != NULL);
+
+ if (IDC_MODE_SELECT == event.GetId())
+ {
+ int id = GetSelectedDeviceIndex();
+ if (id < 0)
+ return;
+ //printf("--- mode selected: '%s'\n", (const char*) event.GetString().ToAscii());
+
+ /*
+ * Call the phone window's setup function. Don't call our SetupPhoneUI
+ * function from here -- updating the combo box from a combo box callback
+ * could cause problems.
+ */
+ if (mpPhoneWindow != NULL) {
+ mpPhoneWindow->SetCurrentMode(event.GetString());
+ mpPhoneWindow->Setup(id);
+ }
+ } else if (event.GetId() == IDC_JAVA_VM) {
+ wxComboBox* pBox = (wxComboBox*) FindWindow(IDC_JAVA_VM);
+ pPrefs->SetString("java-vm", pBox->GetValue().ToAscii());
+ }
+}
+
+/*
+ * One of our option checkboxes has been changed.
+ *
+ * We update the prefs database so that the settings are retained when
+ * the simulator is next used.
+ */
+void MainFrame::OnCheckBox(wxCommandEvent& event)
+{
+ const char* pref;
+
+ switch (event.GetId()) {
+ case IDC_USE_GDB: pref = "debug"; break;
+ case IDC_USE_VALGRIND: pref = "valgrind"; break;
+ case IDC_CHECK_JNI: pref = "check-jni"; break;
+ case IDC_OVERLAY_ONION_SKIN: pref = "overlay-onion-skin"; break;
+ default:
+ printf("Sim: unrecognized checkbox %d in OnCheckBox\n", event.GetId());
+ return;
+ }
+
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ assert(pPrefs != NULL);
+
+ pPrefs->SetBool(pref, (bool) event.GetInt());
+ //printf("--- set pref '%s' to %d\n", pref, (bool) event.GetInt());
+ if (event.GetId() == IDC_OVERLAY_ONION_SKIN) {
+ BroadcastOnionSkinUpdate();
+ }
+ if (event.GetId() == IDC_CHECK_JNI) {
+ const char* val = "0";
+ if ((bool) event.GetInt())
+ val = "1";
+ mPropertyServerThread->SetProperty(PropertyServer::kPropCheckJni, val);
+
+ }
+}
+
+void MainFrame::BroadcastOnionSkinUpdate() {
+ if (mpPhoneWindow != NULL) {
+ // broadcast a user event indicating an onion skin update
+ UserEvent uev(0, (void*) -1);
+ mpPhoneWindow->GetDeviceManager()->BroadcastEvent(uev);
+ }
+}
+
+/*
+ * A text control on the main page is being updated.
+ *
+ * The current implementation updates the preferences database on every
+ * change, which is a bit silly but is easy to do.
+ */
+void MainFrame::OnText(wxCommandEvent& event)
+{
+ const char* pref;
+
+ switch (event.GetId()) {
+ case IDC_JAVA_APP_NAME: pref = "java-app-name"; break;
+ default:
+ printf("Sim: unrecognized textctrl %d in OnText\n", event.GetId());
+ return;
+ }
+
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ assert(pPrefs != NULL);
+
+ // event.GetString() does not work on Mac -- always blank
+ //pPrefs->SetString(pref, event.GetString());
+ assert(event.GetId() == IDC_JAVA_APP_NAME); // fix if we add more
+ wxComboBox* pBox;
+ pBox = (wxComboBox*) FindWindow(IDC_JAVA_APP_NAME);
+ pPrefs->SetString(pref, pBox->GetValue().ToAscii());
+ //printf("--- set pref '%s' to '%s'\n", pref,(const char*)pBox->GetValue());
+}
+
+/*
+ * A user pressed enter in a text control on the main page.
+ *
+ * The current implementation updates the preferences database on every
+ * change, which is a bit silly but is easy to do.
+ */
+void MainFrame::OnTextEnter(wxCommandEvent& event)
+{
+ const char* pref;
+
+ switch (event.GetId()) {
+ case IDC_ONION_SKIN_FILE_NAME:
+ pref = "onion-skin-file-name";
+ break;
+ default:
+ printf("Sim: unrecognized textctrl %d in OnTextEnter\n", event.GetId());
+ return;
+ }
+
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ assert(pPrefs != NULL);
+
+ assert(event.GetId() == IDC_ONION_SKIN_FILE_NAME); // fix if we add more
+ wxTextCtrl* pTextCtrl;
+ pTextCtrl = (wxTextCtrl*) FindWindow(IDC_ONION_SKIN_FILE_NAME);
+ wxString onionSkinFileNameWxString = pTextCtrl->GetValue();
+ char* onionSkinFileName = "";
+ if (onionSkinFileNameWxString.Len() > 0) {
+ onionSkinFileName = android::strdupNew(onionSkinFileNameWxString.ToAscii());
+ }
+ pPrefs->SetString(pref, onionSkinFileName);
+ BroadcastOnionSkinUpdate();
+}
+
+/*
+ * A user pressed a button on the main page
+ *
+ */
+ void MainFrame::OnButton(wxCommandEvent& event)
+ {
+ wxWindow* base;
+ wxFileDialog* pOnionSkinFileChooser;
+ int retVal;
+ switch (event.GetId()) {
+ case IDC_ONION_SKIN_BUTTON:
+ base = FindWindow(IDC_ONION_SKIN_BUTTON)->GetParent();
+ pOnionSkinFileChooser = new wxFileDialog(base,
+ wxT("Choose the onion skin image file."),
+ wxT(""), wxT(""), wxT("*.*"),
+ wxOPEN | wxFILE_MUST_EXIST);
+ retVal = pOnionSkinFileChooser->ShowModal();
+ if (retVal == pOnionSkinFileChooser->GetAffirmativeId()) {
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ assert(pPrefs != NULL);
+ wxString fileNameWxString = pOnionSkinFileChooser->GetPath();
+ const char* fileName = android::strdupNew(fileNameWxString.ToAscii());
+ wxTextCtrl* fileTextCtrl = (wxTextCtrl*) FindWindow(IDC_ONION_SKIN_FILE_NAME);
+ fileTextCtrl->SetValue(fileNameWxString);
+ pPrefs->SetString("onion-skin-file-name", fileName);
+ BroadcastOnionSkinUpdate();
+ }
+ break;
+ default:
+ printf("Sim: unrecognized button %d in OnButton\n", event.GetId());
+ return;
+ }
+ }
+
+ /*
+ * The user moved a slider on the main page
+ */
+ void MainFrame::OnSliderChange(wxScrollEvent& event)
+ {
+ wxSlider* pSlider;
+ Preferences* pPrefs;
+ switch (event.GetId()) {
+ case IDC_ONION_SKIN_ALPHA_VAL:
+ pSlider = (wxSlider*) FindWindow(IDC_ONION_SKIN_ALPHA_VAL);
+ pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ assert(pPrefs != NULL);
+ pPrefs->SetInt("onion-skin-alpha-value", pSlider->GetValue());
+ BroadcastOnionSkinUpdate();
+ break;
+ default:
+ printf("Sim: unrecognized scroller or slider %d in OnSliderChange\n", event.GetId());
+ return;
+ }
+ }
+
+#if 0
+/*
+ * Idle processing. Under wxWidgets this only called once after UI
+ * activity unless you call event.RequestMore().
+ */
+void MainFrame::OnIdle(wxIdleEvent& event)
+{
+ event.Skip(); // let base class handler do stuff
+}
+#endif
+
+/*
+ * Handle the timer.
+ *
+ * This is being called in the main thread, so multithreading with the
+ * rest of MainFrame isn't a concern here.
+ */
+void MainFrame::OnTimer(wxTimerEvent& event)
+{
+ bool status;
+
+ /*
+ * Check to see if the runtime died without telling us. This can only
+ * happen if we forcibly kill our thread. We shouldn't really be
+ * doing that anymore, but keep this in for now just in case.
+ */
+ status = IsRuntimeRunning();
+
+ if (mSimRunning != status) {
+ if (!status) {
+ printf("Sim: fixed mSimRunning=%d actual=%d\n",
+ mSimRunning, status);
+ mSimRunning = status;
+
+ if (!status)
+ HandleRuntimeStop();
+ } else {
+ /*
+ * This was happening when we were shutting down but the
+ * device management thread hadn't completely gone away. The
+ * simple IsRunning test passes, so we get a false positive.
+ * Ignore it.
+ */
+ }
+ }
+
+ if (gWantToKill) {
+ if (IsRuntimeRunning()) {
+ printf("Sim: handling kill request\n");
+ mpPhoneWindow->GetDeviceManager()->KillRuntime();
+ }
+ gWantToKill = false;
+
+ /* see if Ctrl-C should kill us too */
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ bool die = false;
+
+ pPrefs->GetBool("trap-sigint-suicide", &die);
+ if (die) {
+ printf("Sim: goodbye cruel world!\n");
+ exit(0);
+ }
+ }
+}
+
+/*
+ * Determine whether or not the simulator is running.
+ */
+bool MainFrame::IsRuntimeRunning(void)
+{
+ bool result;
+
+ if (mpPhoneWindow == NULL)
+ result = false;
+ else if (!mpPhoneWindow->IsReady())
+ result = false;
+ else
+ result = mpPhoneWindow->GetDeviceManager()->IsRunning();
+
+ return result;
+}
+
+/*
+ * Determine whether or not the runtime can be killed.
+ */
+bool MainFrame::IsRuntimeKillable(void)
+{
+ bool result;
+
+ result = IsRuntimeRunning();
+ if (result)
+ result = mpPhoneWindow->GetDeviceManager()->IsKillable();
+
+ return result;
+}
+
+/*
+ * Determine whether two devices are sufficiently compatible.
+ */
+bool MainFrame::CompatibleDevices(PhoneData* pData1, PhoneData* pData2)
+{
+ int displayCount;
+
+ displayCount = pData1->GetNumDisplays();
+ if (pData2->GetNumDisplays() != displayCount)
+ return false;
+
+ for (int i = 0; i < displayCount; i++) {
+ PhoneDisplay* pDisplay1 = pData1->GetPhoneDisplay(i);
+ PhoneDisplay* pDisplay2 = pData2->GetPhoneDisplay(i);
+
+ if (!PhoneDisplay::IsCompatible(pDisplay1, pDisplay2))
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * (Re-)arrange the UI for the currently selected phone model.
+ *
+ * If the simulator is running, and the set of displays for the current
+ * device are incompatible with the new device, we need to restart the
+ * runtime. We need to ask for permission first though.
+ */
+void MainFrame::SetupPhoneUI(int idx, const char* defaultMode)
+{
+ PhoneCollection* pCollection;
+ PhoneData* pPhoneData;
+ wxString* choices = NULL;
+ int numChoices = 0;
+ int numKeyboards = 0;
+ bool haveDefaultMode = false;
+ wxCharBuffer currentMode;
+ int i;
+
+ pCollection = PhoneCollection::GetInstance();
+ pPhoneData = pCollection->GetPhoneData(idx);
+ if (pPhoneData == NULL) {
+ fprintf(stderr, "ERROR: device index %d not valid\n", idx);
+ goto bail;
+ }
+
+ /*
+ * We have a window up. If the displays aren't compatible, we'll
+ * need to recreate it.
+ */
+ if (mpPhoneWindow != NULL) {
+ PhoneData* pCurData = mpPhoneWindow->GetPhoneData();
+
+ if (!CompatibleDevices(pCurData, pPhoneData)) {
+ /*
+ * We need to trash the window. This will also kill the
+ * runtime. If it's running, ask permission.
+ */
+ if (IsRuntimeRunning()) {
+ wxString msg;
+ int sel;
+
+ msg = wxT("Switching to the new device requires restarting the");
+ msg += wxT(" runtime. Continue?");
+
+ sel = wxMessageBox(msg, wxT("Android Safety Patrol"),
+ wxOK | wxCANCEL | wxICON_QUESTION, this);
+ printf("BUTTON was %d (ok=%d)\n", sel, wxOK);
+ if (sel == wxCANCEL)
+ goto bail;
+
+ /* shut it down (politely), ask for an eventual restart */
+ mpPhoneWindow->GetDeviceManager()->StopRuntime();
+ mpPhoneWindow->Close();
+ mpPhoneWindow = NULL;
+ mRestartRequested = true;
+ goto bail;
+ } else {
+ /* not running, just trash the window and continue */
+ mpPhoneWindow->Close();
+ mpPhoneWindow = NULL;
+ }
+ }
+ }
+
+ /*
+ * Figure out the set of available modes.
+ */
+
+ numChoices = pPhoneData->GetNumModes();
+ if (numChoices > 0) {
+ choices = new wxString[numChoices];
+ for (i = 0; i < numChoices; i++) {
+ PhoneMode* pPhoneMode;
+ pPhoneMode = pPhoneData->GetPhoneMode(i);
+ choices[i] = wxString::FromAscii(pPhoneMode->GetName());
+ if (defaultMode != NULL &&
+ strcmp(defaultMode, pPhoneMode->GetName()) == 0)
+ {
+ haveDefaultMode = true;
+ }
+ }
+ }
+
+ if (choices == NULL) {
+ /* had a failure earlier; configure UI with default stuff */
+ choices = new wxString[1];
+ choices[0] = wxT("(none)");
+ }
+
+ if (!haveDefaultMode) {
+ /*
+ * Default mode wasn't found. If we specify it as the default
+ * in the wxComboBox create call it shows up in the combo box
+ * under Linux, even if it doesn't exist in the list. So, we
+ * make sure that it doesn't get used if we can't find it.
+ */
+ if (defaultMode != NULL) {
+ printf("Sim: HEY: default mode '%s' not found in list\n",
+ defaultMode);
+ }
+ currentMode = choices[0].ToAscii();
+ } else {
+ currentMode = defaultMode;
+ }
+
+
+ /*
+ * Create the window if necessary.
+ */
+ if (mpPhoneWindow == NULL) {
+ // create, setup, and then show window
+ mpPhoneWindow = new PhoneWindow(this, mPhoneWindowPosn);
+ mpPhoneWindow->SetCurrentMode((const char*)currentMode);
+ if (!mpPhoneWindow->Setup(idx)) {
+ delete mpPhoneWindow;
+ mpPhoneWindow = NULL;
+ }
+ if (mpPhoneWindow != NULL) {
+ mpPhoneWindow->Show();
+ //mpPhoneWindow->CheckPlacement();
+ }
+ } else {
+ // just set up for new device
+ mpPhoneWindow->SetCurrentMode((const char*)currentMode);
+ if (!mpPhoneWindow->Setup(idx)) {
+ // it's in an uncertain state, blow it away
+ delete mpPhoneWindow;
+ mpPhoneWindow = NULL;
+ }
+ }
+
+ /*
+ * Reconfigure mode selection box.
+ */
+ wxComboBox* pModeSelection;
+ pModeSelection = (wxComboBox*)FindWindow(IDC_MODE_SELECT);
+ pModeSelection->Clear();
+ for (i = 0; i < numChoices; i++)
+ pModeSelection->Append(choices[i]);
+ pModeSelection->SetSelection(0);
+ pModeSelection->Enable(numChoices > 1);
+
+ /*
+ * configure qwerty keyboard attribute
+ */
+ numKeyboards = pPhoneData->GetNumKeyboards();
+ if (numKeyboards > 0) {
+ // only use the first keyboard for now
+ PhoneKeyboard* pPhoneKeyboard;
+ pPhoneKeyboard = pPhoneData->GetPhoneKeyboard(0);
+ if (pPhoneKeyboard->getQwerty()) {
+ printf("Sim: set 'qwerty' env\n");
+ setenv("qwerty", "true", true);
+ }
+ }
+
+bail:
+ delete[] choices;
+}
+
+/*
+ * Figure out which device is currently selected.
+ *
+ * The easiest way to do this is just run down the list of possible IDs
+ * and stop when something claims to be checked.
+ *
+ * Returns -1 if it can't find a checked item (which can happen if no
+ * device layouts were found).
+ */
+int MainFrame::GetSelectedDeviceIndex(void)
+{
+ wxMenuBar* pMenuBar;
+ wxMenu* pMenu;
+ int idx;
+
+ pMenuBar = GetMenuBar();
+ idx = pMenuBar->FindMenu(kDeviceMenuString);
+ if (idx == wxNOT_FOUND) {
+ fprintf(stderr, "Sim: couldn't find %s menu\n", (const char*) kDeviceMenuString.ToAscii());
+ return -1;
+ }
+
+ pMenu = pMenuBar->GetMenu(idx);
+
+ //printf("Menu.MenuItemCount = %d\n", pMenu->GetMenuItemCount());
+ for (int j = pMenu->GetMenuItemCount() -1; j >= 0; j--) {
+ wxMenuItem* pItem;
+
+ pItem = pMenu->FindItemByPosition(j);
+ //printf("ITEM %d: %s\n", j, (const char*) pItem->GetLabel());
+ if (pItem->IsChecked()) {
+ printf("Sim: selected device is '%s'\n",
+ (const char*) pItem->GetLabel().ToAscii());
+ return j;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * Receive a status message from the runtime thread.
+ */
+void MainFrame::OnUserEvent(UserEvent& event)
+{
+ UserEventMessage* pUem;
+
+ pUem = (UserEventMessage*) event.GetData();
+ assert(pUem != NULL);
+
+ switch (pUem->GetType()) {
+ case UserEventMessage::kRuntimeStarted:
+ printf("Sim: runtime thread started!\n");
+ HandleRuntimeStart();
+ break;
+ case UserEventMessage::kRuntimeStopped:
+ printf("Sim: runtime thread stopped!\n");
+ HandleRuntimeStop();
+ break;
+ case UserEventMessage::kErrorMessage:
+ {
+ wxString msg = pUem->GetString();
+ wxMessageBox(msg, wxT("Android Runtime Error"),
+ wxOK | wxICON_WARNING, this);
+ }
+ break;
+ case UserEventMessage::kLogMessage:
+ mpLogWindow->AddLogMessage(pUem->GetLogMessage());
+ break;
+ case UserEventMessage::kExternalRuntime:
+ HandleExternalRuntime(pUem->GetReader(), pUem->GetWriter());
+ break;
+ default:
+ printf("Sim: MESSAGE: unknown UserEventMessage rcvd (type=%d)\n",
+ pUem->GetType());
+ break;
+ }
+
+ delete pUem;
+}
+
+/*
+ * The device management thread is up, so the runtime should be fully
+ * running shortly.
+ */
+void MainFrame::HandleRuntimeStart(void)
+{
+ mSimRunning = true;
+
+ SetStatusText(kStatusRunning, 1);
+}
+
+/*
+ * The device management thread is exiting, so the runtime must be dead.
+ */
+void MainFrame::HandleRuntimeStop(void)
+{
+ mSimRunning = false;
+
+ SetStatusText(kStatusNotRunning, 1);
+
+ if (mRestartRequested) {
+ printf("Sim: restarting runtime\n");
+ mRestartRequested = false;
+ SetupPhoneUI(GetSelectedDeviceIndex(), NULL);
+ if (mpPhoneWindow != NULL)
+ mpPhoneWindow->GetDeviceManager()->StartRuntime();
+ }
+}
+
+/*
+ * Handle a connection from an external runtime.
+ */
+void MainFrame::HandleExternalRuntime(android::Pipe* reader,
+ android::Pipe* writer)
+{
+ android::MessageStream msgStream;
+ android::Message msg;
+
+ if (IsRuntimeRunning()) {
+ /*
+ * Tell the new guy to go away.
+ */
+ if (!msgStream.init(reader, writer, true)) {
+ fprintf(stderr, "Sim: WARNING: unable to talk to remote runtime\n");
+ goto bail;
+ }
+
+ printf("Sim: telling external runtime to go away\n");
+ msg.setCommand(android::Simulator::kCommandGoAway, 0);
+ msgStream.send(&msg);
+ } else {
+ printf("Sim: new external runtime wants to talk to us\n");
+
+ /*
+ * Launch the pieces necessary to talk to this guy.
+ */
+ int id = GetSelectedDeviceIndex();
+ if (id < 0) {
+ fprintf(stderr,
+ "Sim: could not identify currently selected device\n");
+ goto bail;
+ }
+
+ /* kill existing window, so it pops up and reclaims focus */
+ if (mpPhoneWindow != NULL) {
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+ bool okay;
+
+ if (pPrefs->GetBool("refocus-on-restart", &okay) && okay) {
+ printf("Sim: inducing phone window refocus\n");
+ mpPhoneWindow->Close(TRUE); // no veto
+ mpPhoneWindow = NULL;
+ }
+ }
+
+ SetupPhoneUI(id, NULL);
+ if (mpPhoneWindow != NULL) {
+ mpPhoneWindow->GetDeviceManager()->StartRuntime(reader, writer);
+ } else {
+ fprintf(stderr, "Sim: ERROR: unable to get runtime going\n");
+ goto bail;
+ }
+
+ // we don't own these anymore
+ reader = writer = NULL;
+ }
+
+bail:
+ delete reader;
+ delete writer;
+}
+
+/*
+ * The phone window is about to destroy itself. Get rid of our pointer
+ * to it, and record its last position so we can create the new one in
+ * the same place.
+ */
+void MainFrame::PhoneWindowClosing(int x, int y)
+{
+ Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
+
+ mpPhoneWindow = NULL;
+
+ mPhoneWindowPosn.x = x;
+ mPhoneWindowPosn.y = y;
+
+ pPrefs->SetInt("window-device-x", x);
+ pPrefs->SetInt("window-device-y", y);
+}
+