Files
Upsilon/apps/apps_container.cpp
Léa Saviot a4d79332ea [poincare] Fix Warning message exit on special keys
We want the memory full warning to be exited only on OK, EXE, ... but
Syntax warning (for instance) to be exited on any key pressed
2018-09-14 17:59:14 +02:00

255 lines
7.3 KiB
C++

#include "apps_container.h"
#include "global_preferences.h"
#include <ion.h>
#include <poincare/exception_checkpoint.h>
extern "C" {
#include <assert.h>
}
using namespace Shared;
AppsContainer::AppsContainer() :
Container(),
m_window(),
m_emptyBatteryWindow(),
m_globalContext(),
m_variableBoxController(&m_globalContext),
m_examPopUpController(this),
m_updateController(),
m_batteryTimer(BatteryTimer(this)),
m_suspendTimer(SuspendTimer(this)),
m_backlightDimmingTimer(),
m_homeSnapshot(),
m_onBoardingSnapshot(),
m_hardwareTestSnapshot(),
m_usbConnectedSnapshot()
{
m_emptyBatteryWindow.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height));
Poincare::Expression::setCircuitBreaker(AppsContainer::poincareCircuitBreaker);
}
bool AppsContainer::poincareCircuitBreaker() {
Ion::Keyboard::State state = Ion::Keyboard::scan();
return state.keyDown(Ion::Keyboard::Key::A6);
}
App::Snapshot * AppsContainer::hardwareTestAppSnapshot() {
return &m_hardwareTestSnapshot;
}
App::Snapshot * AppsContainer::onBoardingAppSnapshot() {
return &m_onBoardingSnapshot;
}
App::Snapshot * AppsContainer::usbConnectedAppSnapshot() {
return &m_usbConnectedSnapshot;
}
void AppsContainer::reset() {
Clipboard::sharedClipboard()->reset();
for (int i = 0; i < numberOfApps(); i++) {
appSnapshotAtIndex(i)->reset();
}
}
Poincare::Context * AppsContainer::globalContext() {
return &m_globalContext;
}
MathToolbox * AppsContainer::mathToolbox() {
return &m_mathToolbox;
}
VariableBoxController * AppsContainer::variableBoxController() {
return &m_variableBoxController;
}
void AppsContainer::suspend(bool checkIfPowerKeyReleased) {
resetShiftAlphaStatus();
#if EPSILON_SOFTWARE_UPDATE_PROMPT
if (activeApp()->snapshot()!= onBoardingAppSnapshot() && activeApp()->snapshot() != hardwareTestAppSnapshot() && GlobalPreferences::sharedGlobalPreferences()->showUpdatePopUp()) {
activeApp()->displayModalViewController(&m_updateController, 0.f, 0.f);
}
#endif
Ion::Power::suspend(checkIfPowerKeyReleased);
/* Ion::Power::suspend() completely shuts down the LCD controller. Therefore
* the frame memory is lost. That's why we need to force a window redraw
* upon wakeup, otherwise the screen is filled with noise. */
Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel());
m_backlightDimmingTimer.reset();
window()->redraw(true);
}
bool AppsContainer::dispatchEvent(Ion::Events::Event event) {
bool alphaLockWantsRedraw = updateAlphaLock();
bool didProcessEvent = false;
if (event == Ion::Events::USBEnumeration) {
if (Ion::USB::isPlugged()) {
App::Snapshot * activeSnapshot = (activeApp() == nullptr ? appSnapshotAtIndex(0) : activeApp()->snapshot());
switchTo(usbConnectedAppSnapshot());
Ion::USB::DFU();
switchTo(activeSnapshot);
didProcessEvent = true;
} else {
/* Sometimes, the device gets an ENUMDNE interrupts when being unplugged
* from a non-USB communicating host (e.g. a USB charger). The interrupt
* must me cleared: if not the next enumeration attempts will not be
* detected. */
Ion::USB::clearEnumerationInterrupt();
}
} else {
didProcessEvent = Container::dispatchEvent(event);
}
if (!didProcessEvent) {
didProcessEvent = processEvent(event);
}
if (event.isKeyboardEvent()) {
m_backlightDimmingTimer.reset();
m_suspendTimer.reset();
Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel());
}
if (!didProcessEvent && alphaLockWantsRedraw) {
window()->redraw();
return true;
}
return didProcessEvent || alphaLockWantsRedraw;
}
bool AppsContainer::processEvent(Ion::Events::Event event) {
if (event == Ion::Events::USBPlug) {
if (Ion::USB::isPlugged()) {
if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) {
displayExamModePopUp(false);
} else {
Ion::USB::enable();
}
Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel());
} else {
Ion::USB::disable();
}
return true;
}
if (event == Ion::Events::Home || event == Ion::Events::Back) {
switchTo(appSnapshotAtIndex(0));
return true;
}
if (event == Ion::Events::OnOff) {
suspend(true);
return true;
}
return false;
}
void AppsContainer::switchTo(App::Snapshot * snapshot) {
if (activeApp() && snapshot != activeApp()->snapshot()) {
resetShiftAlphaStatus();
}
if (snapshot == hardwareTestAppSnapshot() || snapshot == onBoardingAppSnapshot()) {
m_window.hideTitleBarView(true);
} else {
m_window.hideTitleBarView(false);
}
if (snapshot) {
m_window.setTitle(snapshot->descriptor()->upperName());
}
Container::switchTo(snapshot);
}
void AppsContainer::run() {
window()->setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height));
refreshPreferences();
#if EPSILON_ONBOARDING_APP
switchTo(onBoardingAppSnapshot());
#else
if (numberOfApps() == 2) {
switchTo(appSnapshotAtIndex(1));
} else {
switchTo(appSnapshotAtIndex(0));
}
#endif
/* ExceptionCheckpoint stores the value of the stack pointer when setjump is
* called. During a longjump, the stack pointer is set to this stored stack
* pointer value, so the method where we call setjump must remain in the call
* tree for the jump to work. */
Poincare::ExceptionCheckpoint ecp;
if (!ExceptionRun(ecp)) {
activeApp()->snapshot()->reset();
switchTo(appSnapshotAtIndex(0));
activeApp()->displayWarning(I18n::Message::AppMemoryFull, true);
}
Container::run();
switchTo(nullptr);
}
bool AppsContainer::updateBatteryState() {
if (m_window.updateBatteryLevel() ||
m_window.updateIsChargingState() ||
m_window.updatePluggedState()) {
return true;
}
return false;
}
void AppsContainer::refreshPreferences() {
m_window.refreshPreferences();
}
void AppsContainer::displayExamModePopUp(bool activate) {
m_examPopUpController.setActivatingExamMode(activate);
activeApp()->displayModalViewController(&m_examPopUpController, 0.f, 0.f, Metric::ExamPopUpTopMargin, Metric::PopUpRightMargin, Metric::ExamPopUpBottomMargin, Metric::PopUpLeftMargin);
}
void AppsContainer::shutdownDueToLowBattery() {
while (Ion::Battery::level() == Ion::Battery::Charge::EMPTY) {
m_emptyBatteryWindow.redraw(true);
Ion::msleep(3000);
Ion::Power::suspend();
}
window()->redraw(true);
}
void AppsContainer::setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus newStatus) {
Ion::Events::setShiftAlphaStatus(newStatus);
updateAlphaLock();
}
bool AppsContainer::updateAlphaLock() {
return m_window.updateAlphaLock();
}
OnBoarding::UpdateController * AppsContainer::updatePopUpController() {
return &m_updateController;
}
void AppsContainer::redrawWindow() {
m_window.redraw();
}
void AppsContainer::examDeactivatingPopUpIsDismissed() {
if (Ion::USB::isPlugged()) {
Ion::USB::enable();
}
}
Window * AppsContainer::window() {
return &m_window;
}
int AppsContainer::numberOfContainerTimers() {
return 3;
}
Timer * AppsContainer::containerTimerAtIndex(int i) {
Timer * timers[3] = {&m_batteryTimer, &m_suspendTimer, &m_backlightDimmingTimer};
return timers[i];
}
void AppsContainer::resetShiftAlphaStatus() {
Ion::Events::setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default);
updateAlphaLock();
}