1/*
2 * Copyright (C) 2015 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
17package com.android.setupwizardlib.test;
18
19import android.annotation.SuppressLint;
20import android.app.Dialog;
21import android.content.Context;
22import android.os.Build.VERSION;
23import android.os.Build.VERSION_CODES;
24import android.os.Handler;
25import android.os.HandlerThread;
26import android.os.SystemClock;
27import android.test.AndroidTestCase;
28import android.test.suitebuilder.annotation.SmallTest;
29import android.view.View;
30import android.view.Window;
31import android.view.WindowManager;
32
33import com.android.setupwizardlib.test.util.MockWindow;
34import com.android.setupwizardlib.util.SystemBarHelper;
35
36public class SystemBarHelperTest extends AndroidTestCase {
37
38    private static final int STATUS_BAR_DISABLE_BACK = 0x00400000;
39
40    @SuppressLint("InlinedApi")
41    private static final int DEFAULT_IMMERSIVE_FLAGS =
42            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
43            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
44            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
45            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
46
47    @SuppressLint("InlinedApi")
48    private static final int DIALOG_IMMERSIVE_FLAGS =
49            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
50                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
51
52    @SmallTest
53    public void testAddVisibilityFlagView() {
54        final View view = createViewWithSystemUiVisibility(0x456);
55        SystemBarHelper.addVisibilityFlag(view, 0x1400);
56        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
57            // Check that result is 0x1456, because 0x1400 | 0x456 = 0x1456.
58            assertEquals("View visibility should be 0x1456", 0x1456, view.getSystemUiVisibility());
59        }
60    }
61
62    @SmallTest
63    public void testRemoveVisibilityFlagView() {
64        final View view = createViewWithSystemUiVisibility(0x456);
65        SystemBarHelper.removeVisibilityFlag(view, 0x1400);
66        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
67            // Check that result is 0x56, because 0x456 & ~0x1400 = 0x56.
68            assertEquals("View visibility should be 0x56", 0x56, view.getSystemUiVisibility());
69        }
70    }
71
72    @SmallTest
73    public void testAddVisibilityFlagWindow() {
74        final Window window = createWindowWithSystemUiVisibility(0x456);
75        SystemBarHelper.addVisibilityFlag(window, 0x1400);
76        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
77            // Check that result is 0x1456 = 0x1400 | 0x456.
78            assertEquals("View visibility should be 0x1456", 0x1456,
79                    window.getAttributes().systemUiVisibility);
80        }
81    }
82
83    @SmallTest
84    public void testRemoveVisibilityFlagWindow() {
85        final Window window = createWindowWithSystemUiVisibility(0x456);
86        SystemBarHelper.removeVisibilityFlag(window, 0x1400);
87        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
88            // Check that result is 0x56 = 0x456 & ~0x1400.
89            assertEquals("View visibility should be 0x56", 0x56,
90                    window.getAttributes().systemUiVisibility);
91        }
92    }
93
94    @SmallTest
95    public void testHideSystemBarsWindow() {
96        final Window window = createWindowWithSystemUiVisibility(0x456);
97        SystemBarHelper.hideSystemBars(window);
98        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
99            assertEquals("DEFAULT_IMMERSIVE_FLAGS should be added to window's systemUiVisibility",
100                    DEFAULT_IMMERSIVE_FLAGS | 0x456,
101                    window.getAttributes().systemUiVisibility);
102            assertEquals(
103                    "DEFAULT_IMMERSIVE_FLAGS should be added to decorView's systemUiVisibility",
104                    DEFAULT_IMMERSIVE_FLAGS | 0x456,
105                    window.getDecorView().getSystemUiVisibility());
106            assertEquals("Navigation bar should be transparent", window.getNavigationBarColor(), 0);
107            assertEquals("Status bar should be transparent", window.getStatusBarColor(), 0);
108        }
109    }
110
111    @SmallTest
112    public void testShowSystemBarsWindow() {
113        final Window window = createWindowWithSystemUiVisibility(0x456);
114        SystemBarHelper.showSystemBars(window, getContext());
115        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
116            assertEquals(
117                    "DEFAULT_IMMERSIVE_FLAGS should be removed from window's systemUiVisibility",
118                    0x456 & ~DEFAULT_IMMERSIVE_FLAGS,
119                    window.getAttributes().systemUiVisibility);
120            assertEquals(
121                    "DEFAULT_IMMERSIVE_FLAGS should be removed from decorView's systemUiVisibility",
122                    0x456 & ~DEFAULT_IMMERSIVE_FLAGS,
123                    window.getDecorView().getSystemUiVisibility());
124            assertEquals("Navigation bar should not be transparent",
125                    window.getNavigationBarColor(), 0xff000000);
126            assertEquals("Status bar should not be transparent",
127                    window.getStatusBarColor(), 0xff000000);
128        }
129    }
130
131    @SmallTest
132    public void testHideSystemBarsNoInfiniteLoop() throws InterruptedException {
133        final TestWindow window = new TestWindow(getContext(), null);
134        final HandlerThread thread = new HandlerThread("SystemBarHelperTest");
135        thread.start();
136        final Handler handler = new Handler(thread.getLooper());
137        handler.post(new Runnable() {
138            @Override
139            public void run() {
140                SystemBarHelper.hideSystemBars(window);
141            }
142        });
143        SystemClock.sleep(500);  // Wait for the looper to drain all the messages
144        thread.quit();
145        // Initial peek + 3 retries = 4 tries total
146        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
147            assertEquals("Peek decor view should give up after 4 tries", 4,
148                    window.peekDecorViewCount);
149        }
150    }
151
152    @SmallTest
153    public void testHideSystemBarsDialog() {
154        final Dialog dialog = new Dialog(mContext);
155        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
156            final WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
157            attrs.systemUiVisibility = 0x456;
158            dialog.getWindow().setAttributes(attrs);
159        }
160
161        SystemBarHelper.hideSystemBars(dialog);
162        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
163            assertEquals("DIALOG_IMMERSIVE_FLAGS should be added to window's systemUiVisibility",
164                    DIALOG_IMMERSIVE_FLAGS | 0x456,
165                    dialog.getWindow().getAttributes().systemUiVisibility);
166        }
167    }
168
169    @SmallTest
170    public void testSetBackButtonVisibleTrue() {
171        final Window window = createWindowWithSystemUiVisibility(0x456);
172        SystemBarHelper.setBackButtonVisible(window, true);
173        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
174            assertEquals("View visibility should be 0x456", 0x456,
175                    window.getAttributes().systemUiVisibility);
176        }
177    }
178
179    @SmallTest
180    public void testSetBackButtonVisibleFalse() {
181        final Window window = createWindowWithSystemUiVisibility(0x456);
182        SystemBarHelper.setBackButtonVisible(window, false);
183        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
184            assertEquals("STATUS_BAR_DISABLE_BACK should be added to systemUiVisibility",
185                    0x456 | STATUS_BAR_DISABLE_BACK, window.getAttributes().systemUiVisibility);
186        }
187    }
188
189    private View createViewWithSystemUiVisibility(int vis) {
190        final View view = new View(getContext());
191        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
192            view.setSystemUiVisibility(vis);
193        }
194        return view;
195    }
196
197    private Window createWindowWithSystemUiVisibility(int vis) {
198        final Window window = new TestWindow(getContext(), createViewWithSystemUiVisibility(vis));
199        if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
200            WindowManager.LayoutParams attrs = window.getAttributes();
201            attrs.systemUiVisibility = vis;
202            window.setAttributes(attrs);
203        }
204        return window;
205    }
206
207    private static class TestWindow extends MockWindow {
208
209        private View mDecorView;
210        public int peekDecorViewCount = 0;
211
212        private int mNavigationBarColor = -1;
213        private int mStatusBarColor = -1;
214
215        public TestWindow(Context context, View decorView) {
216            super(context);
217            mDecorView = decorView;
218        }
219
220        @Override
221        public View getDecorView() {
222            return mDecorView;
223        }
224
225        @Override
226        public View peekDecorView() {
227            peekDecorViewCount++;
228            return mDecorView;
229        }
230
231        @Override
232        public void setNavigationBarColor(int i) {
233            mNavigationBarColor = i;
234        }
235
236        @Override
237        public int getNavigationBarColor() {
238            return mNavigationBarColor;
239        }
240
241        @Override
242        public void setStatusBarColor(int i) {
243            mStatusBarColor = i;
244        }
245
246        @Override
247        public int getStatusBarColor() {
248            return mStatusBarColor;
249        }
250    }
251}
252