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 
17 package androidx.appcompat.testutils;
18 
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.os.Bundle;
22 import android.view.ContextThemeWrapper;
23 import android.view.KeyEvent;
24 import android.view.Menu;
25 import android.view.MenuItem;
26 import android.view.WindowManager;
27 
28 import androidx.appcompat.app.AppCompatCallback;
29 import androidx.appcompat.test.R;
30 import androidx.appcompat.view.ActionMode;
31 import androidx.testutils.LocaleTestUtils;
32 import androidx.testutils.RecreatedAppCompatActivity;
33 
34 import org.jspecify.annotations.NonNull;
35 import org.jspecify.annotations.Nullable;
36 
37 import java.util.Locale;
38 
39 public abstract class BaseTestActivity extends RecreatedAppCompatActivity {
40     private static Locale sOverrideLocale;
41 
42     private Menu mMenu;
43 
44     private KeyEvent mOnKeyDownEvent;
45     private KeyEvent mOnKeyUpEvent;
46     private KeyEvent mOnKeyShortcutEvent;
47 
48     private MenuItem mOptionsItemSelected;
49 
50     private boolean mOnMenuOpenedCalled;
51     private boolean mOnPanelClosedCalled;
52 
53     private boolean mShouldPopulateOptionsMenu = true;
54 
55     private boolean mOnBackPressedCalled;
56     private boolean mDestroyed;
57 
58     private AppCompatCallback mAppCompatCallback;
59 
60     @Override
onCreate(Bundle savedInstanceState)61     protected void onCreate(Bundle savedInstanceState) {
62         super.onCreate(savedInstanceState);
63 
64         overridePendingTransition(0, 0);
65         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
66         final int contentView = getContentViewLayoutResId();
67         if (contentView > 0) {
68             setContentView(contentView);
69         }
70         onContentViewSet();
71         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
72     }
73 
74     /**
75      * Recreates the activity with an RTL locale.
76      */
setRtlOneShotAndRecreate()77     public void setRtlOneShotAndRecreate() {
78         sOverrideLocale = new Locale(LocaleTestUtils.RTL_LANGUAGE);
79         recreate();
80     }
81 
82     /**
83      * Clears any specified one-shot RTL override.
84      */
resetRtlOneShot()85     public void resetRtlOneShot() {
86         sOverrideLocale = null;
87     }
88 
89     @Override
attachBaseContext(Context newBase)90     protected void attachBaseContext(Context newBase) {
91         if (sOverrideLocale != null) {
92             Configuration overrideConfig = new Configuration();
93             overrideConfig.fontScale = 0;
94             overrideConfig.locale = sOverrideLocale;
95 
96             ContextThemeWrapper wrappedBase = new ContextThemeWrapper(
97                     newBase, R.style.Theme_AppCompat_Empty);
98             wrappedBase.applyOverrideConfiguration(overrideConfig);
99 
100             newBase = wrappedBase;
101 
102             sOverrideLocale = null;
103         }
104 
105         super.attachBaseContext(newBase);
106     }
107 
108     @Override
finish()109     public void finish() {
110         super.finish();
111         overridePendingTransition(0, 0);
112     }
113 
getContentViewLayoutResId()114     protected abstract int getContentViewLayoutResId();
115 
onContentViewSet()116     protected void onContentViewSet() {
117     }
118 
119     @Override
onOptionsItemSelected(MenuItem item)120     public boolean onOptionsItemSelected(MenuItem item) {
121         mOptionsItemSelected = item;
122         return super.onOptionsItemSelected(item);
123     }
124 
125     @Override
onMenuOpened(int featureId, Menu menu)126     public boolean onMenuOpened(int featureId, Menu menu) {
127         mOnMenuOpenedCalled = true;
128         return super.onMenuOpened(featureId, menu);
129     }
130 
131     @Override
onPanelClosed(int featureId, Menu menu)132     public void onPanelClosed(int featureId, Menu menu) {
133         mOnPanelClosedCalled = true;
134         super.onPanelClosed(featureId, menu);
135     }
136 
137     @Override
onKeyDown(int keyCode, KeyEvent event)138     public boolean onKeyDown(int keyCode, KeyEvent event) {
139         mOnKeyDownEvent = event;
140         return super.onKeyDown(keyCode, event);
141     }
142 
143     @Override
onKeyUp(int keyCode, KeyEvent event)144     public boolean onKeyUp(int keyCode, KeyEvent event) {
145         mOnKeyUpEvent = event;
146         return super.onKeyUp(keyCode, event);
147     }
148 
149     @Override
onKeyShortcut(int keyCode, KeyEvent event)150     public boolean onKeyShortcut(int keyCode, KeyEvent event) {
151         mOnKeyShortcutEvent = event;
152         return super.onKeyShortcut(keyCode, event);
153     }
154 
getInvokedKeyShortcutEvent()155     public KeyEvent getInvokedKeyShortcutEvent() {
156         return mOnKeyShortcutEvent;
157     }
158 
wasOnMenuOpenedCalled()159     public boolean wasOnMenuOpenedCalled() {
160         return mOnMenuOpenedCalled;
161     }
162 
wasOnPanelClosedCalled()163     public boolean wasOnPanelClosedCalled() {
164         return mOnPanelClosedCalled;
165     }
166 
getInvokedKeyDownEvent()167     public KeyEvent getInvokedKeyDownEvent() {
168         return mOnKeyDownEvent;
169     }
170 
getInvokedKeyUpEvent()171     public KeyEvent getInvokedKeyUpEvent() {
172         return mOnKeyUpEvent;
173     }
174 
175     @Override
onCreateOptionsMenu(Menu menu)176     public boolean onCreateOptionsMenu(Menu menu) {
177         mMenu = menu;
178         if (mShouldPopulateOptionsMenu) {
179             getMenuInflater().inflate(R.menu.sample_actions, menu);
180             return true;
181         } else {
182             menu.clear();
183             return super.onCreateOptionsMenu(menu);
184         }
185     }
186 
getOptionsItemSelected()187     public MenuItem getOptionsItemSelected() {
188         return mOptionsItemSelected;
189     }
190 
reset()191     public void reset() {
192         mOnKeyUpEvent = null;
193         mOnKeyDownEvent = null;
194         mOnKeyShortcutEvent = null;
195         mOnMenuOpenedCalled = false;
196         mOnPanelClosedCalled = false;
197         mMenu = null;
198         mOptionsItemSelected = null;
199     }
200 
setShouldPopulateOptionsMenu(boolean populate)201     public void setShouldPopulateOptionsMenu(boolean populate) {
202         mShouldPopulateOptionsMenu = populate;
203         if (mMenu != null) {
204             supportInvalidateOptionsMenu();
205         }
206     }
207 
208     @Override
onDestroy()209     protected void onDestroy() {
210         super.onDestroy();
211         mDestroyed = true;
212     }
213 
214     @SuppressWarnings("deprecation")
215     @Override
onBackPressed()216     public void onBackPressed() {
217         super.onBackPressed();
218         mOnBackPressedCalled = true;
219     }
220 
wasOnBackPressedCalled()221     public boolean wasOnBackPressedCalled() {
222         return mOnBackPressedCalled;
223     }
224 
getMenu()225     public Menu getMenu() {
226         return mMenu;
227     }
228 
229     @Override
isDestroyed()230     public boolean isDestroyed() {
231         return mDestroyed;
232     }
233 
234     @Override
onSupportActionModeStarted(@onNull ActionMode mode)235     public void onSupportActionModeStarted(@NonNull ActionMode mode) {
236         if (mAppCompatCallback != null) {
237             mAppCompatCallback.onSupportActionModeStarted(mode);
238         }
239     }
240 
241     @Override
onSupportActionModeFinished(@onNull ActionMode mode)242     public void onSupportActionModeFinished(@NonNull ActionMode mode) {
243         if (mAppCompatCallback != null) {
244             mAppCompatCallback.onSupportActionModeFinished(mode);
245         }
246     }
247 
248     @Override
onWindowStartingSupportActionMode( ActionMode.@onNull Callback callback)249     public @Nullable ActionMode onWindowStartingSupportActionMode(
250             ActionMode.@NonNull Callback callback) {
251         if (mAppCompatCallback != null) {
252             return mAppCompatCallback.onWindowStartingSupportActionMode(callback);
253         }
254         return super.onWindowStartingSupportActionMode(callback);
255     }
256 
setAppCompatCallback(AppCompatCallback callback)257     public void setAppCompatCallback(AppCompatCallback callback) {
258         mAppCompatCallback = callback;
259     }
260 }
261