blob: 65a6498dc9d4be8d95202087aa5bb900fcbdb3f5 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MINIOS_SCREENS_H_
#define MINIOS_SCREENS_H_
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <gtest/gtest_prod.h>
#include "minios/key_reader.h"
#include "minios/network_manager_interface.h"
#include "minios/process_manager.h"
#include "minios/screen_base.h"
#include "minios/update_engine_proxy.h"
namespace screens {
extern const char kScreens[];
// Dropdown Menu Colors.
extern const char kMenuDropdownFrameNavy[];
extern const char kMenuDropdownBackgroundBlack[];
// Key values.
extern const int kKeyUp;
extern const int kKeyDown;
extern const int kKeyEnter;
extern const int kKeyVolUp;
extern const int kKeyVolDown;
extern const int kKeyPower;
// Key state parameters.
extern const int kFdsMax;
extern const int kKeyMax;
// All the different screens in the MiniOs Flow. `kDownloadError` is shown when
// there is an Update Engine failure, `kNetworkError` is shown when there is an
// issue getting the networks. `kPasswordError` and `kConnectionError` are shown
// upon failures connecting to a chosen network.
enum class ScreenType {
kWelcomeScreen = 0,
kNetworkDropDownScreen = 1,
kExpandedNetworkDropDownScreen = 2,
kPasswordScreen = 3,
kLanguageDropDownScreen = 4,
kWaitForConnection = 5,
kStartDownload = 6,
kDownloadError = 7,
kNetworkError = 8,
kPasswordError = 9,
kConnectionError = 10,
};
// Screens contains the different MiniOs Screens as well as specific components
// such as dropdowns and footers which are built using the pieces of
// ScreenBase.
class Screens : public ScreenBase,
public key_reader::KeyReader::Delegate,
public UpdateEngineProxy::UpdaterDelegate,
public minios::NetworkManagerInterface::Observer {
public:
explicit Screens(
ProcessManagerInterface* process_manager,
std::shared_ptr<minios::NetworkManagerInterface> network_manager)
: process_manager_(process_manager),
network_manager_(network_manager),
key_states_(kFdsMax, std::vector<bool>(kKeyMax, false)) {
key_reader_.SetDelegate(this);
}
virtual ~Screens() = default;
// Not copyable or movable.
Screens(const Screens&) = delete;
Screens& operator=(const Screens&) = delete;
// Loads token constants for screen placement, checks whether locale is read
// from right to left and whether device is detachable.
bool Init();
// Has the minimum needed to set up tests, to reduce excessive logging. All
// other components are tested separately.
bool InitForTest();
// Shows the MiniOs Screens. Users can navigate between then using up/down
// arrow keys.
void StartMiniOsFlow();
// Shows the list of all supported locales with the currently selected index
// highlighted blue. Users can 'scroll' using the up and down arrow keys.
void ShowLanguageDropdown();
// Waits for key input and repaints the screen with a changed language
// selection, clears the whole screen including the footer and updates the
// language dependent constants. Returns to original screen after selection,
virtual void LanguageMenuOnSelect();
// Shows language menu drop down button on base screen. Button is highlighted
// if it is currently selected.
void ShowLanguageMenu(bool is_selected);
// Shows footer with basic instructions and chromebook model.
void ShowFooter();
// Clears screen and shows footer and language drop down menu.
void MessageBaseScreen();
// Shows a list of all available networks.
void ShowNetworkDropdown();
// Shows network menu drop down button on the screen. Button is
// highlighted if it is currently selected. Selecting this button directs to
// the expanded network dropdown.
void ShowCollapsedNetworkDropDown(bool is_selected);
// Queries list of available networks and shows them as a drop down. On
// selection sets the 'chosen_network' and redirects to the password
// screen.
void ExpandNetworkDropdown();
// Get user password using the keyboard layout stored in locale. Users can use
// the tab key to toggle showing the password.
virtual void GetPassword();
// Controls the flow of MiniOs by changing screen based on the current index
// and screen and whether or not a button has been selected(entered). Called
// every time a valid key press is recorded.
void SwitchScreen(bool enter);
// Getter and setter test functions for `index_` and `current_screen`.
void SetIndexForTest(int index) { index_ = index; }
int GetIndexForTest() { return index_; }
void SetScreenForTest(ScreenType current_screen) {
current_screen_ = current_screen;
}
ScreenType GetScreenForTest() { return current_screen_; }
// Sets network list for test.
void SetNetworkListForTest_(const std::vector<std::string>& networks) {
network_list_ = networks;
}
private:
FRIEND_TEST(ScreensTest, ReadDimension);
FRIEND_TEST(ScreensTest, GetDimension);
FRIEND_TEST(ScreensTest, GetLangConsts);
FRIEND_TEST(ScreensTest, GetLangConstsError);
FRIEND_TEST(ScreensTest, UpdateButtons);
FRIEND_TEST(ScreensTest, UpdateButtonsIsDetachable);
FRIEND_TEST(ScreensTest, CheckRightToLeft);
FRIEND_TEST(ScreensTest, CheckDetachable);
FRIEND_TEST(ScreensTest, GetVpdFromFile);
FRIEND_TEST(ScreensTest, GetVpdFromCommand);
FRIEND_TEST(ScreensTest, GetVpdFromDefault);
FRIEND_TEST(ScreensTest, GetHwidFromCommand);
FRIEND_TEST(ScreensTest, GetHwidFromDefault);
FRIEND_TEST(ScreensTest, GetFreconConstFile);
FRIEND_TEST(ScreensTest, GetFreconConstNoInt);
FRIEND_TEST(ScreensTest, GetFreconConstNoFile);
FRIEND_TEST(ScreensTest, MapRegionToKeyboardNoFile);
FRIEND_TEST(ScreensTest, MapRegionToKeyboardNotDict);
FRIEND_TEST(ScreensTest, MapRegionToKeyboardNoKeyboard);
FRIEND_TEST(ScreensTest, MapRegionToKeyboardBadKeyboardFormat);
FRIEND_TEST(ScreensTest, MapRegionToKeyboard);
FRIEND_TEST(ScreensTestMocks, OnKeyPress);
FRIEND_TEST(ScreensTestMocks, UpdateEngineError);
FRIEND_TEST(ScreensTestMocks, UpdateEngineProgressComplete);
FRIEND_TEST(ScreensTestMocks, IdleError);
FRIEND_TEST(ScreensTestMocks, GetNetworks);
FRIEND_TEST(ScreensTestMocks, OnConnectError);
FRIEND_TEST(ScreensTestMocks, OnPasswordError);
FRIEND_TEST(ScreensTestMocks, NoNetworksGiven);
FRIEND_TEST(ScreensTestMocks, ScreenFlowForwardWithNetwork);
FRIEND_TEST(ScreensTestMocks, GetNetworksRefresh);
FRIEND_TEST(ScreensTestMocks, ChangeErrorScreen);
FRIEND_TEST(ScreensTestMocks, ErrorScreenFallBack);
// Changes the index and enter value based on the given key. Unknown keys are
// ignored and index is kept within the range of menu items.
void UpdateButtons(int menu_count, int key, bool* enter);
// Read the language constants into memory. Does not change
// based on the current locale. Returns false on failure.
bool ReadLangConstants();
// Sets the width of language token for a given locale. Returns false on
// error.
bool GetLangConstants(const std::string& locale, int* lang_width);
// This function overloads Delegate. It is only called when the key is valid
// and updates the key state for the given fd and key. Calls `SwitchState` to
// update the flow once key is recorded as being pressed and released.
void OnKeyPress(int fd_index, int key_changed, bool key_released) override;
// `NetworkManagerInterface::Observer` overrides.
// Updates the list of networks stored by the UI to show in the drop down.
void OnGetNetworks(const std::vector<std::string>& networks,
brillo::Error* error) override;
// Attempts to connect, shows error screen on failure.
void OnConnect(const std::string& ssid, brillo::Error* error) override;
// Calls `GetNetworks` to update the the list of networks.
virtual void UpdateNetworkList();
// Does all the reloading needed when the locale is changed, including
// repainting the screen. Called after `LanguageDropdown` is done.
virtual void OnLocaleChange();
// Calls the show screen function of `current_screen`.
virtual void ShowNewScreen();
// Shows the buttons of MiniOs screens. Index changes button focus based on
// button order.
void ShowMiniOsWelcomeScreen();
void ShowMiniOsNetworkDropdownScreen();
void ShowMiniOsGetPasswordScreen();
void ShowWaitingForConnectionScreen();
void ShowMiniOsDownloadingScreen();
virtual void ShowMiniOsCompleteScreen();
// Checks whether the current language is read from right to left. Must be
// updated every time the language changes.
void CheckRightToLeft();
// Checks whether device has a detachable keyboard and sets `is_detachable`.
void CheckDetachable();
// Get region from VPD. Set vpd_region_ to US as default.
void GetVpdRegion();
// Get hardware Id from crossystem. Set hwid to `CHROMEBOOK` as default.
void ReadHardwareId();
// Get XKB keyboard layout based on the VPD region. Return false on error.
bool MapRegionToKeyboard(std::string* xkb_keyboard_layout);
// Calls corresponding MiniOs screen based on update engine status. If UE is
// `DOWNLOADING` then shows a progress bar with percentage.
void OnProgressChanged(const update_engine::StatusResult& status) override;
// Calls error screen components with different messages.
void ShowErrorScreen(std::string error_message);
// Reset and show error screen.
void ChangeToErrorScreen(enum ScreenType error_screen);
ProcessManagerInterface* process_manager_;
key_reader::KeyReader key_reader_ =
key_reader::KeyReader(/*include_usb=*/true);
std::shared_ptr<minios::NetworkManagerInterface> network_manager_;
// Whether the device has a detachable keyboard.
bool is_detachable_{false};
// Key value pairs that store language widths.
base::StringPairs lang_constants_;
// List of all supported locales.
std::vector<std::string> supported_locales_;
// List of currently available networks.
std::vector<std::string> network_list_;
// The networks the user has picked from the menu.
std::string chosen_network_;
// Hardware Id read from crossystem.
std::string hwid_;
// Region code read from VPD. Used to determine keyboard layout. Does not
// change based on selected locale.
std::string vpd_region_;
// Records the key press for each fd and key, where the index of the fd is the
// row and the key code the column. Resets to false after key is released.
// Only tracks the valid keys.
std::vector<std::vector<bool>> key_states_;
// The number of menu buttons on each screen corresponding to the enum
// numbers, used to keep the index in bounds. The drop down screen counts are
// updated later based on the locale and network lists.
std::unordered_map<ScreenType, int> menu_count_{
{ScreenType::kWelcomeScreen, 3},
{ScreenType::kNetworkDropDownScreen, 3},
{ScreenType::kExpandedNetworkDropDownScreen, 0},
{ScreenType::kPasswordScreen, 3},
{ScreenType::kLanguageDropDownScreen, 0},
{ScreenType::kWaitForConnection, 0},
{ScreenType::kStartDownload, 0},
{ScreenType::kDownloadError, 2},
{ScreenType::kNetworkError, 2},
{ScreenType::kPasswordError, 2},
{ScreenType::kConnectionError, 2}};
ScreenType current_screen_{ScreenType::kWelcomeScreen};
// Previous screen only used when changing the language so you know what
// screen to return to after selection.
ScreenType previous_screen_{ScreenType::kWelcomeScreen};
// The `index_` shows which button is highlighted in the `current_screen_`,
// uses menu_count of current screen to stay in bounds.
int index_{1};
// Determines whether we want to display the update engine state changes to
// the UI. Only necessary after user has entered their password and connected
// to the network.
bool display_update_engine_state_{false};
// Used to keep track of the last seen Update Engine stage to prevent
// unnecessary screen changes.
update_engine::Operation previous_update_state_{
update_engine::Operation::IDLE};
};
} // namespace screens
#endif // MINIOS_SCREENS_H_