AI2 Component  (Version nb184)
AppInventorCompatActivity.java
Go to the documentation of this file.
1 // -*- mode: java; c-basic-offset: 2; -*-
2 // Copyright 2018-2020 MIT, All rights reserved
3 // Released under the Apache License, Version 2.0
4 // http://www.apache.org/licenses/LICENSE-2.0
5 
6 package com.google.appinventor.components.runtime;
7 
8 import android.app.Activity;
9 import android.content.res.Configuration;
10 import android.graphics.drawable.ColorDrawable;
11 import android.os.Bundle;
12 import android.util.Log;
13 import android.view.Gravity;
14 import android.view.View;
15 import android.view.ViewGroup;
16 import android.view.Window;
17 import android.widget.FrameLayout.LayoutParams;
18 import android.widget.TextView;
19 import androidx.annotation.Nullable;
20 import androidx.appcompat.app.ActionBar;
21 import androidx.appcompat.app.AppCompatCallback;
22 import androidx.appcompat.app.AppCompatDelegate;
23 import androidx.appcompat.view.ActionMode;
24 import androidx.appcompat.view.ActionMode.Callback;
32 
40 public class AppInventorCompatActivity extends Activity implements AppCompatCallback {
41 
42  public enum Theme {
47  DARK
48  }
49 
50  private static final String LOG_TAG = AppInventorCompatActivity.class.getSimpleName();
51  static final int DEFAULT_PRIMARY_COLOR =
53  private static boolean classicMode = false;
54  private static boolean actionBarEnabled;
55  private static Theme currentTheme = Theme.PACKAGED;
56  private static int primaryColor;
57  private AppCompatDelegate appCompatDelegate;
58  android.widget.LinearLayout frameWithTitle;
59  TextView titleBar;
60  private static boolean didSetClassicModeFromYail = false;
61  @SuppressWarnings("WeakerAccess") // Potentially useful to extensions with custom activities
63 
64  @Override
65  public void onCreate(Bundle icicle) {
66  classicMode = classicMode || SdkLevel.getLevel() < SdkLevel.LEVEL_HONEYCOMB;
67  if (classicMode) {
70  // On Honeycomb, so requesting the ActionBar
73  actionBarEnabled = true;
74  } else {
75  // AppCompat libraries require minSdk 14 (Ice Cream Sandwich). Therefore, we only need to
76  // run this code if we are on Ice Cream Sandwich or higher and in a newer (i.e., non-Classic)
77  // theme.
79  if (currentTheme != Theme.PACKAGED) {
80  applyTheme();
81  }
82  appCompatDelegate = AppCompatDelegate.create(this, this);
83  appCompatDelegate.onCreate(icicle);
84  }
85 
86  super.onCreate(icicle);
87 
88  frameWithTitle = new android.widget.LinearLayout(this);
89  frameWithTitle.setOrientation(android.widget.LinearLayout.VERTICAL);
90  setContentView(frameWithTitle); // Due to a bug in Honeycomb 3.0 and 3.1, a content view must
91  // exist before attempting to check the ActionBar status,
92  // which is done indirectly via shouldCreateTitleBar()
93  actionBarEnabled = themeHelper.hasActionBar();
94  titleBar = (TextView) findViewById(android.R.id.title);
95  if (shouldCreateTitleBar()) {
96  titleBar = new TextView(this);
97  titleBar.setBackgroundResource(android.R.drawable.title_bar);
98  titleBar.setTextAppearance(this, android.R.style.TextAppearance_WindowTitle);
99  titleBar.setGravity(Gravity.CENTER_VERTICAL);
100  titleBar.setSingleLine();
101  titleBar.setShadowLayer(2, 0, 0, 0xBB000000);
103  // Since AppCompat requires SDK 14 or higher, all apps prior to that will receive the
104  // "classic" theme. However, if the app has a different theme then we will end up without
105  // a title bar even though isClassicMode() will return true. Here we add the title bar
106  // if we are the REPL and not in classic mode (so we can simulate Classic title bar) or
107  // on an older device regardless of theme.
108  frameWithTitle.addView(titleBar, new ViewGroup.LayoutParams(
109  ViewGroup.LayoutParams.MATCH_PARENT,
110  ViewGroup.LayoutParams.WRAP_CONTENT
111  ));
112  }
113  } else {
114  Log.d(LOG_TAG, "Already have a title bar (classic mode): " + titleBar);
115  }
116  }
117 
118  @SuppressWarnings("WeakerAccess")
119  public final boolean isAppCompatMode() {
120  return appCompatDelegate != null;
121  }
122 
123  @Override
124  protected void onPostCreate(Bundle savedInstanceState) {
125  super.onPostCreate(savedInstanceState);
126  if (appCompatDelegate != null) {
127  appCompatDelegate.onPostCreate(savedInstanceState);
128  }
129  }
130 
131  @Override
132  protected void onPostResume() {
133  super.onPostResume();
134  if (appCompatDelegate != null) {
135  appCompatDelegate.onPostResume();
136  }
137  }
138 
139  @Override
140  public void onConfigurationChanged(Configuration newConfig) {
141  super.onConfigurationChanged(newConfig);
142  if (appCompatDelegate != null) {
143  appCompatDelegate.onConfigurationChanged(newConfig);
144  }
145  }
146 
147  @Override
148  protected void onStop() {
149  super.onStop();
150  if (appCompatDelegate != null) {
151  appCompatDelegate.onStop();
152  }
153  }
154 
155  @Override
156  protected void onDestroy() {
157  super.onDestroy();
158  if (appCompatDelegate != null) {
159  appCompatDelegate.onDestroy();
160  }
161  }
162 
163  @Override
164  protected void onTitleChanged(CharSequence title, int color) {
165  super.onTitleChanged(title, color);
166  if (appCompatDelegate != null) {
167  appCompatDelegate.setTitle(title);
168  } else if (titleBar != null) {
169  titleBar.setText(title);
170  }
171  }
172 
173  @Override
174  public void onSupportActionModeStarted(ActionMode actionMode) {
175  // Do nothing
176  }
177 
178  @Override
179  public void onSupportActionModeFinished(ActionMode actionMode) {
180  // Do nothing
181  }
182 
183  @Nullable
184  @Override
185  public ActionMode onWindowStartingSupportActionMode(Callback callback) {
186  return null; // Let's Android decide best action
187  }
188 
189  @Override
190  public void setContentView(View view) {
191  // If we are a custom activity, wrap it in frameWithTitle for theme
192  if (view != frameWithTitle) {
193  frameWithTitle.addView(view, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
194  ViewGroup.LayoutParams.MATCH_PARENT));
195  view = frameWithTitle;
196  }
197 
198  // Update the content view based on AppCompat support
199  if (appCompatDelegate != null) {
200  appCompatDelegate.setContentView(view);
201  } else {
202  super.setContentView(view);
203  }
204  }
205 
206  @SuppressWarnings("WeakerAccess") // To maintain visibility compatibility with AppCompatActivity
207  public ActionBar getSupportActionBar() {
208  Window.Callback classicCallback = getWindow().getCallback();
209  try {
210  return appCompatDelegate == null ? null : appCompatDelegate.getSupportActionBar();
211  } catch (IllegalStateException e) {
212  // Thrown in "Classic" mode
213  appCompatDelegate = null;
214  AppInventorCompatActivity.classicMode = true;
215  getWindow().setCallback(classicCallback);
216  return null;
217  }
218  }
219 
220  public static boolean isEmulator() {
221  return android.os.Build.PRODUCT.contains("google_sdk") || // Old emulator build (2.x)
222  android.os.Build.PRODUCT.equals("sdk") || // Honeycomb image (for testing)
223  android.os.Build.PRODUCT.contains("sdk_gphone"); // New emulator build (3.x)
224  }
225 
226  @SuppressWarnings("unused") // Potentially useful for extensions adding custom activities
227  protected static boolean isActionBarEnabled() {
228  return actionBarEnabled;
229  }
230 
231  @SuppressWarnings("WeakerAccess")
232  protected void setActionBarEnabled(boolean enabled) {
233  actionBarEnabled = enabled;
234  }
235 
236  @SuppressWarnings("unused") // Potentially useful for extensions adding custom activities
237  public static boolean isClassicMode() {
238  return classicMode;
239  }
240 
241  @SuppressWarnings("WeakerAccess")
242  protected void setClassicMode(boolean classic) {
243  if (isRepl() && SdkLevel.getLevel() >= SdkLevel.LEVEL_HONEYCOMB) { // Only allow changes in REPL when running on a supported SDK level
244  classicMode = classic;
245  }
246  }
247 
248  protected static int getPrimaryColor() {
249  return primaryColor;
250  }
251 
252  @SuppressWarnings("WeakerAccess")
253  protected void setPrimaryColor(int color) {
254  final ActionBar actionBar = getSupportActionBar();
255  int newColor = color == Component.COLOR_DEFAULT ? DEFAULT_PRIMARY_COLOR : color;
256  if (actionBar != null && newColor != primaryColor) {
257  // Only make the change if we have to...
258  primaryColor = newColor;
259  actionBar.setBackgroundDrawable(new ColorDrawable(color));
260  }
261  }
262 
263  protected boolean isRepl() {
264  return false;
265  }
266 
267  @SuppressWarnings("WeakerAccess") // Potentially useful for extensions adding custom activities
268  protected void hideTitleBar() {
269  if (titleBar != null) {
270  if (titleBar.getParent() != frameWithTitle) {
271  if (titleBar.getParent() != null) {
272  ((View)titleBar.getParent()).setVisibility(View.GONE);
273  }
274  } else {
275  titleBar.setVisibility(View.GONE);
276  }
277  }
278  }
279 
280  protected void maybeShowTitleBar() {
281  if (titleBar != null) {
282  titleBar.setVisibility(View.VISIBLE);
283  Log.d(LOG_TAG, "titleBar visible");
284  if (titleBar.getParent() != null && titleBar.getParent() != frameWithTitle) {
285  Log.d(LOG_TAG, "Setting parent visible");
286  ((View) titleBar.getParent()).setVisibility(View.VISIBLE);
287  }
288  }
289  }
290 
291  @SuppressWarnings("WeakerAccess") // Potentially useful for extensions adding custom activities
292  protected void styleTitleBar() {
293  ActionBar actionBar = getSupportActionBar();
294  Log.d(LOG_TAG, "actionBarEnabled = " + actionBarEnabled);
295  Log.d(LOG_TAG, "!classicMode = " + !classicMode);
296  Log.d(LOG_TAG, "actionBar = " + actionBar);
297  if (actionBar != null) {
298  actionBar.setBackgroundDrawable(new ColorDrawable(getPrimaryColor()));
299  if (actionBarEnabled) {
300  actionBar.show();
301  hideTitleBar();
302  return;
303  } else {
304  actionBar.hide();
305  }
306  }
308  }
309 
310  @SuppressWarnings("WeakerAccess")
311  protected void setAppInventorTheme(Theme theme) {
312  if (!Form.getActiveForm().isRepl()) {
313  return; // Theme changing only allowed in REPL
314  }
315  if (theme == currentTheme) {
316  return;
317  }
318  currentTheme = theme;
319  applyTheme();
320  }
321 
322  private void applyTheme() {
323  Log.d(LOG_TAG, "applyTheme " + currentTheme);
324  setClassicMode(false);
325  switch (currentTheme) {
326  case CLASSIC:
327  setClassicMode(true);
328  setTheme(android.R.style.Theme);
329  break;
330  case DEVICE_DEFAULT:
331  case BLACK_TITLE_TEXT:
332  setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar);
333  break;
334  case DARK:
335  setTheme(android.R.style.Theme_DeviceDefault_NoActionBar);
336  break;
337  }
338  }
339 
340  private boolean shouldCreateTitleBar() {
342  return true;
343  } else if (titleBar == null && (isRepl() || classicMode)) {
344  return true;
345  }
346  return false;
347  }
348 
349  @SuppressWarnings("unused") // Called from YAIL
350  public static void setClassicModeFromYail(boolean newClassicMode) {
351  if (!didSetClassicModeFromYail) { // Check so we only do this once (from Screen1)
352  Log.d(LOG_TAG, "Setting classic mode from YAIL: " + newClassicMode);
353  classicMode = newClassicMode;
354  didSetClassicModeFromYail = true;
355  }
356  }
357 }
com.google.appinventor.components.runtime.Component.COLOR_DEFAULT
static final int COLOR_DEFAULT
Definition: Component.java:68
com.google.appinventor.components.runtime.AppInventorCompatActivity.onCreate
void onCreate(Bundle icicle)
Definition: AppInventorCompatActivity.java:65
com.google.appinventor.components.runtime.AppInventorCompatActivity.onDestroy
void onDestroy()
Definition: AppInventorCompatActivity.java:156
com.google.appinventor.components.runtime.util
-*- mode: java; c-basic-offset: 2; -*-
Definition: AccountChooser.java:7
com.google.appinventor.components.runtime.util.PaintUtil
Definition: PaintUtil.java:17
com.google.appinventor.components.runtime.AppInventorCompatActivity.onConfigurationChanged
void onConfigurationChanged(Configuration newConfig)
Definition: AppInventorCompatActivity.java:140
com.google.appinventor.components.runtime.AppInventorCompatActivity.onSupportActionModeStarted
void onSupportActionModeStarted(ActionMode actionMode)
Definition: AppInventorCompatActivity.java:174
com.google.appinventor.components
com.google.appinventor.components.runtime.AppInventorCompatActivity.onTitleChanged
void onTitleChanged(CharSequence title, int color)
Definition: AppInventorCompatActivity.java:164
com.google.appinventor.components.runtime.AppInventorCompatActivity.onWindowStartingSupportActionMode
ActionMode onWindowStartingSupportActionMode(Callback callback)
Definition: AppInventorCompatActivity.java:185
com.google.appinventor.components.runtime.AppInventorCompatActivity.onStop
void onStop()
Definition: AppInventorCompatActivity.java:148
com.google.appinventor.components.runtime.AppInventorCompatActivity.isAppCompatMode
final boolean isAppCompatMode()
Definition: AppInventorCompatActivity.java:119
com.google.appinventor.components.runtime.AppInventorCompatActivity.isEmulator
static boolean isEmulator()
Definition: AppInventorCompatActivity.java:220
com.google.appinventor.components.runtime.AppInventorCompatActivity.themeHelper
ThemeHelper themeHelper
Definition: AppInventorCompatActivity.java:62
com.google.appinventor.components.runtime.AppInventorCompatActivity.setClassicModeFromYail
static void setClassicModeFromYail(boolean newClassicMode)
Definition: AppInventorCompatActivity.java:350
com.google.appinventor.components.runtime.AppInventorCompatActivity.styleTitleBar
void styleTitleBar()
Definition: AppInventorCompatActivity.java:292
com.google.appinventor.components.runtime.AppInventorCompatActivity.getPrimaryColor
static int getPrimaryColor()
Definition: AppInventorCompatActivity.java:248
com.google.appinventor.components.common.ComponentConstants.DEFAULT_PRIMARY_COLOR
static final String DEFAULT_PRIMARY_COLOR
Definition: ComponentConstants.java:88
com.google.appinventor.components.runtime.util.theme.HoneycombThemeHelper
Definition: HoneycombThemeHelper.java:17
com.google.appinventor.components.runtime.util.theme.ClassicThemeHelper
Definition: ClassicThemeHelper.java:8
com.google.appinventor.components.runtime.AppInventorCompatActivity.maybeShowTitleBar
void maybeShowTitleBar()
Definition: AppInventorCompatActivity.java:280
com.google.appinventor.components.runtime.util.theme.ThemeHelper
Definition: ThemeHelper.java:8
com.google.appinventor.components.runtime.AppInventorCompatActivity.isRepl
boolean isRepl()
Definition: AppInventorCompatActivity.java:263
com.google.appinventor.components.runtime.AppInventorCompatActivity.setAppInventorTheme
void setAppInventorTheme(Theme theme)
Definition: AppInventorCompatActivity.java:311
com.google.appinventor.components.runtime.util.SdkLevel.LEVEL_HONEYCOMB
static final int LEVEL_HONEYCOMB
Definition: SdkLevel.java:28
com.google.appinventor.components.runtime.util.SdkLevel
Definition: SdkLevel.java:19
com.google.appinventor.components.runtime.AppInventorCompatActivity.setPrimaryColor
void setPrimaryColor(int color)
Definition: AppInventorCompatActivity.java:253
com.google.appinventor.components.runtime.util.SdkLevel.LEVEL_ICE_CREAM_SANDWICH
static final int LEVEL_ICE_CREAM_SANDWICH
Definition: SdkLevel.java:30
com.google.appinventor.components.runtime.util.theme.IceCreamSandwichThemeHelper
Definition: IceCreamSandwichThemeHelper.java:17
com.google.appinventor.components.runtime.AppInventorCompatActivity.Theme.PACKAGED
PACKAGED
Definition: AppInventorCompatActivity.java:43
com.google.appinventor.components.runtime.util.SdkLevel.getLevel
static int getLevel()
Definition: SdkLevel.java:45
com.google.appinventor.components.runtime
Copyright 2009-2011 Google, All Rights reserved.
Definition: AccelerometerSensor.java:8
com.google.appinventor.components.runtime.Component
Definition: Component.java:17
com.google.appinventor.components.runtime.util.theme
Definition: ClassicThemeHelper.java:6
com.google.appinventor.components.runtime.AppInventorCompatActivity.Theme.DEVICE_DEFAULT
DEVICE_DEFAULT
Definition: AppInventorCompatActivity.java:45
com.google.appinventor.components.runtime.AppInventorCompatActivity.getSupportActionBar
ActionBar getSupportActionBar()
Definition: AppInventorCompatActivity.java:207
com.google.appinventor.components.runtime.util.theme.ThemeHelper.hasActionBar
boolean hasActionBar()
com.google.appinventor.components.common
Definition: ComponentCategory.java:7
com.google.appinventor.components.runtime.AppInventorCompatActivity.Theme
Definition: AppInventorCompatActivity.java:42
com.google.appinventor.components.runtime.util.theme.ThemeHelper.requestActionBar
void requestActionBar()
com.google.appinventor.components.runtime.AppInventorCompatActivity.setContentView
void setContentView(View view)
Definition: AppInventorCompatActivity.java:190
com.google.appinventor.components.runtime.AppInventorCompatActivity.hideTitleBar
void hideTitleBar()
Definition: AppInventorCompatActivity.java:268
com.google.appinventor.components.runtime.AppInventorCompatActivity
Definition: AppInventorCompatActivity.java:40
com.google.appinventor.components.runtime.AppInventorCompatActivity.isActionBarEnabled
static boolean isActionBarEnabled()
Definition: AppInventorCompatActivity.java:227
com.google
com
com.google.appinventor.components.runtime.util.PaintUtil.hexStringToInt
static int hexStringToInt(String argb)
Definition: PaintUtil.java:45
com.google.appinventor.components.runtime.AppInventorCompatActivity.onPostCreate
void onPostCreate(Bundle savedInstanceState)
Definition: AppInventorCompatActivity.java:124
com.google.appinventor.components.runtime.AppInventorCompatActivity.isClassicMode
static boolean isClassicMode()
Definition: AppInventorCompatActivity.java:237
com.google.appinventor.components.runtime.AppInventorCompatActivity.setClassicMode
void setClassicMode(boolean classic)
Definition: AppInventorCompatActivity.java:242
com.google.appinventor.components.common.ComponentConstants
Definition: ComponentConstants.java:13
com.google.appinventor.components.runtime.AppInventorCompatActivity.onSupportActionModeFinished
void onSupportActionModeFinished(ActionMode actionMode)
Definition: AppInventorCompatActivity.java:179
com.google.appinventor.components.runtime.Form.getActiveForm
static Form getActiveForm()
Definition: Form.java:2181
com.google.appinventor.components.runtime.Form
Definition: Form.java:126
com.google.appinventor.components.runtime.AppInventorCompatActivity.Theme.BLACK_TITLE_TEXT
BLACK_TITLE_TEXT
Definition: AppInventorCompatActivity.java:46
com.google.appinventor.components.runtime.AppInventorCompatActivity.onPostResume
void onPostResume()
Definition: AppInventorCompatActivity.java:132
com.google.appinventor.components.runtime.AppInventorCompatActivity.Theme.CLASSIC
CLASSIC
Definition: AppInventorCompatActivity.java:44
com.google.appinventor
com.google.appinventor.components.runtime.AppInventorCompatActivity.setActionBarEnabled
void setActionBarEnabled(boolean enabled)
Definition: AppInventorCompatActivity.java:232