• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.h"
33 
34 namespace cuttlefish {
35 namespace confui {
36 
37 /**
38  * create a raw frame for confirmation UI dialog
39  */
40 class ConfUiRenderer {
41  public:
42   using LabelConfMsg = teeui::LabelBody;
43 
44   ConfUiRenderer(const std::uint32_t display);
45 
46   /**
47    * this does not repaint from the scratch all the time
48    *
49    * Unless repainting the whole thing is needed, it remove the message
50    * label, and re-draw there. There seems yet no fancy way of doing this.
51    * Thus, it repaint the background color on the top of the label, and
52    * draw the label on the new background
53    *
54    * As HostRenderer is intended to be shared across sessions, HostRender
55    * owns the buffer, and returns reference to the buffer. Note that no
56    * 2 or more sessions are concurrently executed. Only 1 or 0 is active
57    * at the given moment.
58    */
59   std::tuple<TeeUiFrame&, bool> RenderRawFrame(
60       const std::string& confirmation_msg, const std::string& lang_id = "en");
61 
IsFrameReady()62   bool IsFrameReady() const { return !raw_frame_.empty(); }
63 
64  private:
65   struct Boundary {            // inclusive but.. LayoutElement's size is float
66     std::uint32_t x, y, w, h;  // (x, y) is the top left
67   };
68 
69   template <typename LayoutElement>
GetBoundary(LayoutElement && e)70   Boundary GetBoundary(LayoutElement&& e) {
71     auto box = e.bounds_;
72     Boundary b;
73     // (x,y) is left top. so floor() makes sense
74     // w, h are witdh and height in float. perhaps ceiling makes more
75     // sense
76     b.x = static_cast<std::uint32_t>(box.x().floor().count());
77     b.y = static_cast<std::uint32_t>(box.y().floor().count());
78     b.w = static_cast<std::uint32_t>(box.w().ceil().count());
79     b.h = static_cast<std::uint32_t>(box.h().ceil().count());
80     return b;
81   }
82 
83   // essentially, to repaint from the scratch, so returns new frame
84   // when successful. Or, nullopt
85   std::optional<TeeUiFrame> RepaintRawFrame(const std::string& confirmation_msg,
86                                             const std::string& lang_id = "en");
87 
88   bool InitLayout(const std::string& lang_id);
89   teeui::Error UpdateTranslations();
90   /**
91    * could be confusing. update prompt_, and update the text_ in the Label
92    * object, the GUI components. This does not render immediately. And..
93    * to render it, we must clean up the existing dirty pixels, which
94    * this method does not do.
95    */
96   void SetConfUiMessage(const std::string& s);
97   teeui::Error SetLangId(const std::string& lang_id);
98   teeui::context<teeui::ConUIParameters> GetDeviceContext();
99 
100   // effectively, will be send to teeui as a callback function
101   teeui::Error UpdatePixels(TeeUiFrame& buffer, std::uint32_t x,
102                             std::uint32_t y, teeui::Color color);
103 
104   // from Trusty
105   // second param is for type deduction
106   template <typename... Elements>
drawElements(std::tuple<Elements...> & layout,const teeui::PixelDrawer & drawPixel)107   static teeui::Error drawElements(std::tuple<Elements...>& layout,
108                                    const teeui::PixelDrawer& drawPixel) {
109     // Error::operator|| is overloaded, so we don't get short circuit
110     // evaluation. But we get the first error that occurs. We will still try and
111     // draw the remaining elements in the order they appear in the layout tuple.
112     return (std::get<Elements>(layout).draw(drawPixel) || ...);
113   }
114 
115   // repaint the confirmation UI label only
116   teeui::Error RenderConfirmationMsgOnly(const std::string& confirmation_msg);
117 
118   // from Trusty
119   template <typename Context>
UpdateColorScheme(Context * ctx)120   void UpdateColorScheme(Context* ctx) {
121     using namespace teeui;
122     color_text_ = is_inverted_ ? kColorDisabledInv : kColorDisabled;
123     shield_color_ = is_inverted_ ? kColorShieldInv : kColorShield;
124     color_bg_ = is_inverted_ ? kColorBackgroundInv : kColorBackground;
125 
126     ctx->template setParam<ShieldColor>(shield_color_);
127     ctx->template setParam<ColorText>(color_text_);
128     ctx->template setParam<ColorBG>(color_bg_);
129     return;
130   }
131 
132   template <typename Label>
SetText(const std::string & text)133   auto SetText(const std::string& text) {
134     return std::get<Label>(layout_).setText(
135         {text.c_str(), text.c_str() + text.size()});
136   }
137 
138   /**
139    * source:
140    * https://android.googlesource.com/trusty/app/confirmationui/+/0429cc7/src/trusty_confirmation_ui.cpp#49
141    */
142   template <typename Label>
UpdateString()143   teeui::Error UpdateString() {
144     using namespace teeui;
145     const char* str;
146     auto& label = std::get<Label>(layout_);
147     str = localization::lookup(TranslationId(label.textId()));
148     if (str == nullptr) {
149       ConfUiLog(ERROR) << "Given translation_id" << label.textId()
150                        << "not found";
151       return Error::Localization;
152     }
153     label.setText({str, str + strlen(str)});
154     return Error::OK;
155   }
156 
157   const int display_num_;
158   teeui::layout_t<teeui::ConfUILayout> layout_;
159   std::string lang_id_;
160   std::string prompt_;  // confirmation ui message
161   TeeUiFrame raw_frame_;
162   std::uint32_t current_height_;
163   std::uint32_t current_width_;
164   teeui::Color color_bg_;
165   teeui::Color color_text_;
166   teeui::Color shield_color_;
167   bool is_inverted_;
168   teeui::context<teeui::ConUIParameters> ctx_;
169 
170   static constexpr const teeui::Color kColorEnabled = 0xff212121;
171   static constexpr const teeui::Color kColorDisabled = 0xffbdbdbd;
172   static constexpr const teeui::Color kColorEnabledInv = 0xffdedede;
173   static constexpr const teeui::Color kColorDisabledInv = 0xff424242;
174   static constexpr const teeui::Color kColorBackground = 0xffffffff;
175   static constexpr const teeui::Color kColorBackgroundInv = 0xff212121;
176   static constexpr const teeui::Color kColorShieldInv = 0xffc4cb80;
177   static constexpr const teeui::Color kColorShield = 0xff778500;
178 };
179 }  // end of namespace confui
180 }  // end of namespace cuttlefish
181