blob: a16bd2a72a8339e936ea9e2d5a085bd62679ed62 [file] [log] [blame]
Wale Ogunwaled1c37912016-08-16 03:19:39 -07001/*
2 * Copyright (C) 2016 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
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070014 * limitations under the License.
Wale Ogunwaled1c37912016-08-16 03:19:39 -070015 */
16
17package com.android.server.wm;
18
Evan Rosky641daea2019-04-24 14:45:24 -070019import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
20import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
21import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -070022import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
Andrii Kulian4ede3e02017-01-12 11:52:31 -080023import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
Riddle Hsu0c1b0d12020-05-27 23:15:39 +080024import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
Andrii Kulian4ede3e02017-01-12 11:52:31 -080025import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -070026import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
Garfield Tanb6776602019-02-20 14:44:26 -080027import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Jorim Jaggiab9fcb22018-03-15 23:46:12 +010028import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
Wale Ogunwaled1c37912016-08-16 03:19:39 -070029import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
Bryce Lee081554b2017-05-25 07:52:12 -070030import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
31import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
Wale Ogunwale07bcab72016-10-14 15:30:09 -070032import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
Wale Ogunwaled1c37912016-08-16 03:19:39 -070033import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
34import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
wilsonshihca274ed2020-05-05 17:32:21 +080035import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
Brett Chabota26eda92018-07-23 13:08:30 -070036
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080037import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
38
Riddle Hsuffc12462020-05-27 17:43:25 +080039import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +090040import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
Louis Chang242be902020-06-03 12:24:45 +080041import static com.android.server.wm.WindowContainer.POSITION_TOP;
Evan Rosky641daea2019-04-24 14:45:24 -070042import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
43import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
44import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +090045
Wale Ogunwalea7e3b642016-08-29 10:15:34 -070046import static org.junit.Assert.assertEquals;
Bryce Lee081554b2017-05-25 07:52:12 -070047import static org.junit.Assert.assertFalse;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080048import static org.junit.Assert.assertNotNull;
Wale Ogunwalea7e3b642016-08-29 10:15:34 -070049import static org.junit.Assert.assertNull;
Wale Ogunwale07bcab72016-10-14 15:30:09 -070050import static org.junit.Assert.assertTrue;
Garfield Tanb6776602019-02-20 14:44:26 -080051import static org.mockito.ArgumentMatchers.any;
Riddle Hsuffc12462020-05-27 17:43:25 +080052import static org.mockito.ArgumentMatchers.anyBoolean;
Riddle Hsua118b3a2018-10-11 22:05:06 +080053import static org.mockito.ArgumentMatchers.anyInt;
Wale Ogunwale2322bed2019-10-10 17:24:19 +020054import static org.mockito.Mockito.reset;
Garfield Tanb6776602019-02-20 14:44:26 -080055import static org.mockito.Mockito.verify;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080056
Riddle Hsub398da32019-01-21 21:48:16 +080057import android.content.res.Configuration;
Riddle Hsua71f8e02020-05-05 23:07:59 +080058import android.graphics.Point;
Riddle Hsua118b3a2018-10-11 22:05:06 +080059import android.graphics.Rect;
Brett Chabota26eda92018-07-23 13:08:30 -070060import android.platform.test.annotations.Presubmit;
Garfield Tana3f19032019-11-19 18:04:50 -080061import android.view.IWindowManager;
Brett Chabota26eda92018-07-23 13:08:30 -070062import android.view.Surface;
63import android.view.WindowManager;
64
Yunfan Chenc1caf6b2019-04-12 13:58:51 +090065import androidx.test.filters.FlakyTest;
Brett Chabota26eda92018-07-23 13:08:30 -070066import androidx.test.filters.SmallTest;
Brett Chabota26eda92018-07-23 13:08:30 -070067
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070068import org.junit.Before;
Brett Chabota26eda92018-07-23 13:08:30 -070069import org.junit.Test;
Riddle Hsu73f53572019-09-23 23:13:01 +080070import org.junit.runner.RunWith;
Brett Chabota26eda92018-07-23 13:08:30 -070071
Issei Suzuki737b7f12020-05-25 14:54:06 +020072import java.util.ArrayList;
73
Wale Ogunwaled1c37912016-08-16 03:19:39 -070074/**
Garfield Tane8d84ab2019-10-11 09:49:40 -070075 * Tests for the {@link ActivityRecord} class.
Wale Ogunwaled1c37912016-08-16 03:19:39 -070076 *
Wale Ogunwale07bcab72016-10-14 15:30:09 -070077 * Build/Install/Run:
Vishnu Naire6e2b0f2019-02-21 10:41:00 -080078 * atest WmTests:AppWindowTokenTests
Wale Ogunwaled1c37912016-08-16 03:19:39 -070079 */
80@SmallTest
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070081@Presubmit
Riddle Hsu73f53572019-09-23 23:13:01 +080082@RunWith(WindowTestRunner.class)
Wale Ogunwale44fbdf52016-11-16 10:18:45 -080083public class AppWindowTokenTests extends WindowTestsBase {
Wale Ogunwaled1c37912016-08-16 03:19:39 -070084
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -070085 ActivityStack mStack;
Robert Carrb1579c82017-09-05 14:54:47 -070086 Task mTask;
Garfield Tane8d84ab2019-10-11 09:49:40 -070087 ActivityRecord mActivity;
Robert Carrb1579c82017-09-05 14:54:47 -070088
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080089 private final String mPackageName = getInstrumentation().getTargetContext().getPackageName();
90
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070091 @Before
Robert Carrb1579c82017-09-05 14:54:47 -070092 public void setUp() throws Exception {
Robert Carrb1579c82017-09-05 14:54:47 -070093 mStack = createTaskStackOnDisplay(mDisplayContent);
94 mTask = createTaskInStack(mStack, 0 /* userId */);
Garfield Tane8d84ab2019-10-11 09:49:40 -070095 mActivity = WindowTestUtils.createTestActivityRecord(mDisplayContent);
Robert Carrb1579c82017-09-05 14:54:47 -070096
Garfield Tane8d84ab2019-10-11 09:49:40 -070097 mTask.addChild(mActivity, 0);
Robert Carrb1579c82017-09-05 14:54:47 -070098 }
99
Wale Ogunwalea7e3b642016-08-29 10:15:34 -0700100 @Test
Andrii Kulian6b3a3712017-11-02 11:06:47 -0700101 @Presubmit
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700102 public void testAddWindow_Order() {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700103 assertEquals(0, mActivity.getChildCount());
Wale Ogunwale07bcab72016-10-14 15:30:09 -0700104
Garfield Tane8d84ab2019-10-11 09:49:40 -0700105 final WindowState win1 = createWindow(null, TYPE_APPLICATION, mActivity, "win1");
106 final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, mActivity,
Wale Ogunwale44fbdf52016-11-16 10:18:45 -0800107 "startingWin");
Garfield Tane8d84ab2019-10-11 09:49:40 -0700108 final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, mActivity, "baseWin");
109 final WindowState win4 = createWindow(null, TYPE_APPLICATION, mActivity, "win4");
Wale Ogunwale07bcab72016-10-14 15:30:09 -0700110
Wale Ogunwale07bcab72016-10-14 15:30:09 -0700111 // Should not contain the windows that were added above.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700112 assertEquals(4, mActivity.getChildCount());
113 assertTrue(mActivity.mChildren.contains(win1));
114 assertTrue(mActivity.mChildren.contains(startingWin));
115 assertTrue(mActivity.mChildren.contains(baseWin));
116 assertTrue(mActivity.mChildren.contains(win4));
Wale Ogunwale07bcab72016-10-14 15:30:09 -0700117
118 // The starting window should be on-top of all other windows.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700119 assertEquals(startingWin, mActivity.mChildren.peekLast());
Wale Ogunwale07bcab72016-10-14 15:30:09 -0700120
121 // The base application window should be below all other windows.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700122 assertEquals(baseWin, mActivity.mChildren.peekFirst());
123 mActivity.removeImmediately();
Wale Ogunwale07bcab72016-10-14 15:30:09 -0700124 }
125
126 @Test
Andrii Kulian6b3a3712017-11-02 11:06:47 -0700127 @Presubmit
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700128 public void testFindMainWindow() {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700129 assertNull(mActivity.findMainWindow());
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700130
Garfield Tane8d84ab2019-10-11 09:49:40 -0700131 final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mActivity, "window1");
132 final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, mActivity, "window11");
133 final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, mActivity, "window12");
134 assertEquals(window1, mActivity.findMainWindow());
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700135 window1.mAnimatingExit = true;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700136 assertEquals(window1, mActivity.findMainWindow());
137 final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, mActivity,
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +0900138 "window2");
Garfield Tane8d84ab2019-10-11 09:49:40 -0700139 assertEquals(window2, mActivity.findMainWindow());
140 mActivity.removeImmediately();
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700141 }
Andrii Kulian4ede3e02017-01-12 11:52:31 -0800142
143 @Test
Andrii Kulian6b3a3712017-11-02 11:06:47 -0700144 @Presubmit
Riddle Hsu84bc3d72019-12-19 19:24:07 +0800145 public void testGetTopFullscreenOpaqueWindow() {
146 assertNull(mActivity.getTopFullscreenOpaqueWindow());
Jorim Jaggi87fdbcb2017-08-17 13:41:11 +0200147
Garfield Tane8d84ab2019-10-11 09:49:40 -0700148 final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mActivity, "window1");
149 final WindowState window11 = createWindow(null, TYPE_APPLICATION, mActivity, "window11");
150 final WindowState window12 = createWindow(null, TYPE_APPLICATION, mActivity, "window12");
Riddle Hsu84bc3d72019-12-19 19:24:07 +0800151 assertEquals(window12, mActivity.getTopFullscreenOpaqueWindow());
Jorim Jaggi87fdbcb2017-08-17 13:41:11 +0200152 window12.mAttrs.width = 500;
Riddle Hsu84bc3d72019-12-19 19:24:07 +0800153 assertEquals(window11, mActivity.getTopFullscreenOpaqueWindow());
Jorim Jaggi87fdbcb2017-08-17 13:41:11 +0200154 window11.mAttrs.width = 500;
Riddle Hsu84bc3d72019-12-19 19:24:07 +0800155 assertEquals(window1, mActivity.getTopFullscreenOpaqueWindow());
156 window1.mAttrs.alpha = 0f;
157 assertNull(mActivity.getTopFullscreenOpaqueWindow());
Garfield Tane8d84ab2019-10-11 09:49:40 -0700158 mActivity.removeImmediately();
Jorim Jaggi87fdbcb2017-08-17 13:41:11 +0200159 }
160
161 @Test
Wale Ogunwale815c7cb2019-05-02 08:04:01 -0700162 @FlakyTest(bugId = 131005232)
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700163 public void testLandscapeSeascapeRotationByApp() {
Andrii Kulian4ede3e02017-01-12 11:52:31 -0800164 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
165 TYPE_BASE_APPLICATION);
166 attrs.setTitle("AppWindow");
Garfield Tane8d84ab2019-10-11 09:49:40 -0700167 final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mActivity);
168 mActivity.addWindow(appWindow);
Andrii Kulian4ede3e02017-01-12 11:52:31 -0800169
170 // Set initial orientation and update.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700171 mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
Riddle Hsuccf09402019-08-13 00:33:06 +0800172 mDisplayContent.updateOrientation(
Garfield Tan90b04282018-12-11 14:04:42 -0800173 mDisplayContent.getRequestedOverrideConfiguration(),
174 null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700175 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +0900176 appWindow.mResizeReported = false;
Andrii Kulian4ede3e02017-01-12 11:52:31 -0800177
178 // Update the orientation to perform 180 degree rotation and check that resize was reported.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700179 mActivity.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
Riddle Hsuccf09402019-08-13 00:33:06 +0800180 mDisplayContent.updateOrientation(
Garfield Tan90b04282018-12-11 14:04:42 -0800181 mDisplayContent.getRequestedOverrideConfiguration(),
182 null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
Yunfan Chen0530fe72019-02-12 15:05:49 +0900183 // In this test, DC will not get config update. Set the waiting flag to false.
184 mDisplayContent.mWaitingForConfig = false;
Riddle Hsu72d6dc32020-03-25 22:58:00 +0800185 mWm.mRoot.performSurfacePlacement();
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700186 assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +0900187 assertTrue(appWindow.mResizeReported);
Wale Ogunwale1666e312016-12-16 11:27:18 -0800188 appWindow.removeImmediately();
Andrii Kulian4ede3e02017-01-12 11:52:31 -0800189 }
190
191 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700192 public void testLandscapeSeascapeRotationByPolicy() {
Louis Chang677921f2019-12-06 16:44:24 +0800193 // This instance has been spied in {@link TestDisplayContent}.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700194 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800195
Andrii Kulian4ede3e02017-01-12 11:52:31 -0800196 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
197 TYPE_BASE_APPLICATION);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700198 attrs.setTitle("RotationByPolicy");
Garfield Tane8d84ab2019-10-11 09:49:40 -0700199 final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mActivity);
200 mActivity.addWindow(appWindow);
Andrii Kulian4ede3e02017-01-12 11:52:31 -0800201
202 // Set initial orientation and update.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700203 performRotation(displayRotation, Surface.ROTATION_90);
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +0900204 appWindow.mResizeReported = false;
Andrii Kulian4ede3e02017-01-12 11:52:31 -0800205
206 // Update the rotation to perform 180 degree rotation and check that resize was reported.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700207 performRotation(displayRotation, Surface.ROTATION_270);
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +0900208 assertTrue(appWindow.mResizeReported);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800209
Wale Ogunwale1666e312016-12-16 11:27:18 -0800210 appWindow.removeImmediately();
Andrii Kulian4ede3e02017-01-12 11:52:31 -0800211 }
Bryce Lee310de9e2017-03-15 10:18:21 -0700212
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800213 private void performRotation(DisplayRotation spiedRotation, int rotationToReport) {
214 doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt());
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700215 mWm.updateRotation(false, false);
Bryce Lee310de9e2017-03-15 10:18:21 -0700216 }
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700217
218 @Test
Andrii Kulian6b3a3712017-11-02 11:06:47 -0700219 @Presubmit
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700220 public void testGetOrientation() {
Issei Suzukif2f6c912019-11-08 11:24:18 +0100221 mActivity.setVisible(true);
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200222
Garfield Tane8d84ab2019-10-11 09:49:40 -0700223 mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700224
Garfield Tane8d84ab2019-10-11 09:49:40 -0700225 mActivity.setOccludesParent(false);
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700226 // Can specify orientation if app doesn't occludes parent.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700227 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mActivity.getOrientation());
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700228
Garfield Tane8d84ab2019-10-11 09:49:40 -0700229 mActivity.setOccludesParent(true);
Issei Suzukif2f6c912019-11-08 11:24:18 +0100230 mActivity.setVisible(false);
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700231 // Can not specify orientation if app isn't visible even though it occludes parent.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700232 assertEquals(SCREEN_ORIENTATION_UNSET, mActivity.getOrientation());
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700233 // Can specify orientation if the current orientation candidate is orientation behind.
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +0900234 assertEquals(SCREEN_ORIENTATION_LANDSCAPE,
Garfield Tane8d84ab2019-10-11 09:49:40 -0700235 mActivity.getOrientation(SCREEN_ORIENTATION_BEHIND));
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700236 }
Bryce Lee081554b2017-05-25 07:52:12 -0700237
238 @Test
Andrii Kulian6b3a3712017-11-02 11:06:47 -0700239 @Presubmit
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700240 public void testKeyguardFlagsDuringRelaunch() {
Bryce Lee081554b2017-05-25 07:52:12 -0700241 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
242 TYPE_BASE_APPLICATION);
243 attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD;
244 attrs.setTitle("AppWindow");
Garfield Tane8d84ab2019-10-11 09:49:40 -0700245 final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mActivity);
Bryce Lee081554b2017-05-25 07:52:12 -0700246
247 // Add window with show when locked flag
Garfield Tane8d84ab2019-10-11 09:49:40 -0700248 mActivity.addWindow(appWindow);
249 assertTrue(mActivity.containsShowWhenLockedWindow() && mActivity.containsDismissKeyguardWindow());
Bryce Lee081554b2017-05-25 07:52:12 -0700250
251 // Start relaunching
Garfield Tane8d84ab2019-10-11 09:49:40 -0700252 mActivity.startRelaunching();
253 assertTrue(mActivity.containsShowWhenLockedWindow() && mActivity.containsDismissKeyguardWindow());
Bryce Lee081554b2017-05-25 07:52:12 -0700254
255 // Remove window and make sure that we still report back flag
Garfield Tane8d84ab2019-10-11 09:49:40 -0700256 mActivity.removeChild(appWindow);
257 assertTrue(mActivity.containsShowWhenLockedWindow() && mActivity.containsDismissKeyguardWindow());
Bryce Lee081554b2017-05-25 07:52:12 -0700258
259 // Finish relaunching and ensure flag is now not reported
Garfield Tane8d84ab2019-10-11 09:49:40 -0700260 mActivity.finishRelaunching();
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +0900261 assertFalse(
Garfield Tane8d84ab2019-10-11 09:49:40 -0700262 mActivity.containsShowWhenLockedWindow() || mActivity.containsDismissKeyguardWindow());
Bryce Lee081554b2017-05-25 07:52:12 -0700263 }
Jorim Jaggiab9fcb22018-03-15 23:46:12 +0100264
265 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700266 public void testStuckExitingWindow() {
Jorim Jaggiab9fcb22018-03-15 23:46:12 +0100267 final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
268 "closingWindow");
269 closingWindow.mAnimatingExit = true;
270 closingWindow.mRemoveOnExit = true;
Issei Suzuki2bcbd682019-11-08 13:20:14 +0100271 closingWindow.mActivityRecord.commitVisibility(
272 false /* visible */, true /* performLayout */);
Jorim Jaggiab9fcb22018-03-15 23:46:12 +0100273
274 // We pretended that we were running an exit animation, but that should have been cleared up
Garfield Tane8d84ab2019-10-11 09:49:40 -0700275 // by changing visibility of ActivityRecord
Jorim Jaggiab9fcb22018-03-15 23:46:12 +0100276 closingWindow.removeIfPossible();
277 assertTrue(closingWindow.mRemoved);
278 }
Riddle Hsua118b3a2018-10-11 22:05:06 +0800279
280 @Test
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800281 public void testSetOrientation() {
Issei Suzukif2f6c912019-11-08 11:24:18 +0100282 mActivity.setVisible(true);
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200283
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800284 // Assert orientation is unspecified to start.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700285 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mActivity.getOrientation());
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800286
Garfield Tane8d84ab2019-10-11 09:49:40 -0700287 mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
288 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mActivity.getOrientation());
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800289
Garfield Tane8d84ab2019-10-11 09:49:40 -0700290 mDisplayContent.removeAppToken(mActivity.token);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800291 // Assert orientation is unset to after container is removed.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700292 assertEquals(SCREEN_ORIENTATION_UNSET, mActivity.getOrientation());
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800293
294 // Reset display frozen state
295 mWm.mDisplayFrozen = false;
296 }
297
298 @Test
Riddle Hsu0c1b0d12020-05-27 23:15:39 +0800299 public void testRespectTopFullscreenOrientation() {
300 final Configuration displayConfig = mActivity.mDisplayContent.getConfiguration();
301 final Configuration activityConfig = mActivity.getConfiguration();
302 mActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
303
304 assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation);
305 assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation);
306
307 final ActivityRecord topActivity = WindowTestUtils.createTestActivityRecord(mStack);
308 topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
309
310 assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation);
311 // Although the activity requested portrait, it is not the top activity that determines
312 // the display orientation. So it should be able to inherit the orientation from parent.
313 // Otherwise its configuration will be inconsistent that its orientation is portrait but
314 // other screen configurations are in landscape, e.g. screenWidthDp, screenHeightDp, and
315 // window configuration.
316 assertEquals(Configuration.ORIENTATION_LANDSCAPE, activityConfig.orientation);
317 }
318
319 @Test
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800320 public void testReportOrientationChange() {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700321 mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
Garfield Tanb6776602019-02-20 14:44:26 -0800322
Riddle Hsu73f53572019-09-23 23:13:01 +0800323 mDisplayContent.getDisplayRotation().setFixedToUserRotation(
Garfield Tana3f19032019-11-19 18:04:50 -0800324 IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200325 reset(mTask);
Garfield Tane8d84ab2019-10-11 09:49:40 -0700326 mActivity.reportDescendantOrientationChangeIfNeeded();
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200327 verify(mTask).onConfigurationChanged(any(Configuration.class));
Garfield Tanb6776602019-02-20 14:44:26 -0800328 }
329
330 @Test
Jeff Chang3b19efb2019-05-14 19:21:00 +0800331 @FlakyTest(bugId = 131176283)
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800332 public void testCreateRemoveStartingWindow() {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700333 mActivity.addStartingWindow(mPackageName,
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800334 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
Riddle Hsueae6ef3e2020-05-13 01:07:33 +0800335 false);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800336 waitUntilHandlersIdle();
Garfield Tane8d84ab2019-10-11 09:49:40 -0700337 assertHasStartingWindow(mActivity);
338 mActivity.removeStartingWindow();
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800339 waitUntilHandlersIdle();
Garfield Tane8d84ab2019-10-11 09:49:40 -0700340 assertNoStartingWindow(mActivity);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800341 }
342
343 @Test
344 public void testAddRemoveRace() {
345 // There was once a race condition between adding and removing starting windows
Yunfan Chen4c6a8fc2020-05-13 14:47:38 +0900346 final ActivityRecord appToken = mAppWindow.mActivityRecord;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800347 for (int i = 0; i < 1000; i++) {
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800348 appToken.addStartingWindow(mPackageName,
349 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
Riddle Hsueae6ef3e2020-05-13 01:07:33 +0800350 false);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800351 appToken.removeStartingWindow();
352 waitUntilHandlersIdle();
353 assertNoStartingWindow(appToken);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800354 }
355 }
356
357 @Test
358 public void testTransferStartingWindow() {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700359 final ActivityRecord activity1 = createIsolatedTestActivityRecord();
360 final ActivityRecord activity2 = createIsolatedTestActivityRecord();
361 activity1.addStartingWindow(mPackageName,
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800362 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
Riddle Hsueae6ef3e2020-05-13 01:07:33 +0800363 false);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800364 waitUntilHandlersIdle();
Garfield Tane8d84ab2019-10-11 09:49:40 -0700365 activity2.addStartingWindow(mPackageName,
366 android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
Riddle Hsueae6ef3e2020-05-13 01:07:33 +0800367 true, true, false, true, false);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800368 waitUntilHandlersIdle();
Garfield Tane8d84ab2019-10-11 09:49:40 -0700369 assertNoStartingWindow(activity1);
370 assertHasStartingWindow(activity2);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800371 }
372
373 @Test
374 public void testTransferStartingWindowWhileCreating() {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700375 final ActivityRecord activity1 = createIsolatedTestActivityRecord();
376 final ActivityRecord activity2 = createIsolatedTestActivityRecord();
377 ((TestWindowManagerPolicy) activity1.mWmService.mPolicy).setRunnableWhenAddingSplashScreen(
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800378 () -> {
379 // Surprise, ...! Transfer window in the middle of the creation flow.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700380 activity2.addStartingWindow(mPackageName,
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800381 android.R.style.Theme, null, "Test", 0, 0, 0, 0,
Garfield Tane8d84ab2019-10-11 09:49:40 -0700382 activity1.appToken.asBinder(), true, true, false,
Riddle Hsueae6ef3e2020-05-13 01:07:33 +0800383 true, false);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800384 });
Garfield Tane8d84ab2019-10-11 09:49:40 -0700385 activity1.addStartingWindow(mPackageName,
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800386 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
Riddle Hsueae6ef3e2020-05-13 01:07:33 +0800387 false);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800388 waitUntilHandlersIdle();
Garfield Tane8d84ab2019-10-11 09:49:40 -0700389 assertNoStartingWindow(activity1);
390 assertHasStartingWindow(activity2);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800391 }
392
wilsonshihca274ed2020-05-05 17:32:21 +0800393 @Test
394 public void testTransferStartingWindowCanAnimate() {
395 final ActivityRecord activity1 = createIsolatedTestActivityRecord();
396 final ActivityRecord activity2 = createIsolatedTestActivityRecord();
397 activity1.addStartingWindow(mPackageName,
398 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
Riddle Hsueae6ef3e2020-05-13 01:07:33 +0800399 false);
wilsonshihca274ed2020-05-05 17:32:21 +0800400 waitUntilHandlersIdle();
401 activity2.addStartingWindow(mPackageName,
402 android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
Riddle Hsueae6ef3e2020-05-13 01:07:33 +0800403 true, true, false, true, false);
wilsonshihca274ed2020-05-05 17:32:21 +0800404 waitUntilHandlersIdle();
405 assertNoStartingWindow(activity1);
406 assertHasStartingWindow(activity2);
407
408 // Assert that bottom activity is allowed to do animation.
Issei Suzuki737b7f12020-05-25 14:54:06 +0200409 ArrayList<WindowContainer> sources = new ArrayList<>();
410 sources.add(activity2);
wilsonshihca274ed2020-05-05 17:32:21 +0800411 doReturn(true).when(activity2).okToAnimate();
412 doReturn(true).when(activity2).isAnimating();
Issei Suzuki737b7f12020-05-25 14:54:06 +0200413 assertTrue(activity2.applyAnimation(null, TRANSIT_ACTIVITY_OPEN, true, false, sources));
wilsonshihca274ed2020-05-05 17:32:21 +0800414 }
415
Riddle Hsuffc12462020-05-27 17:43:25 +0800416 @Test
417 public void testTransferStartingWindowFromFinishingActivity() {
418 mActivity.addStartingWindow(mPackageName, android.R.style.Theme, null /* compatInfo */,
419 "Test", 0 /* labelRes */, 0 /* icon */, 0 /* logo */, 0 /* windowFlags */,
420 null /* transferFrom */, true /* newTask */, true /* taskSwitch */,
421 false /* processRunning */, false /* allowTaskSnapshot */,
422 false /* activityCreate */);
423 waitUntilHandlersIdle();
424 assertHasStartingWindow(mActivity);
425 mActivity.mStartingWindowState = ActivityRecord.STARTING_WINDOW_SHOWN;
426
427 doCallRealMethod().when(mStack).startActivityLocked(
428 any(), any(), anyBoolean(), anyBoolean(), any());
429 // Make mVisibleSetFromTransferredStartingWindow true.
430 final ActivityRecord middle = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
431 .setTask(mTask).build();
432 mStack.startActivityLocked(middle, null /* focusedTopActivity */,
433 false /* newTask */, false /* keepCurTransition */, null /* options */);
434 middle.makeFinishingLocked();
435
436 assertNull(mActivity.startingWindow);
437 assertHasStartingWindow(middle);
438
439 final ActivityRecord top = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
440 .setTask(mTask).build();
441 // Expect the visibility should be updated to true when transferring starting window from
442 // a visible activity.
443 top.setVisible(false);
444 // The finishing middle should be able to transfer starting window to top.
445 mStack.startActivityLocked(top, null /* focusedTopActivity */,
446 false /* newTask */, false /* keepCurTransition */, null /* options */);
447
448 assertNull(middle.startingWindow);
449 assertHasStartingWindow(top);
450 assertTrue(top.isVisible());
451 // The activity was visible by mVisibleSetFromTransferredStartingWindow, so after its
452 // starting window is transferred, it should restore to invisible.
453 assertFalse(middle.isVisible());
454 }
455
Louis Chang242be902020-06-03 12:24:45 +0800456 @Test
457 public void testTransferStartingWindowSetFixedRotation() {
458 mWm.mIsFixedRotationTransformEnabled = true;
459 final ActivityRecord topActivity = createTestActivityRecordForGivenTask(mTask);
460 mTask.positionChildAt(topActivity, POSITION_TOP);
461 mActivity.addStartingWindow(mPackageName,
462 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
463 false);
464 waitUntilHandlersIdle();
465
466 // Make activities to have different rotation from it display and set fixed rotation
467 // transform to activity1.
468 int rotation = (mDisplayContent.getRotation() + 1) % 4;
469 mDisplayContent.setFixedRotationLaunchingApp(mActivity, rotation);
470 doReturn(rotation).when(mDisplayContent)
471 .rotationForActivityInDifferentOrientation(topActivity);
472
473 // Make sure the fixed rotation transform linked to activity2 when adding starting window
474 // on activity2.
475 topActivity.addStartingWindow(mPackageName,
476 android.R.style.Theme, null, "Test", 0, 0, 0, 0, mActivity.appToken.asBinder(),
477 false, false, false, true, false);
478 waitUntilHandlersIdle();
479 assertTrue(topActivity.hasFixedRotationTransform());
480 }
481
Garfield Tane8d84ab2019-10-11 09:49:40 -0700482 private ActivityRecord createIsolatedTestActivityRecord() {
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -0700483 final ActivityStack taskStack = createTaskStackOnDisplay(mDisplayContent);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800484 final Task task = createTaskInStack(taskStack, 0 /* userId */);
Garfield Tane8d84ab2019-10-11 09:49:40 -0700485 return createTestActivityRecordForGivenTask(task);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800486 }
487
Garfield Tane8d84ab2019-10-11 09:49:40 -0700488 private ActivityRecord createTestActivityRecordForGivenTask(Task task) {
489 final ActivityRecord activity =
490 WindowTestUtils.createTestActivityRecord(mDisplayContent);
491 task.addChild(activity, 0);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800492 waitUntilHandlersIdle();
Garfield Tane8d84ab2019-10-11 09:49:40 -0700493 return activity;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800494 }
495
496 @Test
497 public void testTryTransferStartingWindowFromHiddenAboveToken() {
498 // Add two tasks on top of each other.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700499 final ActivityRecord activityTop = createIsolatedTestActivityRecord();
500 final ActivityRecord activityBottom =
501 createTestActivityRecordForGivenTask(activityTop.getTask());
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800502
503 // Add a starting window.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700504 activityTop.addStartingWindow(mPackageName,
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800505 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
Riddle Hsueae6ef3e2020-05-13 01:07:33 +0800506 false);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800507 waitUntilHandlersIdle();
508
509 // Make the top one invisible, and try transferring the starting window from the top to the
510 // bottom one.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700511 activityTop.setVisibility(false, false);
512 activityBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded();
Yunfan Chendcb1fcf2019-02-07 19:08:41 +0900513 waitUntilHandlersIdle();
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800514
515 // Assert that the bottom window now has the starting window.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700516 assertNoStartingWindow(activityTop);
517 assertHasStartingWindow(activityBottom);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800518 }
519
Evan Rosky641daea2019-04-24 14:45:24 -0700520 @Test
521 public void testTransitionAnimationBounds() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200522 removeGlobalMinSizeRestriction();
Evan Rosky641daea2019-04-24 14:45:24 -0700523 final Rect stackBounds = new Rect(0, 0, 1000, 600);
524 final Rect taskBounds = new Rect(100, 400, 600, 800);
Riddle Hsua71f8e02020-05-05 23:07:59 +0800525 // Set the bounds and windowing mode to window configuration directly, otherwise the
526 // testing setups may be discarded by configuration resolving.
527 mStack.getWindowConfiguration().setBounds(stackBounds);
528 mTask.getWindowConfiguration().setBounds(taskBounds);
529 mActivity.getWindowConfiguration().setBounds(taskBounds);
Evan Rosky641daea2019-04-24 14:45:24 -0700530
531 // Check that anim bounds for freeform window match task bounds
Riddle Hsua71f8e02020-05-05 23:07:59 +0800532 mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200533 assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_NONE));
Evan Rosky641daea2019-04-24 14:45:24 -0700534
535 // STACK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by
536 // bounds animation layer.
Riddle Hsua71f8e02020-05-05 23:07:59 +0800537 mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200538 assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM));
Evan Rosky641daea2019-04-24 14:45:24 -0700539
Riddle Hsua71f8e02020-05-05 23:07:59 +0800540 // Even the activity is smaller than task and it is not aligned to the top-left corner of
541 // task, the animation bounds the same as task and position should be zero because in real
542 // case the letterbox will fill the remaining area in task.
543 final Rect halfBounds = new Rect(taskBounds);
544 halfBounds.scale(0.5f);
545 mActivity.getWindowConfiguration().setBounds(halfBounds);
546 final Point animationPosition = new Point();
547 mActivity.getAnimationPosition(animationPosition);
548
549 assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM));
550 assertEquals(new Point(0, 0), animationPosition);
551
Evan Rosky641daea2019-04-24 14:45:24 -0700552 // STACK_CLIP_BEFORE_ANIM should use stack bounds since it won't be clipped later.
Riddle Hsua71f8e02020-05-05 23:07:59 +0800553 mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200554 assertEquals(mStack.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM));
Evan Rosky641daea2019-04-24 14:45:24 -0700555 }
556
Tarandeep Singh69ab1042019-07-30 13:30:03 -0700557 @Test
558 public void testHasStartingWindow() {
559 final WindowManager.LayoutParams attrs =
560 new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING);
Garfield Tane8d84ab2019-10-11 09:49:40 -0700561 final WindowTestUtils.TestWindowState startingWindow = createWindowState(attrs, mActivity);
562 mActivity.startingDisplayed = true;
563 mActivity.addWindow(startingWindow);
564 assertTrue("Starting window should be present", mActivity.hasStartingWindow());
565 mActivity.startingDisplayed = false;
566 assertTrue("Starting window should be present", mActivity.hasStartingWindow());
Tarandeep Singh69ab1042019-07-30 13:30:03 -0700567
Garfield Tane8d84ab2019-10-11 09:49:40 -0700568 mActivity.removeChild(startingWindow);
569 assertFalse("Starting window should not be present", mActivity.hasStartingWindow());
Tarandeep Singh69ab1042019-07-30 13:30:03 -0700570 }
571
Garfield Tane8d84ab2019-10-11 09:49:40 -0700572 private void assertHasStartingWindow(ActivityRecord atoken) {
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800573 assertNotNull(atoken.startingSurface);
chaviwa8f07a72019-05-01 16:25:39 -0700574 assertNotNull(atoken.mStartingData);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800575 assertNotNull(atoken.startingWindow);
576 }
577
Garfield Tane8d84ab2019-10-11 09:49:40 -0700578 private void assertNoStartingWindow(ActivityRecord atoken) {
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800579 assertNull(atoken.startingSurface);
580 assertNull(atoken.startingWindow);
chaviwa8f07a72019-05-01 16:25:39 -0700581 assertNull(atoken.mStartingData);
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800582 atoken.forAllWindows(windowState -> {
583 assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING);
584 }, true);
585 }
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700586}