Commit f53b1656 authored by Evan W. Patton's avatar Evan W. Patton

Fix bugs related to ActionBar

This commit fixes two bugs:

1. NPE due to a race condition where clear() was called in the
   ReplForm before the FrameLayout was initialized.
2. setImageTintMode on an internal Widget wasn't supported on
   Android 4.x, resulting in a crash on connection.

Change-Id: Ia28f9eaa404fa0b8f830d5a809d77226a611b36c
parent 4b9aad2a
...@@ -2033,8 +2033,10 @@ public class Form extends AppCompatActivity ...@@ -2033,8 +2033,10 @@ public class Form extends AppCompatActivity
// This is called from clear-current-form in runtime.scm. // This is called from clear-current-form in runtime.scm.
public void clear() { public void clear() {
viewLayout.getLayoutManager().removeAllViews(); viewLayout.getLayoutManager().removeAllViews();
if (frameLayout != null) {
frameLayout.removeAllViews(); frameLayout.removeAllViews();
frameLayout = null; frameLayout = null;
}
// Set all screen properties to default values. // Set all screen properties to default values.
defaultPropertyValues(); defaultPropertyValues();
onStopListeners.clear(); onStopListeners.clear();
......
...@@ -30,6 +30,7 @@ import com.google.appinventor.components.annotations.SimpleProperty; ...@@ -30,6 +30,7 @@ import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.common.ComponentConstants; import com.google.appinventor.components.common.ComponentConstants;
import com.google.appinventor.components.runtime.util.AppInvHTTPD; import com.google.appinventor.components.runtime.util.AppInvHTTPD;
import com.google.appinventor.components.runtime.util.ErrorMessages; import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.ImageViewUtil;
import com.google.appinventor.components.runtime.util.RetValManager; import com.google.appinventor.components.runtime.util.RetValManager;
import dalvik.system.DexClassLoader; import dalvik.system.DexClassLoader;
...@@ -64,7 +65,6 @@ public class ReplForm extends Form { ...@@ -64,7 +65,6 @@ public class ReplForm extends Form {
private String replResultFormName = null; private String replResultFormName = null;
private List<String> loadedExternalDexs; // keep a track of loaded dexs to prevent reloading and causing crash in older APIs private List<String> loadedExternalDexs; // keep a track of loaded dexs to prevent reloading and causing crash in older APIs
private String currentTheme = ComponentConstants.DEFAULT_THEME; private String currentTheme = ComponentConstants.DEFAULT_THEME;
private TintImageView overflowMenuView = null;
public ReplForm() { public ReplForm() {
super(); super();
...@@ -331,42 +331,15 @@ public class ReplForm extends Form { ...@@ -331,42 +331,15 @@ public class ReplForm extends Form {
protected void updateTitle() { protected void updateTitle() {
final ActionBar actionBar = getSupportActionBar(); final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) { if (actionBar != null) {
findOverflowMenuView();
ColorStateList stateList;
if ("AppTheme.Light".equals(currentTheme)) { if ("AppTheme.Light".equals(currentTheme)) {
actionBar.setTitle(Html.fromHtml("<font color=\"black\">" + title + "</font>")); actionBar.setTitle(Html.fromHtml("<font color=\"black\">" + title + "</font>"));
stateList = new ColorStateList(new int[][] { new int[] {} }, new int[] { Color.BLACK }); ImageViewUtil.setMenuButtonColor(this, Color.BLACK);
} else { } else {
actionBar.setTitle(title); actionBar.setTitle(title);
stateList = new ColorStateList(new int[][] { new int[] {} }, new int[] { Color.WHITE }); ImageViewUtil.setMenuButtonColor(this, Color.WHITE);
} }
if (overflowMenuView != null) {
overflowMenuView.setImageTintMode(PorterDuff.Mode.MULTIPLY);
overflowMenuView.setImageTintList(stateList);
} }
} }
}
private TintImageView findOverflowMenuView() {
if (overflowMenuView == null) {
ViewGroup vg = (ViewGroup) getWindow().getDecorView();
Queue<ViewGroup> children = new LinkedList<ViewGroup>();
children.add(vg);
while (children.size() > 0) {
vg = children.poll();
for (int i = 0; i < vg.getChildCount(); i++) {
View child = vg.getChildAt(i);
if (child instanceof TintImageView) {
overflowMenuView = (TintImageView) child;
return overflowMenuView;
} else if (child instanceof ViewGroup) {
children.add((ViewGroup) child);
}
}
}
}
return overflowMenuView;
}
private String genReportId() { private String genReportId() {
String [] words = { "A","ABE","ACE","ACT","AD","ADA","ADD", String [] words = { "A","ABE","ACE","ACT","AD","ADA","ADD",
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2017 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime.util;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.internal.widget.TintImageView;
import android.view.View;
import android.view.ViewGroup;
import java.util.LinkedList;
import java.util.Queue;
public final class ImageViewUtil {
/**
* We will determine when this class is first referenced whether we can update the color of
* the menu button. If true, we will attempt to update. Otherwise, the button will get out of
* sync, but this will only happen in the companion so it shouldn't be too much of a problem.
*/
private static final boolean canUpdate;
static {
boolean updateable = false;
try {
TintImageView.class.getMethod("setImageTintMode", PorterDuff.Mode.class);
updateable = true;
} catch(NoSuchMethodException e) {
}
canUpdate = updateable;
}
private ImageViewUtil() {}
public static void setMenuButtonColor(AppCompatActivity activity, int color) {
if (canUpdate) {
TintImageView overflowMenuView = findOverflowMenuView(activity);
if (overflowMenuView != null) {
ColorStateList stateList = new ColorStateList(new int[][]{new int[]{}}, new int[]{color});
try {
overflowMenuView.setImageTintMode(PorterDuff.Mode.MULTIPLY);
overflowMenuView.setImageTintList(stateList);
} catch (NoSuchMethodError e) {
// extra insurance in case the canUpdate flag is lying...
}
}
}
}
private static TintImageView findOverflowMenuView(AppCompatActivity activity) {
TintImageView overflowMenuView = null;
ViewGroup vg = (ViewGroup) activity.getWindow().getDecorView();
Queue<ViewGroup> children = new LinkedList<ViewGroup>();
children.add(vg);
while (children.size() > 0) {
vg = children.poll();
for (int i = 0; i < vg.getChildCount(); i++) {
View child = vg.getChildAt(i);
if (child instanceof TintImageView) {
overflowMenuView = (TintImageView) child;
return overflowMenuView;
} else if (child instanceof ViewGroup) {
children.add((ViewGroup) child);
}
}
}
return overflowMenuView;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment