1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <cstdint> 20 #include <functional> 21 #include <memory> 22 #include <string> 23 #include <tuple> 24 #include <vector> 25 26 #include <freetype/ftglyph.h> // $(croot)/external/freetype 27 #include <teeui/utils.h> // $(croot)/system/teeui/libteeui/.../include 28 29 #include "common/libs/confui/confui.h" 30 #include "host/libs/confui/layouts/layout.h" 31 #include "host/libs/confui/server_common.h" 32 #include "host/libs/screen_connector/screen_connector_common.h" 33 34 namespace cuttlefish { 35 namespace confui { 36 class TeeUiFrameWrapper { 37 public: TeeUiFrameWrapper(const int w,const int h,const teeui::Color color)38 TeeUiFrameWrapper(const int w, const int h, const teeui::Color color) 39 : w_(w), h_(h), teeui_frame_(ScreenSizeInBytes(w, h), color) {} 40 TeeUiFrameWrapper() = delete; data()41 auto data() { return teeui_frame_.data(); } Width()42 int Width() const { return w_; } Height()43 int Height() const { return h_; } IsEmpty()44 bool IsEmpty() const { return teeui_frame_.empty(); } Size()45 auto Size() const { return teeui_frame_.size(); } 46 auto& operator[](const int idx) { return teeui_frame_[idx]; } ScreenStrideBytes()47 std::uint32_t ScreenStrideBytes() const { 48 return ScreenConnectorInfo::ComputeScreenStrideBytes(w_); 49 } 50 51 private: ScreenSizeInBytes(const int w,const int h)52 static std::uint32_t ScreenSizeInBytes(const int w, const int h) { 53 return ScreenConnectorInfo::ComputeScreenSizeInBytes(w, h); 54 } 55 56 int w_; 57 int h_; 58 TeeUiFrame teeui_frame_; 59 }; 60 61 /** 62 * create a raw frame for confirmation UI dialog 63 * 64 * Many rendering code borrowed from the following source 65 * https://android.googlesource.com/trusty/app/confirmationui/+/0429cc7/src 66 */ 67 class ConfUiRenderer { 68 public: 69 using LabelConfMsg = teeui::LabelBody; 70 71 static std::unique_ptr<ConfUiRenderer> GenerateRenderer( 72 const std::uint32_t display, const std::string& confirmation_msg, 73 const std::string& locale, const bool inverted, const bool magnified); 74 75 /** 76 * this does not repaint from the scratch all the time 77 * 78 * It does repaint its frame buffer only when w/h of 79 * current display has changed 80 */ 81 std::shared_ptr<TeeUiFrameWrapper> RenderRawFrame(); 82 IsFrameReady()83 bool IsFrameReady() const { return raw_frame_ && !raw_frame_->IsEmpty(); } 84 IsInConfirm(const std::uint32_t x,const std::uint32_t y)85 bool IsInConfirm(const std::uint32_t x, const std::uint32_t y) { 86 return IsInside<teeui::LabelOK>(x, y); 87 } IsInCancel(const std::uint32_t x,const std::uint32_t y)88 bool IsInCancel(const std::uint32_t x, const std::uint32_t y) { 89 return IsInside<teeui::LabelCancel>(x, y); 90 } 91 92 private: IsSetUpSuccessful()93 bool IsSetUpSuccessful() const { return is_setup_well_; } 94 ConfUiRenderer(const std::uint32_t display, 95 const std::string& confirmation_msg, const std::string& locale, 96 const bool inverted, const bool magnified); 97 98 struct Boundary { // inclusive but.. LayoutElement's size is float 99 std::uint32_t x, y, w, h; // (x, y) is the top left 100 }; 101 102 template <typename LayoutElement> GetBoundary(LayoutElement && e)103 Boundary GetBoundary(LayoutElement&& e) const { 104 auto box = e.bounds_; 105 Boundary b; 106 // (x,y) is left top. so floor() makes sense 107 // w, h are witdh and height in float. perhaps ceiling makes more 108 // sense 109 b.x = static_cast<std::uint32_t>(box.x().floor().count()); 110 b.y = static_cast<std::uint32_t>(box.y().floor().count()); 111 b.w = static_cast<std::uint32_t>(box.w().ceil().count()); 112 b.h = static_cast<std::uint32_t>(box.h().ceil().count()); 113 return b; 114 } 115 116 template <typename Element> IsInside(const std::uint32_t x,const std::uint32_t y)117 bool IsInside(const std::uint32_t x, const std::uint32_t y) const { 118 auto box = GetBoundary(std::get<Element>(layout_)); 119 if (x >= box.x && x <= box.x + box.w && y >= box.y && y <= box.y + box.h) { 120 return true; 121 } 122 return false; 123 } 124 // essentially, to repaint from the scratch, so returns new frame 125 // when successful. Or, nullopt 126 std::unique_ptr<TeeUiFrameWrapper> RepaintRawFrame(const int w, const int h); 127 128 bool InitLayout(const std::string& lang_id); 129 teeui::Error UpdateTranslations(); 130 teeui::Error UpdateLocale(); 131 void SetDeviceContext(const unsigned long long w, const unsigned long long h, 132 bool is_inverted, bool is_magnified); 133 134 // a callback function to be effectively sent to TeeUI library 135 teeui::Error UpdatePixels(TeeUiFrameWrapper& buffer, std::uint32_t x, 136 std::uint32_t y, teeui::Color color); 137 138 // second param is for type deduction 139 template <typename... Elements> drawElements(std::tuple<Elements...> & layout,const teeui::PixelDrawer & drawPixel)140 static teeui::Error drawElements(std::tuple<Elements...>& layout, 141 const teeui::PixelDrawer& drawPixel) { 142 // Error::operator|| is overloaded, so we don't get short circuit 143 // evaluation. But we get the first error that occurs. We will still try and 144 // draw the remaining elements in the order they appear in the layout tuple. 145 return (std::get<Elements>(layout).draw(drawPixel) || ...); 146 } 147 void UpdateColorScheme(const bool is_inverted); 148 template <typename Label> SetText(const std::string & text)149 auto SetText(const std::string& text) { 150 return std::get<Label>(layout_).setText( 151 {text.c_str(), text.c_str() + text.size()}); 152 } 153 154 template <typename Label> 155 teeui::Error UpdateString(); 156 157 std::uint32_t display_num_; 158 teeui::layout_t<teeui::ConfUILayout> layout_; 159 std::string lang_id_; 160 std::string prompt_text_; // confirmation ui message 161 162 /** 163 * Potentially, the same frame could be requested multiple times. 164 * 165 * While another thread/caller is using this frame, the frame should 166 * be kept here, too, to be returned upon future requests. 167 * 168 */ 169 std::shared_ptr<TeeUiFrameWrapper> raw_frame_; 170 std::uint32_t current_height_; 171 std::uint32_t current_width_; 172 teeui::Color color_bg_; 173 teeui::Color color_text_; 174 teeui::Color shield_color_; 175 bool is_inverted_; 176 bool is_magnified_; 177 teeui::context<teeui::ConfUIParameters> ctx_; 178 bool is_setup_well_; 179 180 static constexpr const teeui::Color kColorBackground = 0xffffffff; 181 static constexpr const teeui::Color kColorBackgroundInv = 0xff212121; 182 static constexpr const teeui::Color kColorDisabled = 0xffbdbdbd; 183 static constexpr const teeui::Color kColorDisabledInv = 0xff424242; 184 static constexpr const teeui::Color kColorEnabled = 0xff212121; 185 static constexpr const teeui::Color kColorEnabledInv = 0xffdedede; 186 static constexpr const teeui::Color kColorShield = 0xff778500; 187 static constexpr const teeui::Color kColorShieldInv = 0xffc4cb80; 188 static constexpr const teeui::Color kColorText = 0xff212121; 189 static constexpr const teeui::Color kColorTextInv = 0xffdedede; 190 }; 191 } // end of namespace confui 192 } // end of namespace cuttlefish 193