1463 lines
42 KiB
C++
1463 lines
42 KiB
C++
//
|
|
// 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);
|
|
}
|
|
|