1 /*
2  * Copyright (C) 2014 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.android.setupwizard.navigationbar;
18 
19 import android.app.Activity;
20 import android.app.Fragment;
21 import android.content.Context;
22 import android.content.res.TypedArray;
23 import android.graphics.Color;
24 import android.os.Bundle;
25 import android.util.AttributeSet;
26 import android.view.ContextThemeWrapper;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.View.OnClickListener;
30 import android.view.ViewGroup;
31 import android.view.ViewTreeObserver;
32 import android.view.ViewTreeObserver.OnPreDrawListener;
33 import android.widget.Button;
34 
35 /**
36  * Fragment class for controlling the custom navigation bar shown during setup wizard. Apps in the
37  * Android tree can use this by including the common.mk makefile. Apps outside of the tree can
38  * create a library project out of the source.
39  */
40 public class SetupWizardNavBar extends Fragment implements OnPreDrawListener, OnClickListener {
41     private static final String TAG = "SetupWizardNavBar";
42     private static final int IMMERSIVE_FLAGS =
43             View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
44     private int mSystemUiFlags = IMMERSIVE_FLAGS | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
45 
46     private ViewGroup mNavigationBarView;
47     private Button mNextButton;
48     private Button mBackButton;
49     private NavigationBarListener mCallback;
50 
51     public interface NavigationBarListener {
onNavigationBarCreated(SetupWizardNavBar bar)52         public void onNavigationBarCreated(SetupWizardNavBar bar);
onNavigateBack()53         public void onNavigateBack();
onNavigateNext()54         public void onNavigateNext();
55     }
56 
SetupWizardNavBar()57     public SetupWizardNavBar() {
58         // no-arg constructor for fragments
59     }
60 
61     @Override
onAttach(Activity activity)62     public void onAttach(Activity activity) {
63         super.onAttach(activity);
64         mCallback = (NavigationBarListener) activity;
65     }
66 
67     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)68     public View onCreateView(LayoutInflater inflater, ViewGroup container,
69             Bundle savedInstanceState) {
70         Context context = new ContextThemeWrapper(getActivity(), getNavbarTheme());
71         inflater = LayoutInflater.from(context);
72         mNavigationBarView = (ViewGroup) inflater.inflate(R.layout.setup_wizard_navbar_layout,
73                 container, false);
74         mNextButton = (Button) mNavigationBarView.findViewById(R.id.setup_wizard_navbar_next);
75         mBackButton = (Button) mNavigationBarView.findViewById(R.id.setup_wizard_navbar_back);
76         mNextButton.setOnClickListener(this);
77         mBackButton.setOnClickListener(this);
78         return mNavigationBarView;
79     }
80 
81     @Override
onViewCreated(View view, Bundle savedInstanceState)82     public void onViewCreated(View view, Bundle savedInstanceState) {
83         super.onViewCreated(view, savedInstanceState);
84         mCallback.onNavigationBarCreated(this);
85         mNavigationBarView.setSystemUiVisibility(mSystemUiFlags);
86 
87         // Set the UI flags before draw because the visibility might change in unexpected /
88         // undetectable times, like transitioning from a finishing activity that had a keyboard
89         ViewTreeObserver viewTreeObserver = mNavigationBarView.getViewTreeObserver();
90         viewTreeObserver.addOnPreDrawListener(this);
91     }
92 
93     @Override
onPreDraw()94     public boolean onPreDraw() {
95         // View.setSystemUiVisibility checks if the visibility changes before applying them
96         // so the performance impact is contained
97         mNavigationBarView.setSystemUiVisibility(mSystemUiFlags);
98         return true;
99     }
100 
101     /**
102      * Sets whether system navigation bar should be hidden.
103      * @param useImmersiveMode True to activate immersive mode and hide the system navigation bar
104      */
setUseImmersiveMode(boolean useImmersiveMode)105     public void setUseImmersiveMode(boolean useImmersiveMode) {
106         // By default, enable layoutHideNavigation if immersive mode is used
107         setUseImmersiveMode(useImmersiveMode, useImmersiveMode);
108     }
109 
setUseImmersiveMode(boolean useImmersiveMode, boolean layoutHideNavigation)110     public void setUseImmersiveMode(boolean useImmersiveMode, boolean layoutHideNavigation) {
111         if (useImmersiveMode) {
112             mSystemUiFlags |= IMMERSIVE_FLAGS;
113             if (layoutHideNavigation) {
114                 mSystemUiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
115             }
116         } else {
117             mSystemUiFlags &= ~(IMMERSIVE_FLAGS | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
118         }
119         mNavigationBarView.setSystemUiVisibility(mSystemUiFlags);
120     }
121 
getNavbarTheme()122     private int getNavbarTheme() {
123         // Normally we can automatically guess the theme by comparing the foreground color against
124         // the background color. But we also allow specifying explicitly using
125         // setup_wizard_navbar_theme.
126         TypedArray attributes = getActivity().obtainStyledAttributes(
127                 new int[] {
128                         R.attr.setup_wizard_navbar_theme,
129                         android.R.attr.colorForeground,
130                         android.R.attr.colorBackground });
131         int theme = attributes.getResourceId(0, 0);
132         if (theme == 0) {
133             // Compare the value of the foreground against the background color to see if current
134             // theme is light-on-dark or dark-on-light.
135             float[] foregroundHsv = new float[3];
136             float[] backgroundHsv = new float[3];
137             Color.colorToHSV(attributes.getColor(1, 0), foregroundHsv);
138             Color.colorToHSV(attributes.getColor(2, 0), backgroundHsv);
139             boolean isDarkBg = foregroundHsv[2] > backgroundHsv[2];
140             theme = isDarkBg ? R.style.setup_wizard_navbar_theme_dark :
141                     R.style.setup_wizard_navbar_theme_light;
142         }
143         attributes.recycle();
144         return theme;
145     }
146 
147     @Override
onClick(View v)148     public void onClick(View v) {
149         if (v == mBackButton) {
150             mCallback.onNavigateBack();
151         } else if (v == mNextButton) {
152             mCallback.onNavigateNext();
153         }
154     }
155 
getBackButton()156     public Button getBackButton() {
157         return mBackButton;
158     }
159 
getNextButton()160     public Button getNextButton() {
161         return mNextButton;
162     }
163 
164     public static class NavButton extends Button {
165 
NavButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)166         public NavButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
167             super(context, attrs, defStyleAttr, defStyleRes);
168         }
169 
NavButton(Context context, AttributeSet attrs, int defStyleAttr)170         public NavButton(Context context, AttributeSet attrs, int defStyleAttr) {
171             super(context, attrs, defStyleAttr);
172         }
173 
NavButton(Context context, AttributeSet attrs)174         public NavButton(Context context, AttributeSet attrs) {
175             super(context, attrs);
176         }
177 
NavButton(Context context)178         public NavButton(Context context) {
179             super(context);
180         }
181 
182         @Override
setEnabled(boolean enabled)183         public void setEnabled(boolean enabled) {
184             super.setEnabled(enabled);
185             // The color of the button is #de000000 / #deffffff when enabled. When disabled, apply
186             // additional 23% alpha, so the overall opacity is 20%.
187             setAlpha(enabled ? 1.0f : 0.23f);
188         }
189     }
190 
191 }
192