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