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.internal.policy;
18
19import android.test.ActivityInstrumentationTestCase2;
20import android.test.UiThreadTest;
21import android.view.ActionMode;
22import android.view.ActionMode.Callback;
23import android.view.KeyEvent;
24import android.view.Menu;
25import android.view.MenuInflater;
26import android.view.MenuItem;
27import android.view.MotionEvent;
28import android.view.SearchEvent;
29import android.view.View;
30import android.view.Window;
31import android.view.WindowManager.LayoutParams;
32import android.view.accessibility.AccessibilityEvent;
33
34/**
35 * Tests {@link PhoneWindow}'s {@link ActionMode} related methods.
36 */
37public final class PhoneWindowActionModeTest
38        extends ActivityInstrumentationTestCase2<PhoneWindowActionModeTestActivity> {
39
40    private PhoneWindow mPhoneWindow;
41    private MockWindowCallback mWindowCallback;
42    private MockActionModeCallback mActionModeCallback;
43
44    public PhoneWindowActionModeTest() {
45        super(PhoneWindowActionModeTestActivity.class);
46    }
47
48    @Override
49    protected void setUp() throws Exception {
50        super.setUp();
51        mPhoneWindow = (PhoneWindow) getActivity().getWindow();
52        mWindowCallback = new MockWindowCallback();
53        mPhoneWindow.setCallback(mWindowCallback);
54        mActionModeCallback = new MockActionModeCallback();
55    }
56
57    public void testStartActionModeWithCallback() {
58        mWindowCallback.mShouldReturnOwnActionMode = true;
59
60        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
61                mActionModeCallback, ActionMode.TYPE_FLOATING);
62
63        assertEquals(mWindowCallback.mLastCreatedActionMode, mode);
64    }
65
66    public void testStartActionModePrimaryFinishesPreviousMode() {
67        // Use custom callback to control the provided ActionMode.
68        mWindowCallback.mShouldReturnOwnActionMode = true;
69
70        ActionMode mode1 = mPhoneWindow.getDecorView().startActionMode(
71                mActionModeCallback, ActionMode.TYPE_PRIMARY);
72        ActionMode mode2 = mPhoneWindow.getDecorView().startActionMode(
73                mActionModeCallback, ActionMode.TYPE_PRIMARY);
74
75        assertTrue(mode1 instanceof MockActionMode);
76        assertTrue(((MockActionMode) mode1).mIsFinished);
77        assertNotNull(mode2);
78    }
79
80    public void testStartActionModeFloatingFinishesPreviousMode() {
81        // Use custom callback to control the provided ActionMode.
82        mWindowCallback.mShouldReturnOwnActionMode = true;
83
84        ActionMode mode1 = mPhoneWindow.getDecorView().startActionMode(
85                mActionModeCallback, ActionMode.TYPE_FLOATING);
86        ActionMode mode2 = mPhoneWindow.getDecorView().startActionMode(
87                mActionModeCallback, ActionMode.TYPE_FLOATING);
88
89        assertTrue(mode1 instanceof MockActionMode);
90        assertTrue(((MockActionMode) mode1).mIsFinished);
91        assertNotNull(mode2);
92    }
93
94    public void testStartActionModePreservesPreviousModeOfDifferentType1() {
95        // Use custom callback to control the provided ActionMode.
96        mWindowCallback.mShouldReturnOwnActionMode = true;
97
98        ActionMode mode1 = mPhoneWindow.getDecorView().startActionMode(
99                mActionModeCallback, ActionMode.TYPE_FLOATING);
100        ActionMode mode2 = mPhoneWindow.getDecorView().startActionMode(
101                mActionModeCallback, ActionMode.TYPE_PRIMARY);
102
103        assertTrue(mode1 instanceof MockActionMode);
104        assertFalse(((MockActionMode) mode1).mIsFinished);
105        assertNotNull(mode2);
106    }
107
108    public void testStartActionModePreservesPreviousModeOfDifferentType2() {
109        // Use custom callback to control the provided ActionMode.
110        mWindowCallback.mShouldReturnOwnActionMode = true;
111
112        ActionMode mode1 = mPhoneWindow.getDecorView().startActionMode(
113                mActionModeCallback, ActionMode.TYPE_PRIMARY);
114        ActionMode mode2 = mPhoneWindow.getDecorView().startActionMode(
115                mActionModeCallback, ActionMode.TYPE_FLOATING);
116
117        assertTrue(mode1 instanceof MockActionMode);
118        assertFalse(((MockActionMode) mode1).mIsFinished);
119        assertNotNull(mode2);
120    }
121
122    public void testWindowCallbackModesLifecycleIsNotHandled() {
123        mWindowCallback.mShouldReturnOwnActionMode = true;
124
125        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
126                mActionModeCallback, ActionMode.TYPE_PRIMARY);
127
128        assertNotNull(mode);
129        assertEquals(mWindowCallback.mLastCreatedActionMode, mode);
130        assertFalse(mActionModeCallback.mIsCreateActionModeCalled);
131        assertTrue(mWindowCallback.mIsActionModeStarted);
132    }
133
134    @UiThreadTest
135    public void testCreatedPrimaryModeLifecycleIsHandled() {
136        mWindowCallback.mShouldReturnOwnActionMode = false;
137
138        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
139                mActionModeCallback, ActionMode.TYPE_PRIMARY);
140
141        assertNotNull(mode);
142        assertEquals(ActionMode.TYPE_PRIMARY, mode.getType());
143        assertTrue(mActionModeCallback.mIsCreateActionModeCalled);
144        assertTrue(mWindowCallback.mIsActionModeStarted);
145    }
146
147    @UiThreadTest
148    public void testCreatedFloatingModeLifecycleIsHandled() {
149        mWindowCallback.mShouldReturnOwnActionMode = false;
150
151        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
152                mActionModeCallback, ActionMode.TYPE_FLOATING);
153
154        assertNotNull(mode);
155        assertEquals(ActionMode.TYPE_FLOATING, mode.getType());
156        assertTrue(mActionModeCallback.mIsCreateActionModeCalled);
157        assertTrue(mWindowCallback.mIsActionModeStarted);
158    }
159
160    @UiThreadTest
161    public void testCreatedModeIsNotStartedIfCreateReturnsFalse() {
162        mWindowCallback.mShouldReturnOwnActionMode = false;
163        mActionModeCallback.mShouldCreateActionMode = false;
164
165        ActionMode mode = mPhoneWindow.getDecorView().startActionMode(
166                mActionModeCallback, ActionMode.TYPE_FLOATING);
167
168        assertTrue(mActionModeCallback.mIsCreateActionModeCalled);
169        assertFalse(mWindowCallback.mIsActionModeStarted);
170        assertNull(mode);
171    }
172
173    private static final class MockWindowCallback implements Window.Callback {
174        private boolean mShouldReturnOwnActionMode = false;
175        private MockActionMode mLastCreatedActionMode;
176        private boolean mIsActionModeStarted = false;
177
178        @Override
179        public boolean dispatchKeyEvent(KeyEvent event) {
180            return false;
181        }
182
183        @Override
184        public boolean dispatchKeyShortcutEvent(KeyEvent event) {
185            return false;
186        }
187
188        @Override
189        public boolean dispatchTouchEvent(MotionEvent event) {
190            return false;
191        }
192
193        @Override
194        public boolean dispatchTrackballEvent(MotionEvent event) {
195            return false;
196        }
197
198        @Override
199        public boolean dispatchGenericMotionEvent(MotionEvent event) {
200            return false;
201        }
202
203        @Override
204        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
205            return false;
206        }
207
208        @Override
209        public View onCreatePanelView(int featureId) {
210            return null;
211        }
212
213        @Override
214        public boolean onCreatePanelMenu(int featureId, Menu menu) {
215            return false;
216        }
217
218        @Override
219        public boolean onPreparePanel(int featureId, View view, Menu menu) {
220            return false;
221        }
222
223        @Override
224        public boolean onMenuOpened(int featureId, Menu menu) {
225            return false;
226        }
227
228        @Override
229        public boolean onMenuItemSelected(int featureId, MenuItem item) {
230            return false;
231        }
232
233        @Override
234        public void onWindowAttributesChanged(LayoutParams attrs) {}
235
236        @Override
237        public void onContentChanged() {}
238
239        @Override
240        public void onWindowFocusChanged(boolean hasFocus) {}
241
242        @Override
243        public void onAttachedToWindow() {}
244
245        @Override
246        public void onDetachedFromWindow() {}
247
248        @Override
249        public void onPanelClosed(int featureId, Menu menu) {}
250
251        @Override
252        public boolean onSearchRequested() {
253            return false;
254        }
255
256        @Override
257        public boolean onSearchRequested(SearchEvent searchEvent) {
258            return false;
259        }
260
261        @Override
262        public ActionMode onWindowStartingActionMode(Callback callback) {
263            if (mShouldReturnOwnActionMode) {
264                MockActionMode mode = new MockActionMode();
265                mLastCreatedActionMode = mode;
266                return mode;
267            }
268            return null;
269        }
270
271        @Override
272        public ActionMode onWindowStartingActionMode(Callback callback, int type) {
273            if (mShouldReturnOwnActionMode) {
274                MockActionMode mode = new MockActionMode();
275                mode.mActionModeType = type;
276                mLastCreatedActionMode = mode;
277                return mode;
278            }
279            return null;
280        }
281
282        @Override
283        public void onActionModeStarted(ActionMode mode) {
284            mIsActionModeStarted = true;
285        }
286
287        @Override
288        public void onActionModeFinished(ActionMode mode) {}
289    }
290
291    private static final class MockActionModeCallback implements ActionMode.Callback {
292        private boolean mShouldCreateActionMode = true;
293        private boolean mIsCreateActionModeCalled = false;
294
295        @Override
296        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
297            return true;
298        }
299
300        @Override
301        public void onDestroyActionMode(ActionMode mode) {}
302
303        @Override
304        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
305            mIsCreateActionModeCalled = true;
306            return mShouldCreateActionMode;
307        }
308
309        @Override
310        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
311            return false;
312        }
313    }
314
315    private static final class MockActionMode extends ActionMode {
316        private int mActionModeType = ActionMode.TYPE_PRIMARY;
317        private boolean mIsFinished = false;
318
319        @Override
320        public int getType() {
321            return mActionModeType;
322        }
323
324        @Override
325        public void setTitle(CharSequence title) {}
326
327        @Override
328        public void setTitle(int resId) {}
329
330        @Override
331        public void setSubtitle(CharSequence subtitle) {}
332
333        @Override
334        public void setSubtitle(int resId) {}
335
336        @Override
337        public void setCustomView(View view) {}
338
339        @Override
340        public void invalidate() {}
341
342        @Override
343        public void finish() {
344            mIsFinished = true;
345        }
346
347        @Override
348        public Menu getMenu() {
349            return null;
350        }
351
352        @Override
353        public CharSequence getTitle() {
354            return null;
355        }
356
357        @Override
358        public CharSequence getSubtitle() {
359            return null;
360        }
361
362        @Override
363        public View getCustomView() {
364            return null;
365        }
366
367        @Override
368        public MenuInflater getMenuInflater() {
369            return null;
370        }
371    }
372}
373