Home | History | Annotate | Download | only in template
      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 com.google.android.setupcompat.template;
     18 
     19 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
     20 
     21 import android.content.Context;
     22 import android.content.res.TypedArray;
     23 import android.graphics.Color;
     24 import android.os.Build;
     25 import android.os.Build.VERSION;
     26 import android.os.Build.VERSION_CODES;
     27 import androidx.annotation.AttrRes;
     28 import androidx.annotation.NonNull;
     29 import androidx.annotation.Nullable;
     30 import androidx.annotation.VisibleForTesting;
     31 import android.util.AttributeSet;
     32 import android.view.View;
     33 import android.view.Window;
     34 import com.google.android.setupcompat.PartnerCustomizationLayout;
     35 import com.google.android.setupcompat.R;
     36 import com.google.android.setupcompat.internal.TemplateLayout;
     37 import com.google.android.setupcompat.partnerconfig.PartnerConfig;
     38 import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
     39 import com.google.android.setupcompat.util.SystemBarHelper;
     40 
     41 /**
     42  * A {@link Mixin} for setting and getting background color and window compatible with light theme
     43  * of system navigation bar.
     44  */
     45 public class SystemNavBarMixin implements Mixin {
     46 
     47   private final TemplateLayout templateLayout;
     48   @Nullable private final Window windowOfActivity;
     49   @VisibleForTesting final boolean applyPartnerResources;
     50   private int sucSystemNavBarBackgroundColor = 0;
     51 
     52   /**
     53    * Creates a mixin for managing the system navigation bar.
     54    *
     55    * @param layout The layout this Mixin belongs to.
     56    * @param window The window this activity of Mixin belongs to.*
     57    */
     58   public SystemNavBarMixin(@NonNull TemplateLayout layout, @Nullable Window window) {
     59     this.templateLayout = layout;
     60     this.windowOfActivity = window;
     61     this.applyPartnerResources =
     62         layout instanceof PartnerCustomizationLayout
     63             && ((PartnerCustomizationLayout) layout).shouldApplyPartnerResource();
     64   }
     65 
     66   /**
     67    * Creates a mixin for managing the system navigation bar.
     68    *
     69    * @param attrs XML attributes given to the layout.
     70    * @param defStyleAttr The default style attribute as given to the constructor of the layout.
     71    */
     72   public void applyPartnerCustomizations(@Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
     73     // Support updating system navigation bar background color and is light system navigation bar
     74     // from O.
     75     if (Build.VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
     76       TypedArray a =
     77           templateLayout
     78               .getContext()
     79               .obtainStyledAttributes(attrs, R.styleable.SucSystemNavBarMixin, defStyleAttr, 0);
     80       sucSystemNavBarBackgroundColor =
     81           a.getColor(R.styleable.SucSystemNavBarMixin_sucSystemNavBarBackgroundColor, 0);
     82       setSystemNavBarBackground(sucSystemNavBarBackgroundColor);
     83       setLightSystemNavBar(
     84           a.getBoolean(
     85               R.styleable.SucSystemNavBarMixin_sucLightSystemNavBar, isLightSystemNavBar()));
     86       a.recycle();
     87     }
     88   }
     89 
     90   /**
     91    * Sets the background color of navigation bar. The color will be overridden by partner resource
     92    * if the activity is running in setup wizard flow.
     93    *
     94    * @param color The background color of navigation bar.
     95    */
     96   public void setSystemNavBarBackground(int color) {
     97     if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && windowOfActivity != null) {
     98       if (applyPartnerResources) {
     99         Context context = templateLayout.getContext();
    100         color =
    101             PartnerConfigHelper.get(context)
    102                 .getColor(context, PartnerConfig.CONFIG_NAVIGATION_BAR_BG_COLOR);
    103       }
    104       windowOfActivity.setNavigationBarColor(color);
    105     }
    106   }
    107 
    108   /** Returns the background color of navigation bar. */
    109   public int getSystemNavBarBackground() {
    110     if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && windowOfActivity != null) {
    111       return windowOfActivity.getNavigationBarColor();
    112     }
    113     return Color.BLACK;
    114   }
    115 
    116   /**
    117    * Sets the navigation bar to draw in a mode that is compatible with light or dark navigation bar
    118    * backgrounds. The navigation bar drawing mode will be overridden by partner resource if the
    119    * activity is running in setup wizard flow.
    120    *
    121    * @param isLight true means compatible with light theme, otherwise compatible with dark theme
    122    */
    123   public void setLightSystemNavBar(boolean isLight) {
    124     if (Build.VERSION.SDK_INT >= VERSION_CODES.O && windowOfActivity != null) {
    125       if (applyPartnerResources) {
    126         Context context = templateLayout.getContext();
    127         isLight =
    128             PartnerConfigHelper.get(context)
    129                 .getBoolean(context, PartnerConfig.CONFIG_LIGHT_NAVIGATION_BAR, false);
    130       }
    131       if (isLight) {
    132         windowOfActivity
    133             .getDecorView()
    134             .setSystemUiVisibility(
    135                 windowOfActivity.getDecorView().getSystemUiVisibility()
    136                     | SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
    137       } else {
    138         windowOfActivity
    139             .getDecorView()
    140             .setSystemUiVisibility(
    141                 windowOfActivity.getDecorView().getSystemUiVisibility()
    142                     & ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
    143       }
    144     }
    145   }
    146 
    147   /**
    148    * Returns true if the navigation bar icon should be drawn on light background, false if the icons
    149    * should be drawn light-on-dark.
    150    */
    151   public boolean isLightSystemNavBar() {
    152     if (Build.VERSION.SDK_INT >= VERSION_CODES.O && windowOfActivity != null) {
    153       return (windowOfActivity.getDecorView().getSystemUiVisibility()
    154               & SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR)
    155           == SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
    156     }
    157     return true;
    158   }
    159 
    160   /**
    161    * Hides the navigation bar, make the color of the status and navigation bars transparent, and
    162    * specify {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} flag so that the content is laid-out
    163    * behind the transparent status bar. This is commonly used with {@link
    164    * android.app.Activity#getWindow()} to make the navigation and status bars follow the Setup
    165    * Wizard style.
    166    *
    167    * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op.
    168    */
    169   public void hideSystemBars(final Window window) {
    170     if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
    171       SystemBarHelper.addVisibilityFlag(window, SystemBarHelper.DEFAULT_IMMERSIVE_FLAGS);
    172       SystemBarHelper.addImmersiveFlagsToDecorView(window, SystemBarHelper.DEFAULT_IMMERSIVE_FLAGS);
    173 
    174       // Also set the navigation bar and status bar to transparent color. Note that this
    175       // doesn't work if android.R.boolean.config_enableTranslucentDecor is false.
    176       window.setNavigationBarColor(Color.TRANSPARENT);
    177       window.setStatusBarColor(Color.TRANSPARENT);
    178     }
    179   }
    180 
    181   /**
    182    * Reverts the actions of hideSystemBars. Note that this will remove the system UI visibility
    183    * flags regardless of whether it is originally present. The status bar color is reset to
    184    * transparent, thus it will show the status bar color set by StatusBarMixin.
    185    *
    186    * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op.
    187    */
    188   public void showSystemBars(final Window window, final Context context) {
    189     if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
    190       SystemBarHelper.removeVisibilityFlag(window, SystemBarHelper.DEFAULT_IMMERSIVE_FLAGS);
    191       SystemBarHelper.removeImmersiveFlagsFromDecorView(
    192           window, SystemBarHelper.DEFAULT_IMMERSIVE_FLAGS);
    193 
    194       if (context != null) {
    195         if (applyPartnerResources) {
    196           int partnerNavigationBarColor =
    197               PartnerConfigHelper.get(context)
    198                   .getColor(context, PartnerConfig.CONFIG_NAVIGATION_BAR_BG_COLOR);
    199           window.setStatusBarColor(Color.TRANSPARENT);
    200           window.setNavigationBarColor(partnerNavigationBarColor);
    201         } else {
    202           // noinspection AndroidLintInlinedApi
    203           TypedArray typedArray =
    204               context.obtainStyledAttributes(
    205                   new int[] {android.R.attr.statusBarColor, android.R.attr.navigationBarColor});
    206           int statusBarColor = typedArray.getColor(0, 0);
    207           int navigationBarColor = typedArray.getColor(1, 0);
    208           if (templateLayout instanceof PartnerCustomizationLayout) {
    209             if (VERSION.SDK_INT >= VERSION_CODES.M) {
    210               statusBarColor = Color.TRANSPARENT;
    211             }
    212             if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
    213               navigationBarColor = sucSystemNavBarBackgroundColor;
    214             }
    215           }
    216           window.setStatusBarColor(statusBarColor);
    217           window.setNavigationBarColor(navigationBarColor);
    218           typedArray.recycle();
    219         }
    220       }
    221     }
    222   }
    223 }
    224