Merge "recovery_ui:Add support for multiple connectors switch"
diff --git a/etc/init.rc b/etc/init.rc
index e4afecf..03df27b 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -102,7 +102,7 @@
 on fs && property:sys.usb.configfs=1
     mount configfs none /config
     mkdir /config/usb_gadget/g1 0770 shell shell
-    write /config/usb_gadget/g1/idVendor 0x18D1
+    write /config/usb_gadget/g1/idVendor 0x${ro.recovery.usb.vid}
     mkdir /config/usb_gadget/g1/strings/0x409 0770
     write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
     write /config/usb_gadget/g1/strings/0x409/manufacturer ${ro.product.manufacturer}
@@ -114,7 +114,7 @@
 
 on fs && property:sys.usb.configfs=0
     write /sys/class/android_usb/android0/f_ffs/aliases adb,fastboot
-    write /sys/class/android_usb/android0/idVendor 18D1
+    write /sys/class/android_usb/android0/idVendor ${ro.recovery.usb.vid}
     write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer}
     write /sys/class/android_usb/android0/iProduct ${ro.product.model}
     write /sys/class/android_usb/android0/iSerial ${ro.serialno}
@@ -139,19 +139,19 @@
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=adb && property:sys.usb.configfs=0
-    write /sys/class/android_usb/android0/idProduct D001
+    write /sys/class/android_usb/android0/idProduct ${ro.recovery.usb.adb.pid}
     write /sys/class/android_usb/android0/functions adb
     write /sys/class/android_usb/android0/enable 1
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=sideload && property:sys.usb.configfs=0
-    write /sys/class/android_usb/android0/idProduct D001
+    write /sys/class/android_usb/android0/idProduct ${ro.recovery.usb.adb.pid}
     write /sys/class/android_usb/android0/functions adb
     write /sys/class/android_usb/android0/enable 1
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=fastboot && property:sys.usb.configfs=0
-    write /sys/class/android_usb/android0/idProduct 4EE0
+    write /sys/class/android_usb/android0/idProduct ${ro.recovery.usb.fastboot.pid}
     write /sys/class/android_usb/android0/functions fastboot
     write /sys/class/android_usb/android0/enable 1
     setprop sys.usb.state ${sys.usb.config}
@@ -166,21 +166,21 @@
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=sideload && property:sys.usb.ffs.ready=1 && property:sys.usb.configfs=1
-    write /config/usb_gadget/g1/idProduct 0xD001
+    write /config/usb_gadget/g1/idProduct 0x${ro.recovery.usb.adb.pid}
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "adb"
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=adb && property:sys.usb.ffs.ready=1 && property:sys.usb.configfs=1
-    write /config/usb_gadget/g1/idProduct 0xD001
+    write /config/usb_gadget/g1/idProduct 0x${ro.recovery.usb.adb.pid}
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "adb"
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=fastboot && property:sys.usb.ffs.ready=1 && property:sys.usb.configfs=1
-    write /config/usb_gadget/g1/idProduct 0x4EE0
+    write /config/usb_gadget/g1/idProduct 0x${ro.recovery.usb.fastboot.pid}
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "fastboot"
     symlink /config/usb_gadget/g1/functions/ffs.fastboot /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index 597f2ce..41a3661 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -36,7 +36,6 @@
 static int overscan_offset_y = 0;
 
 static uint32_t gr_current = ~0;
-static constexpr uint32_t alpha_mask = 0xff000000;
 
 // gr_draw is owned by backends.
 static GRSurface* gr_draw = nullptr;
@@ -79,7 +78,7 @@
 }
 
 // Blends gr_current onto pix value, assumes alpha as most significant byte.
-static inline uint32_t pixel_blend(uint8_t alpha, uint32_t pix) {
+static inline uint32_t pixel_blend_argb(uint8_t alpha, uint32_t pix) {
   if (alpha == 255) return gr_current;
   if (alpha == 0) return pix;
   uint32_t pix_r = pix & 0xff;
@@ -96,6 +95,48 @@
   return (out_r & 0xff) | (out_g & 0xff00) | (out_b & 0xff0000) | (gr_current & 0xff000000);
 }
 
+static inline uint32_t pixel_blend_rgba(uint8_t alpha, uint32_t pix) {
+  if (alpha == 255) return gr_current;
+  if (alpha == 0) return pix;
+  uint32_t pix_r = pix & 0xff00;
+  uint32_t pix_g = pix & 0xff0000;
+  uint32_t pix_b = pix & 0xff000000;
+  uint32_t cur_r = gr_current & 0xff00;
+  uint32_t cur_g = gr_current & 0xff0000;
+  uint32_t cur_b = gr_current & 0xff000000;
+
+  uint32_t out_r = (pix_r * (255 - alpha) + cur_r * alpha) / 255;
+  uint32_t out_g = (pix_g * (255 - alpha) + cur_g * alpha) / 255;
+  uint32_t out_b = (pix_b * (255 - alpha) + cur_b * alpha) / 255;
+
+  return (gr_current & 0xff) | (out_r & 0xff00) | (out_g & 0xff0000) | (out_b & 0xff000000);
+}
+
+static inline uint32_t pixel_blend(uint8_t alpha, uint32_t pix) {
+  if (pixel_format == PixelFormat::RGBA) {
+    return pixel_blend_rgba(alpha, pix);
+  }
+  return pixel_blend_argb(alpha, pix);
+}
+
+static inline uint32_t get_alphamask() {
+  if (pixel_format == PixelFormat::RGBA) {
+    return 0x000000ff;
+  }
+  return 0xff000000;
+}
+
+static inline uint8_t get_alpha_shift() {
+  if (pixel_format == PixelFormat::RGBA) {
+    return 0;
+  }
+  return 24;
+}
+
+static inline uint8_t get_alpha(uint32_t pix) {
+  return static_cast<uint8_t>((pix & (gr_current & get_alphamask())) >> get_alpha_shift());
+}
+
 // Increments pixel pointer right, with current rotation.
 static void incr_x(uint32_t** p, int row_pixels) {
   if (rotation == GRRotation::LEFT) {
@@ -143,7 +184,7 @@
 
 static void TextBlend(const uint8_t* src_p, int src_row_bytes, uint32_t* dst_p, int dst_row_pixels,
                       int width, int height) {
-  uint8_t alpha_current = static_cast<uint8_t>((alpha_mask & gr_current) >> 24);
+  uint8_t alpha_current = get_alpha(gr_current);
   for (int j = 0; j < height; ++j) {
     const uint8_t* sx = src_p;
     uint32_t* px = dst_p;
@@ -158,7 +199,7 @@
 }
 
 void gr_text(const GRFont* font, int x, int y, const char* s, bool bold) {
-  if (!font || !font->texture || (gr_current & alpha_mask) == 0) return;
+  if (!font || !font->texture || (gr_current & get_alphamask()) == 0) return;
 
   if (font->texture->pixel_bytes != 1) {
     printf("gr_text: font has wrong format\n");
@@ -213,6 +254,8 @@
   uint32_t r32 = r, g32 = g, b32 = b, a32 = a;
   if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) {
     gr_current = (a32 << 24) | (r32 << 16) | (g32 << 8) | b32;
+  } else if (pixel_format == PixelFormat::RGBA) {
+    gr_current = (b32 << 24) | (g32 << 16) | (r32 << 8) | a32;
   } else {
     gr_current = (a32 << 24) | (b32 << 16) | (g32 << 8) | r32;
   }
@@ -247,7 +290,7 @@
 
   int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
   uint32_t* p = PixelAt(gr_draw, x1, y1, row_pixels);
-  uint8_t alpha = static_cast<uint8_t>(((gr_current & alpha_mask) >> 24));
+  uint8_t alpha = get_alpha(gr_current);
   if (alpha > 0) {
     for (int y = y1; y < y2; ++y) {
       uint32_t* px = p;
@@ -369,6 +412,8 @@
     pixel_format = PixelFormat::ARGB;
   } else if (format == "BGRA_8888") {
     pixel_format = PixelFormat::BGRA;
+  } else if (format == "RGBA_8888") {
+    pixel_format = PixelFormat::RGBA;
   } else {
     pixel_format = PixelFormat::UNKNOWN;
   }
@@ -457,3 +502,7 @@
 void gr_rotate(GRRotation rot) {
   rotation = rot;
 }
+
+bool gr_has_multiple_connectors() {
+  return gr_backend->HasMultipleConnectors();
+}
diff --git a/minui/graphics.h b/minui/graphics.h
index 5408c93..ff063ae 100644
--- a/minui/graphics.h
+++ b/minui/graphics.h
@@ -40,8 +40,11 @@
   // Blank (or unblank) the specific screen.
   virtual void Blank(bool blank, DrmConnector index) = 0;
 
+  // Return true if the device supports multiple connectors.
+  virtual bool HasMultipleConnectors() = 0;
+
   // Device cleanup when drawing is done.
-  virtual ~MinuiBackend() {};
+  virtual ~MinuiBackend() = default;
 };
 
 #endif  // _GRAPHICS_H_
diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp
index c557022..6c3a5bd 100644
--- a/minui/graphics_drm.cpp
+++ b/minui/graphics_drm.cpp
@@ -200,6 +200,10 @@
   }
 }
 
+bool MinuiBackendDrm::HasMultipleConnectors() {
+  return (drm[DRM_SEC].GRSurfaceDrms[0] && drm[DRM_SEC].GRSurfaceDrms[1]);
+}
+
 static drmModeCrtc* find_crtc_for_connector(int fd, drmModeRes* resources,
                                             drmModeConnector* connector) {
   // Find the encoder. If we already have one, just use it.
diff --git a/minui/graphics_drm.h b/minui/graphics_drm.h
index fe3beaf..a8c9886 100644
--- a/minui/graphics_drm.h
+++ b/minui/graphics_drm.h
@@ -60,6 +60,7 @@
   GRSurface* Flip() override;
   void Blank(bool) override;
   void Blank(bool blank, DrmConnector index) override;
+  bool HasMultipleConnectors() override;
 
  private:
   void DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc);
diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp
index 1cb0c0a..4a7d325 100644
--- a/minui/graphics_fbdev.cpp
+++ b/minui/graphics_fbdev.cpp
@@ -47,6 +47,11 @@
   fprintf(stderr, "Unsupported multiple connectors, blank = %d, index = %d\n", blank, index);
 }
 
+bool MinuiBackendFbdev::HasMultipleConnectors() {
+  fprintf(stderr, "Unsupported multiple connectors\n");
+  return false;
+}
+
 void MinuiBackendFbdev::SetDisplayedFramebuffer(size_t n) {
   if (n > 1 || !double_buffered) return;
 
diff --git a/minui/graphics_fbdev.h b/minui/graphics_fbdev.h
index 7e193c4..c772428 100644
--- a/minui/graphics_fbdev.h
+++ b/minui/graphics_fbdev.h
@@ -57,6 +57,7 @@
   GRSurface* Flip() override;
   void Blank(bool) override;
   void Blank(bool blank, DrmConnector index) override;
+  bool HasMultipleConnectors() override;
 
  private:
   void SetDisplayedFramebuffer(size_t n);
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index a2f62f0..2353ed3 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -102,6 +102,7 @@
   RGBX = 2,
   BGRA = 3,
   ARGB = 4,
+  RGBA = 5, // LSB Alpha
 };
 
 enum class GraphicsBackend : int {
@@ -128,6 +129,7 @@
 void gr_flip();
 void gr_fb_blank(bool blank);
 void gr_fb_blank(bool blank, int index);
+bool gr_has_multiple_connectors();
 
 // Clears entire surface to current color.
 void gr_clear();
diff --git a/minui/resources.cpp b/minui/resources.cpp
index d7b9277..1521c8f 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -153,32 +153,57 @@
                                int width) {
   const uint8_t* ip = input_row;
   uint8_t* op = output_row;
+  PixelFormat pixel_format = gr_pixel_format();
 
   switch (channels) {
     case 1:
       // expand gray level to RGBX
       for (int x = 0; x < width; ++x) {
-        *op++ = *ip;
-        *op++ = *ip;
-        *op++ = *ip;
-        *op++ = 0xff;
+        if (pixel_format == PixelFormat::RGBA) {
+          *op++ = 0xff;
+          *op++ = *ip;
+          *op++ = *ip;
+          *op++ = *ip;
+        } else {
+          *op++ = *ip;
+          *op++ = *ip;
+          *op++ = *ip;
+          *op++ = 0xff;
+        }
         ip++;
       }
       break;
 
     case 3:
-      // expand RGBA to RGBX
       for (int x = 0; x < width; ++x) {
-        *op++ = *ip++;
-        *op++ = *ip++;
-        *op++ = *ip++;
-        *op++ = 0xff;
+        // expand RGBA to RGBX
+        if (pixel_format == PixelFormat::RGBA) {
+            *op++ = 0xff;
+            *op++ = *ip++;
+            *op++ = *ip++;
+            *op++ = *ip++;
+        } else {
+            *op++ = *ip++;
+            *op++ = *ip++;
+            *op++ = *ip++;
+            *op++ = 0xff;
+        }
       }
       break;
 
     case 4:
-      // copy RGBA to RGBX
-      memcpy(output_row, input_row, width * 4);
+      if (pixel_format == PixelFormat::RGBA) {
+        for (int x = 0; x < width; ++x) {
+            *op++ = *(ip + 3);
+            *op++ = *ip++;
+            *op++ = *ip++;
+            *op++ = *ip++;
+            ip++;
+        }
+      } else {
+        // copy RGBA to RGBX
+        memcpy(output_row, input_row, width * 4);
+      }
       break;
   }
 }
@@ -201,6 +226,8 @@
   PixelFormat pixel_format = gr_pixel_format();
   if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) {
     png_set_bgr(png_ptr);
+  } else if (pixel_format == PixelFormat::RGBA) {
+    png_set_swap_alpha(png_ptr);
   }
 
   for (png_uint_32 y = 0; y < height; ++y) {
@@ -273,6 +300,8 @@
 
   if (gr_pixel_format() == PixelFormat::ARGB || gr_pixel_format() == PixelFormat::BGRA) {
     png_set_bgr(png_ptr);
+  } else if (gr_pixel_format() == PixelFormat::RGBA) {
+    png_set_swap_alpha(png_ptr);
   }
 
   for (png_uint_32 y = 0; y < height; ++y) {
@@ -316,11 +345,6 @@
     return -8;
   }
 
-  PixelFormat pixel_format = gr_pixel_format();
-  if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) {
-    png_set_bgr(png_ptr);
-  }
-
   for (png_uint_32 y = 0; y < height; ++y) {
     uint8_t* p_row = surface->data() + y * surface->row_bytes;
     png_read_row(png_ptr, p_row, nullptr);
diff --git a/tests/Android.bp b/tests/Android.bp
index 9ad3d3b..0708e85 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -216,6 +216,7 @@
     ],
 
     test_suites: ["general-tests"],
+    test_config: "RecoveryHostTest.xml",
 
     data: ["testdata/*"],
 
diff --git a/tests/AndroidTest.xml b/tests/RecoveryHostTest.xml
similarity index 100%
rename from tests/AndroidTest.xml
rename to tests/RecoveryHostTest.xml