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