13da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam/* 240dd08f091020a436af0d253d2cb54f560493920Maurice Lam * Copyright (C) 2014 The Android Open Source Project 33da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * 43da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * Licensed under the Apache License, Version 2.0 (the "License"); 53da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * you may not use this file except in compliance with the License. 63da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * You may obtain a copy of the License at 73da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * 83da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * http://www.apache.org/licenses/LICENSE-2.0 93da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * 103da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * Unless required by applicable law or agreed to in writing, software 113da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * distributed under the License is distributed on an "AS IS" BASIS, 123da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * See the License for the specific language governing permissions and 143da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * limitations under the License. 153da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam */ 163da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 173da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lampackage com.android.setupwizard.navigationbar; 183da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 193da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.app.Activity; 203da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.app.Fragment; 213da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.content.Context; 223da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.content.res.TypedArray; 233da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.graphics.Color; 243da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.os.Bundle; 253da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.util.AttributeSet; 263da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.view.ContextThemeWrapper; 273da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.view.LayoutInflater; 283da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.view.View; 293da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.view.View.OnClickListener; 303da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.view.ViewGroup; 313da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.view.ViewTreeObserver; 323da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.view.ViewTreeObserver.OnPreDrawListener; 333da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lamimport android.widget.Button; 343da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 353da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam/** 36d9fbe9e218ce792755341aea4cd9c678171c5669Maurice Lam * Fragment class for controlling the custom navigation bar shown during setup wizard. Apps in the 37d9fbe9e218ce792755341aea4cd9c678171c5669Maurice Lam * Android tree can use this by including the common.mk makefile. Apps outside of the tree can 38d9fbe9e218ce792755341aea4cd9c678171c5669Maurice Lam * create a library project out of the source. 393da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam */ 406c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lampublic class SetupWizardNavBar extends Fragment implements OnPreDrawListener, OnClickListener { 413da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam private static final String TAG = "SetupWizardNavBar"; 423da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam private static final int IMMERSIVE_FLAGS = 433da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 44f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam private int mSystemUiFlags = IMMERSIVE_FLAGS | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 453da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 463da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam private ViewGroup mNavigationBarView; 473da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam private Button mNextButton; 483da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam private Button mBackButton; 493da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam private NavigationBarListener mCallback; 503da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 513da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public interface NavigationBarListener { 523da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public void onNavigationBarCreated(SetupWizardNavBar bar); 533da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public void onNavigateBack(); 543da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public void onNavigateNext(); 553da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 563da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 573da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public SetupWizardNavBar() { 583da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam // no-arg constructor for fragments 593da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 603da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 613da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam @Override 623da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public void onAttach(Activity activity) { 633da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam super.onAttach(activity); 646c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam mCallback = (NavigationBarListener) activity; 653da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 663da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 673da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam @Override 683da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public View onCreateView(LayoutInflater inflater, ViewGroup container, 693da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam Bundle savedInstanceState) { 703da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam Context context = new ContextThemeWrapper(getActivity(), getNavbarTheme()); 713da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam inflater = LayoutInflater.from(context); 723da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam mNavigationBarView = (ViewGroup) inflater.inflate(R.layout.setup_wizard_navbar_layout, 733da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam container, false); 746c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam mNextButton = (Button) mNavigationBarView.findViewById(R.id.setup_wizard_navbar_next); 756c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam mBackButton = (Button) mNavigationBarView.findViewById(R.id.setup_wizard_navbar_back); 766c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam mNextButton.setOnClickListener(this); 776c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam mBackButton.setOnClickListener(this); 783da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam return mNavigationBarView; 793da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 803da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 813da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam @Override 823da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public void onViewCreated(View view, Bundle savedInstanceState) { 833da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam super.onViewCreated(view, savedInstanceState); 843da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam mCallback.onNavigationBarCreated(this); 853da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam mNavigationBarView.setSystemUiVisibility(mSystemUiFlags); 863da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 873da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam // Set the UI flags before draw because the visibility might change in unexpected / 883da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam // undetectable times, like transitioning from a finishing activity that had a keyboard 893da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam ViewTreeObserver viewTreeObserver = mNavigationBarView.getViewTreeObserver(); 903da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam viewTreeObserver.addOnPreDrawListener(this); 913da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 923da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 933da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam @Override 943da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public boolean onPreDraw() { 953da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam // View.setSystemUiVisibility checks if the visibility changes before applying them 963da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam // so the performance impact is contained 973da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam mNavigationBarView.setSystemUiVisibility(mSystemUiFlags); 983da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam return true; 993da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1003da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1013da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam /** 1023da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * Sets whether system navigation bar should be hidden. 1033da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam * @param useImmersiveMode True to activate immersive mode and hide the system navigation bar 1043da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam */ 1053da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public void setUseImmersiveMode(boolean useImmersiveMode) { 106f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam // By default, enable layoutHideNavigation if immersive mode is used 107f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam setUseImmersiveMode(useImmersiveMode, useImmersiveMode); 108f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam } 109f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam 110f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam public void setUseImmersiveMode(boolean useImmersiveMode, boolean layoutHideNavigation) { 111f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam if (useImmersiveMode) { 112f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam mSystemUiFlags |= IMMERSIVE_FLAGS; 113f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam if (layoutHideNavigation) { 114f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam mSystemUiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 115f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam } 116f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam } else { 117f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam mSystemUiFlags &= ~(IMMERSIVE_FLAGS | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); 118f24653c485c73b8f4e8b947cfd2dbed8d79aa58eMaurice Lam } 1193da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam mNavigationBarView.setSystemUiVisibility(mSystemUiFlags); 1203da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1213da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1223da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam private int getNavbarTheme() { 1236c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam // Normally we can automatically guess the theme by comparing the foreground color against 1246c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam // the background color. But we also allow specifying explicitly using 1256c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam // setup_wizard_navbar_theme. 1263da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam TypedArray attributes = getActivity().obtainStyledAttributes( 1273da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam new int[] { 1283da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam R.attr.setup_wizard_navbar_theme, 1293da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam android.R.attr.colorForeground, 1303da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam android.R.attr.colorBackground }); 1313da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam int theme = attributes.getResourceId(0, 0); 1323da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam if (theme == 0) { 1336c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam // Compare the value of the foreground against the background color to see if current 1346c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam // theme is light-on-dark or dark-on-light. 1353da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam float[] foregroundHsv = new float[3]; 1363da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam float[] backgroundHsv = new float[3]; 1373da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam Color.colorToHSV(attributes.getColor(1, 0), foregroundHsv); 1383da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam Color.colorToHSV(attributes.getColor(2, 0), backgroundHsv); 1393da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam boolean isDarkBg = foregroundHsv[2] > backgroundHsv[2]; 1403da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam theme = isDarkBg ? R.style.setup_wizard_navbar_theme_dark : 1413da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam R.style.setup_wizard_navbar_theme_light; 1423da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1433da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam attributes.recycle(); 1443da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam return theme; 1453da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1463da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1476c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam @Override 1486c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam public void onClick(View v) { 1496c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam if (v == mBackButton) { 1506c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam mCallback.onNavigateBack(); 1516c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam } else if (v == mNextButton) { 1526c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam mCallback.onNavigateNext(); 1536c4d5786ec0ce22429a68c5b9e92f3dab9863f2dMaurice Lam } 1543da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1553da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1563da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public Button getBackButton() { 1573da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam return mBackButton; 1583da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1593da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1603da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public Button getNextButton() { 1613da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam return mNextButton; 1623da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1633da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1643da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public static class NavButton extends Button { 1653da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1663da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public NavButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 1673da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam super(context, attrs, defStyleAttr, defStyleRes); 1683da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1693da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1703da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public NavButton(Context context, AttributeSet attrs, int defStyleAttr) { 1713da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam super(context, attrs, defStyleAttr); 1723da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1733da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1743da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public NavButton(Context context, AttributeSet attrs) { 1753da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam super(context, attrs); 1763da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1773da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1783da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public NavButton(Context context) { 1793da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam super(context); 1803da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1813da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1823da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam @Override 1833da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam public void setEnabled(boolean enabled) { 1843da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam super.setEnabled(enabled); 185fc4414955c73b11a7975c74a741df00c7b3a005bMaurice Lam // The color of the button is #de000000 / #deffffff when enabled. When disabled, apply 186fc4414955c73b11a7975c74a741df00c7b3a005bMaurice Lam // additional 23% alpha, so the overall opacity is 20%. 187fc4414955c73b11a7975c74a741df00c7b3a005bMaurice Lam setAlpha(enabled ? 1.0f : 0.23f); 1883da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1893da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam } 1903da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam 1913da01bb1e0865edc45a4cebe122c4ab1f1ba0bacMaurice Lam} 192