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