@@ -58,7 +58,14 @@ pub struct AndroidFrame {
5858
5959pub struct AndroidGrpcFrameStream {
6060 inner : tonic:: Streaming < grpc:: Image > ,
61- target_size : Option < ( u32 , u32 ) > ,
61+ target : Option < AndroidFrameTarget > ,
62+ }
63+
64+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
65+ struct AndroidFrameTarget {
66+ width : u32 ,
67+ height : u32 ,
68+ rotation_quarter_turns : u16 ,
6269}
6370
6471pub fn is_android_id ( id : & str ) -> bool {
@@ -517,21 +524,20 @@ impl AndroidBridge {
517524 display : 0 ,
518525 transport : None ,
519526 } ;
520- let target_size = self
527+ let target = self
521528 . resolve_serial ( & avd_name)
522529 . ok ( )
523- . and_then ( |serial| self . screen_size_for_serial ( & serial) . ok ( ) )
524- . map ( |( width, height) | {
525- (
526- width. round ( ) . max ( 1.0 ) as u32 ,
527- height. round ( ) . max ( 1.0 ) as u32 ,
528- )
530+ . and_then ( |serial| self . display_metrics_for_serial ( & serial) . ok ( ) )
531+ . map ( |metrics| AndroidFrameTarget {
532+ width : metrics. width . round ( ) . max ( 1.0 ) as u32 ,
533+ height : metrics. height . round ( ) . max ( 1.0 ) as u32 ,
534+ rotation_quarter_turns : metrics. rotation_quarter_turns ,
529535 } ) ;
530- if let ( Some ( max_edge) , Some ( ( width , height ) ) ) = ( max_edge, target_size ) {
536+ if let ( Some ( max_edge) , Some ( target ) ) = ( max_edge, target ) {
531537 let max_edge = max_edge. clamp ( 240 , 2400 ) ;
532- let largest = width. max ( height) ;
538+ let largest = target . width . max ( target . height ) ;
533539 if largest > max_edge {
534- if width >= height {
540+ if target . width >= target . height {
535541 format. width = max_edge;
536542 } else {
537543 format. height = max_edge;
@@ -573,7 +579,7 @@ impl AndroidBridge {
573579 } ) ?;
574580 Ok ( AndroidGrpcFrameStream {
575581 inner : response. into_inner ( ) ,
576- target_size ,
582+ target ,
577583 } )
578584 }
579585
@@ -972,7 +978,7 @@ impl AndroidGrpcFrameStream {
972978 . unwrap_or ( grpc:: image_format:: ImgFormat :: Rgba8888 ) ,
973979 ) ?;
974980 let ( width, height, rgba) =
975- normalize_android_frame_orientation ( width, height, rgba, self . target_size ) ;
981+ normalize_android_frame_orientation ( width, height, rgba, self . target ) ;
976982 Ok ( Some ( AndroidFrame {
977983 width,
978984 height,
@@ -985,21 +991,28 @@ impl AndroidGrpcFrameStream {
985991fn normalize_android_frame_orientation (
986992 width : u32 ,
987993 height : u32 ,
988- rgba : Vec < u8 > ,
989- target_size : Option < ( u32 , u32 ) > ,
994+ mut rgba : Vec < u8 > ,
995+ target : Option < AndroidFrameTarget > ,
990996) -> ( u32 , u32 , Vec < u8 > ) {
991- let Some ( ( target_width , target_height ) ) = target_size else {
997+ let Some ( target ) = target else {
992998 return ( width, height, rgba) ;
993999 } ;
994- if width == 0
995- || height == 0
996- || target_width == 0
997- || target_height == 0
998- || ( width > height) == ( target_width > target_height)
999- {
1000+ if width == 0 || height == 0 || target. width == 0 || target. height == 0 {
10001001 return ( width, height, rgba) ;
10011002 }
1002- ( height, width, rotate_rgba_clockwise ( & rgba, width, height) )
1003+
1004+ let ( width, height) = if ( width > height) == ( target. width > target. height ) {
1005+ ( width, height)
1006+ } else {
1007+ rgba = rotate_rgba_clockwise ( & rgba, width, height) ;
1008+ ( height, width)
1009+ } ;
1010+
1011+ if target. rotation_quarter_turns >= 2 {
1012+ rotate_rgba_180_in_place ( & mut rgba, width, height) ;
1013+ }
1014+
1015+ ( width, height, rgba)
10031016}
10041017
10051018fn rotate_rgba_clockwise ( rgba : & [ u8 ] , width : u32 , height : u32 ) -> Vec < u8 > {
@@ -1018,6 +1031,16 @@ fn rotate_rgba_clockwise(rgba: &[u8], width: u32, height: u32) -> Vec<u8> {
10181031 out
10191032}
10201033
1034+ fn rotate_rgba_180_in_place ( rgba : & mut [ u8 ] , width : u32 , height : u32 ) {
1035+ let pixel_count = width as usize * height as usize ;
1036+ for pixel in 0 ..( pixel_count / 2 ) {
1037+ let opposite = pixel_count - 1 - pixel;
1038+ for channel in 0 ..4 {
1039+ rgba. swap ( pixel * 4 + channel, opposite * 4 + channel) ;
1040+ }
1041+ }
1042+ }
1043+
10211044fn run_command_text < const N : usize > ( program : PathBuf , args : [ & str ; N ] ) -> Result < String , AppError > {
10221045 let output = run_command ( program, args) ?;
10231046 String :: from_utf8 ( output)
@@ -1685,8 +1708,16 @@ mod tests {
16851708 4 , 0 , 0 , 255 , 5 , 0 , 0 , 255 , 6 , 0 , 0 , 255 ,
16861709 ] ;
16871710
1688- let ( width, height, rotated) =
1689- normalize_android_frame_orientation ( 3 , 2 , rgba, Some ( ( 2 , 3 ) ) ) ;
1711+ let ( width, height, rotated) = normalize_android_frame_orientation (
1712+ 3 ,
1713+ 2 ,
1714+ rgba,
1715+ Some ( AndroidFrameTarget {
1716+ width : 2 ,
1717+ height : 3 ,
1718+ rotation_quarter_turns : 0 ,
1719+ } ) ,
1720+ ) ;
16901721
16911722 assert_eq ! ( ( width, height) , ( 2 , 3 ) ) ;
16921723 assert_eq ! (
@@ -1703,12 +1734,48 @@ mod tests {
17031734 fn android_frame_orientation_keeps_matching_aspect ( ) {
17041735 let rgba = vec ! [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ;
17051736
1706- let ( width, height, out) =
1707- normalize_android_frame_orientation ( 1 , 2 , rgba. clone ( ) , Some ( ( 1080 , 2400 ) ) ) ;
1737+ let ( width, height, out) = normalize_android_frame_orientation (
1738+ 1 ,
1739+ 2 ,
1740+ rgba. clone ( ) ,
1741+ Some ( AndroidFrameTarget {
1742+ width : 1080 ,
1743+ height : 2400 ,
1744+ rotation_quarter_turns : 0 ,
1745+ } ) ,
1746+ ) ;
17081747
17091748 assert_eq ! ( ( width, height) , ( 1 , 2 ) ) ;
17101749 assert_eq ! ( out, rgba) ;
17111750 }
1751+
1752+ #[ test]
1753+ fn android_frame_orientation_rotates_reverse_orientations_180 ( ) {
1754+ let rgba = vec ! [
1755+ 1 , 0 , 0 , 255 , 2 , 0 , 0 , 255 , 3 , 0 , 0 , 255 , //
1756+ 4 , 0 , 0 , 255 , 5 , 0 , 0 , 255 , 6 , 0 , 0 , 255 ,
1757+ ] ;
1758+
1759+ let ( width, height, rotated) = normalize_android_frame_orientation (
1760+ 3 ,
1761+ 2 ,
1762+ rgba,
1763+ Some ( AndroidFrameTarget {
1764+ width : 3 ,
1765+ height : 2 ,
1766+ rotation_quarter_turns : 3 ,
1767+ } ) ,
1768+ ) ;
1769+
1770+ assert_eq ! ( ( width, height) , ( 3 , 2 ) ) ;
1771+ assert_eq ! (
1772+ rotated,
1773+ vec![
1774+ 6 , 0 , 0 , 255 , 5 , 0 , 0 , 255 , 4 , 0 , 0 , 255 , //
1775+ 3 , 0 , 0 , 255 , 2 , 0 , 0 , 255 , 1 , 0 , 0 , 255 ,
1776+ ]
1777+ ) ;
1778+ }
17121779}
17131780
17141781mod grpc {
0 commit comments