Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2018 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 package android.server.wm;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertNotEquals;
     22 import static org.junit.Assert.assertNotSame;
     23 import static org.junit.Assert.assertNull;
     24 import static org.junit.Assert.assertSame;
     25 import static org.junit.Assert.assertTrue;
     26 
     27 import android.graphics.Insets;
     28 import android.graphics.Rect;
     29 import android.platform.test.annotations.Presubmit;
     30 import android.view.DisplayCutout;
     31 import android.view.WindowInsets;
     32 
     33 import androidx.test.filters.SmallTest;
     34 import androidx.test.runner.AndroidJUnit4;
     35 
     36 import org.junit.Test;
     37 import org.junit.runner.RunWith;
     38 
     39 import java.util.Collections;
     40 
     41 /**
     42  * Test {@link WindowInsets}.
     43  */
     44 @SmallTest
     45 @RunWith(AndroidJUnit4.class)
     46 @Presubmit
     47 public class WindowInsetsTest {
     48 
     49     private static final DisplayCutout CUTOUT = new DisplayCutout(new Rect(0, 10, 0, 0),
     50             Collections.singletonList(new Rect(5, 0, 15, 10)));
     51     private static final DisplayCutout CUTOUT2 = new DisplayCutout(new Rect(0, 15, 0, 0),
     52             Collections.singletonList(new Rect(5, 0, 15, 15)));
     53     private static final int INSET_LEFT = 1;
     54     private static final int INSET_TOP = 2;
     55     private static final int INSET_RIGHT = 3;
     56     private static final int INSET_BOTTOM = 4;
     57 
     58     @Test
     59     public void testBuilder() {
     60         final WindowInsets insets = new WindowInsets.Builder()
     61                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
     62                 .setStableInsets(Insets.of(5, 6, 7, 8))
     63                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
     64                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
     65                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
     66                 .setDisplayCutout(CUTOUT)
     67                 .build();
     68 
     69         assertEquals(Insets.of(1, 2, 3, 4), insets.getSystemWindowInsets());
     70         assertEquals(Insets.of(5, 6, 7, 8), insets.getStableInsets());
     71         assertEquals(Insets.of(9, 10, 11, 12), insets.getSystemGestureInsets());
     72         assertEquals(Insets.of(13, 14, 15, 16), insets.getMandatorySystemGestureInsets());
     73         assertEquals(Insets.of(17, 18, 19, 20), insets.getTappableElementInsets());
     74         assertSame(CUTOUT, insets.getDisplayCutout());
     75     }
     76 
     77     @Test
     78     public void testBuilder_copy() {
     79         final WindowInsets insets = new WindowInsets.Builder()
     80                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
     81                 .setStableInsets(Insets.of(5, 6, 7, 8))
     82                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
     83                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
     84                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
     85                 .setDisplayCutout(CUTOUT)
     86                 .build();
     87         final WindowInsets copy = new WindowInsets.Builder(insets).build();
     88 
     89         assertEquals(insets, copy);
     90     }
     91 
     92     @Test
     93     public void testBuilder_consumed() {
     94         final WindowInsets insets = new WindowInsets.Builder()
     95                 .build();
     96 
     97         assertFalse(insets.hasSystemWindowInsets());
     98         assertFalse(insets.hasStableInsets());
     99         assertEquals(Insets.NONE, insets.getSystemGestureInsets());
    100         assertNull(insets.getDisplayCutout());
    101         assertTrue(insets.isConsumed());
    102     }
    103 
    104     @Test
    105     public void testBuilder_emptyCutout() {
    106         final WindowInsets insets = new WindowInsets.Builder()
    107                 .setDisplayCutout(null)
    108                 .build();
    109 
    110         assertFalse(insets.hasSystemWindowInsets());
    111         assertFalse(insets.hasStableInsets());
    112         assertEquals(Insets.NONE, insets.getSystemGestureInsets());
    113 
    114         assertNull(insets.getDisplayCutout());
    115         assertFalse(insets.isConsumed());
    116         assertTrue(insets.consumeDisplayCutout().isConsumed());
    117     }
    118 
    119     @Test
    120     public void testBuilder_producesImmutableWindowInsets() {
    121         final WindowInsets.Builder builder = new WindowInsets.Builder()
    122                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    123                 .setStableInsets(Insets.of(5, 6, 7, 8))
    124                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    125                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    126                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    127                 .setDisplayCutout(CUTOUT);
    128         final WindowInsets insets = builder.build();
    129 
    130         builder.setSystemWindowInsets(Insets.NONE);
    131         builder.setStableInsets(Insets.NONE);
    132         builder.setDisplayCutout(null);
    133         builder.setSystemGestureInsets(Insets.NONE);
    134         builder.setMandatorySystemGestureInsets(Insets.NONE);
    135         builder.setTappableElementInsets(Insets.NONE);
    136 
    137         assertEquals(Insets.of(1, 2, 3, 4), insets.getSystemWindowInsets());
    138         assertEquals(Insets.of(5, 6, 7, 8), insets.getStableInsets());
    139         assertSame(CUTOUT, insets.getDisplayCutout());
    140     }
    141 
    142     @Test
    143     public void testEquality() {
    144         final WindowInsets insets = new WindowInsets.Builder()
    145                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    146                 .setStableInsets(Insets.of(5, 6, 7, 8))
    147                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    148                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    149                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    150                 .setDisplayCutout(CUTOUT).build();
    151 
    152         final WindowInsets insets2 = new WindowInsets.Builder()
    153                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    154                 .setStableInsets(Insets.of(5, 6, 7, 8))
    155                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    156                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    157                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    158                 .setDisplayCutout(CUTOUT).build();
    159 
    160         assertNotSame("Test setup failed, insets and insets2 should not be identical",
    161                 insets, insets2);
    162 
    163         assertEquals(insets, insets2);
    164         assertEquals(insets.hashCode(), insets2.hashCode());
    165     }
    166 
    167     @Test
    168     public void testInEquality_consuming() {
    169         final WindowInsets insets = new WindowInsets.Builder()
    170                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    171                 .setStableInsets(Insets.of(5, 6, 7, 8))
    172                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    173                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    174                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    175                 .setDisplayCutout(CUTOUT).build();
    176 
    177         assertNotEquals(insets, insets.consumeSystemWindowInsets());
    178         assertNotEquals(insets, insets.consumeStableInsets());
    179         assertNotEquals(insets, insets.consumeDisplayCutout());
    180     }
    181 
    182     @Test
    183     public void testConsume_systemWindowInsets() {
    184         final WindowInsets insets = new WindowInsets.Builder()
    185                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    186                 .setStableInsets(Insets.of(5, 6, 7, 8))
    187                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    188                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    189                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    190                 .setDisplayCutout(CUTOUT).build();
    191 
    192         final WindowInsets consumed = insets.consumeSystemWindowInsets();
    193 
    194         assertEquals(Insets.NONE, consumed.getSystemWindowInsets());
    195         assertEquals(insets.getStableInsets(), consumed.getStableInsets());
    196         assertEquals(insets.getDisplayCutout(), consumed.getDisplayCutout());
    197         assertEquals(Insets.NONE, consumed.getSystemGestureInsets());
    198         assertEquals(Insets.NONE, consumed.getMandatorySystemGestureInsets());
    199         assertEquals(Insets.NONE, consumed.getTappableElementInsets());
    200     }
    201 
    202     @Test
    203     public void testConsume_stableInsets() {
    204         final WindowInsets insets = new WindowInsets.Builder()
    205                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    206                 .setStableInsets(Insets.of(5, 6, 7, 8))
    207                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    208                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    209                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    210                 .setDisplayCutout(CUTOUT).build();
    211 
    212         final WindowInsets consumed = insets.consumeStableInsets();
    213 
    214         assertEquals(insets.getSystemWindowInsets(), consumed.getSystemWindowInsets());
    215         assertEquals(Insets.NONE, consumed.getStableInsets());
    216         assertEquals(insets.getDisplayCutout(), consumed.getDisplayCutout());
    217         assertEquals(insets.getSystemGestureInsets(), consumed.getSystemGestureInsets());
    218         assertEquals(insets.getMandatorySystemGestureInsets(), consumed.getMandatorySystemGestureInsets());
    219         assertEquals(insets.getTappableElementInsets(), consumed.getTappableElementInsets());
    220     }
    221 
    222     @Test
    223     public void testConsume_displayCutout() {
    224         final WindowInsets insets = new WindowInsets.Builder()
    225                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    226                 .setStableInsets(Insets.of(5, 6, 7, 8))
    227                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    228                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    229                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    230                 .setDisplayCutout(CUTOUT).build();
    231 
    232         final WindowInsets consumed = insets.consumeDisplayCutout();
    233 
    234         assertEquals(insets.getSystemWindowInsets(), consumed.getSystemWindowInsets());
    235         assertEquals(insets.getStableInsets(), consumed.getStableInsets());
    236         assertNull(consumed.getDisplayCutout());
    237         assertEquals(insets.getSystemGestureInsets(), consumed.getSystemGestureInsets());
    238         assertEquals(insets.getMandatorySystemGestureInsets(), consumed.getMandatorySystemGestureInsets());
    239         assertEquals(insets.getTappableElementInsets(), consumed.getTappableElementInsets());
    240     }
    241 
    242     @Test
    243     public void testConsistency_individualSides() {
    244         final WindowInsets insets = new WindowInsets.Builder()
    245                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    246                 .setStableInsets(Insets.of(5, 6, 7, 8))
    247                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    248                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    249                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    250                 .setDisplayCutout(CUTOUT).build();
    251 
    252         assertEquals(insets.getSystemWindowInsets(), Insets.of(
    253                 insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
    254                 insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
    255         assertEquals(insets.getStableInsets(), Insets.of(
    256                 insets.getStableInsetLeft(), insets.getStableInsetTop(),
    257                 insets.getStableInsetRight(), insets.getStableInsetBottom()));
    258     }
    259 
    260     @Test
    261     @SuppressWarnings("deprecation")
    262     public void testReplacingConsumedSystemWindowInset_staysZeroAndConsumed() {
    263         final WindowInsets consumed = new WindowInsets.Builder().build();
    264         final WindowInsets replaced = consumed.replaceSystemWindowInsets(new Rect(1, 2, 3, 4));
    265 
    266         assertEquals(Insets.NONE, replaced.getSystemWindowInsets());
    267         assertTrue(replaced.isConsumed());
    268     }
    269 
    270     @Test
    271     @SuppressWarnings("deprecation")
    272     public void testReplacingSystemWindowInsets_works() {
    273         final WindowInsets replaced = new WindowInsets.Builder()
    274                 .setSystemWindowInsets(Insets.of(100, 200, 300, 400))
    275                 .setStableInsets(Insets.of(5, 6, 7, 8))
    276                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    277                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    278                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    279                 .setDisplayCutout(CUTOUT).build()
    280                 .replaceSystemWindowInsets(new Rect(1, 2, 3, 4));
    281         final WindowInsets expected = new WindowInsets.Builder()
    282                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    283                 .setStableInsets(Insets.of(5, 6, 7, 8))
    284                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    285                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    286                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    287                 .setDisplayCutout(CUTOUT).build();
    288 
    289         assertEquals(expected, replaced);
    290     }
    291 
    292     @Test
    293     @SuppressWarnings("deprecation")
    294     public void testReplacingSystemWindowInsets_consistencyAcrossOverloads() {
    295         final Rect newInsets = new Rect(100, 200, 300, 400);
    296         final WindowInsets insets = new WindowInsets.Builder()
    297                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    298                 .setStableInsets(Insets.of(5, 6, 7, 8))
    299                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    300                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    301                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    302                 .setDisplayCutout(CUTOUT).build();
    303 
    304         assertEquals(insets.replaceSystemWindowInsets(newInsets),
    305                 insets.replaceSystemWindowInsets(newInsets.left, newInsets.top, newInsets.right,
    306                         newInsets.bottom));
    307     }
    308 
    309     @Test
    310     public void testInEquality_difference() {
    311         final WindowInsets insets = new WindowInsets.Builder()
    312                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    313                 .setStableInsets(Insets.of(5, 6, 7, 8))
    314                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    315                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    316                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    317                 .setDisplayCutout(CUTOUT).build();
    318 
    319         final WindowInsets insetsChangedSysWindowInsets = new WindowInsets.Builder()
    320                 .setSystemWindowInsets(Insets.of(10, 20, 30, 40))
    321                 .setStableInsets(Insets.of(5, 6, 7, 8))
    322                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    323                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    324                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    325                 .setDisplayCutout(CUTOUT).build();
    326 
    327         final WindowInsets insetsChangedStableInsets = new WindowInsets.Builder()
    328                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    329                 .setStableInsets(Insets.of(50, 60, 70, 80))
    330                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    331                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    332                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    333                 .setDisplayCutout(CUTOUT).build();
    334 
    335         final WindowInsets insetsChangedCutout = new WindowInsets.Builder()
    336                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    337                 .setStableInsets(Insets.of(5, 6, 7, 8))
    338                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    339                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    340                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    341                 .setDisplayCutout(CUTOUT2).build();
    342 
    343         final WindowInsets insetsChangedGesture = new WindowInsets.Builder()
    344                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    345                 .setStableInsets(Insets.of(5, 6, 7, 8))
    346                 .setSystemGestureInsets(Insets.of(90, 100, 110, 120))
    347                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    348                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    349                 .setDisplayCutout(CUTOUT).build();
    350 
    351         final WindowInsets insetsChangedMandatoryGesture = new WindowInsets.Builder()
    352                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    353                 .setStableInsets(Insets.of(5, 6, 7, 8))
    354                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    355                 .setMandatorySystemGestureInsets(Insets.of(130, 140, 150, 160))
    356                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    357                 .setDisplayCutout(CUTOUT).build();
    358 
    359         final WindowInsets insetsChangedTappableElement = new WindowInsets.Builder()
    360                 .setSystemWindowInsets(Insets.of(1, 2, 3, 4))
    361                 .setStableInsets(Insets.of(5, 6, 7, 8))
    362                 .setSystemGestureInsets(Insets.of(9, 10, 11, 12))
    363                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    364                 .setTappableElementInsets(Insets.of(170, 180, 190, 200))
    365                 .setDisplayCutout(CUTOUT).build();
    366 
    367         assertNotEquals(insets, insetsChangedSysWindowInsets);
    368         assertNotEquals(insets, insetsChangedStableInsets);
    369         assertNotEquals(insets, insetsChangedCutout);
    370         assertNotEquals(insets, insetsChangedGesture);
    371         assertNotEquals(insets, insetsChangedMandatoryGesture);
    372         assertNotEquals(insets, insetsChangedTappableElement);
    373     }
    374 
    375     @Test
    376     public void testInset() {
    377         final WindowInsets insets = new WindowInsets.Builder()
    378                 .setSystemWindowInsets(Insets.of(10, 20, 30, 40))
    379                 .setStableInsets(Insets.of(50, 60, 70, 80))
    380                 .setSystemGestureInsets(Insets.of(90, 100, 110, 120))
    381                 .setMandatorySystemGestureInsets(Insets.of(130, 140, 150, 160))
    382                 .setTappableElementInsets(Insets.of(170, 180, 190, 200))
    383                 .setDisplayCutout(CUTOUT).build();
    384 
    385         final WindowInsets insetInsets = insets.inset(
    386                 INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM);
    387 
    388         assertEquals(applyInset(insets.getSystemWindowInsets()),
    389                 insetInsets.getSystemWindowInsets());
    390         assertEquals(applyInset(insets.getStableInsets()), insetInsets.getStableInsets());
    391         assertEquals(applyInset(insets.getSystemGestureInsets()),
    392                 insetInsets.getSystemGestureInsets());
    393         assertEquals(applyInset(insets.getMandatorySystemGestureInsets()),
    394                 insetInsets.getMandatorySystemGestureInsets());
    395         assertEquals(applyInset(insets.getTappableElementInsets()),
    396                 insetInsets.getTappableElementInsets());
    397         assertEquals(applyInset(getCutoutSafeInsets(insets)), getCutoutSafeInsets(insetInsets));
    398     }
    399 
    400     @Test
    401     public void testInset_clipsToZero() {
    402         final WindowInsets insets = new WindowInsets.Builder()
    403                 .setSystemWindowInsets(Insets.of(10, 20, 30, 40))
    404                 .setStableInsets(Insets.of(50, 60, 70, 80))
    405                 .setSystemGestureInsets(Insets.of(90, 100, 110, 120))
    406                 .setMandatorySystemGestureInsets(Insets.of(13, 14, 15, 16))
    407                 .setTappableElementInsets(Insets.of(17, 18, 19, 20))
    408                 .setDisplayCutout(CUTOUT).build();
    409 
    410         final WindowInsets insetInsets = insets.inset(1000, 1000, 1000, 1000);
    411 
    412         assertEquals(Insets.NONE, insetInsets.getSystemWindowInsets());
    413         assertEquals(Insets.NONE, insetInsets.getStableInsets());
    414         assertEquals(Insets.NONE, insetInsets.getSystemGestureInsets());
    415         assertEquals(Insets.NONE, insetInsets.getMandatorySystemGestureInsets());
    416         assertEquals(Insets.NONE, insetInsets.getTappableElementInsets());
    417         assertNull(insetInsets.getDisplayCutout());
    418     }
    419 
    420     @Test
    421     public void testConsumed_copy() {
    422         final WindowInsets insets = new WindowInsets.Builder()
    423                 .setSystemWindowInsets(Insets.of(10, 20, 30, 40))
    424                 .setStableInsets(Insets.of(50, 60, 70, 80))
    425                 .build();
    426 
    427         final WindowInsets consumed = insets.consumeSystemWindowInsets().consumeStableInsets();
    428         final WindowInsets copy = new WindowInsets(consumed);
    429         assertTrue(copy.isConsumed());
    430     }
    431 
    432     private static Insets applyInset(Insets res) {
    433         return Insets.of(Math.max(0, res.left - INSET_LEFT),
    434                 Math.max(0, res.top - INSET_TOP),
    435                 Math.max(0, res.right - INSET_RIGHT),
    436                 Math.max(0, res.bottom - INSET_BOTTOM));
    437     }
    438 
    439     private static Insets getCutoutSafeInsets(WindowInsets insets) {
    440         final DisplayCutout dc = insets.getDisplayCutout();
    441         return Insets.of(dc.getSafeInsetLeft(), dc.getSafeInsetTop(), dc.getSafeInsetRight(),
    442                 dc.getSafeInsetBottom());
    443     }
    444 }
    445