7 package com.google.appinventor.components.runtime;
9 import android.graphics.drawable.RippleDrawable;
10 import android.os.Build;
24 import android.view.MotionEvent;
25 import android.content.res.ColorStateList;
26 import android.graphics.Color;
27 import android.graphics.drawable.Drawable;
28 import android.graphics.drawable.ShapeDrawable;
29 import android.graphics.drawable.shapes.OvalShape;
30 import android.graphics.drawable.shapes.RectShape;
31 import android.graphics.drawable.shapes.RoundRectShape;
32 import android.graphics.PorterDuff;
33 import android.util.Log;
34 import android.view.View;
35 import android.view.View.OnClickListener;
36 import android.view.View.OnFocusChangeListener;
37 import android.view.View.OnLongClickListener;
39 import java.io.IOException;
46 @UsesPermissions(permissionNames =
"android.permission.INTERNET")
48 implements OnClickListener, OnFocusChangeListener, OnLongClickListener, View.OnTouchListener {
50 private static final String LOG_TAG =
"ButtonBase";
52 private final android.widget.Button view;
57 private static final float ROUNDED_CORNERS_RADIUS = 10f;
58 private static final float[] ROUNDED_CORNERS_ARRAY =
new float[] { ROUNDED_CORNERS_RADIUS,
59 ROUNDED_CORNERS_RADIUS, ROUNDED_CORNERS_RADIUS, ROUNDED_CORNERS_RADIUS,
60 ROUNDED_CORNERS_RADIUS, ROUNDED_CORNERS_RADIUS, ROUNDED_CORNERS_RADIUS,
61 ROUNDED_CORNERS_RADIUS };
64 private static final int SHAPED_DEFAULT_BACKGROUND_COLOR = Color.LTGRAY;
67 private int textAlignment;
70 private int backgroundColor;
73 private int fontTypeface;
79 private boolean showFeedback=
true;
82 private boolean italic;
85 private int textColor;
91 private String imagePath =
"";
94 private Drawable defaultButtonDrawable;
96 private Drawable myBackgroundDrawable =
null;
99 private ColorStateList defaultColorStateList;
104 private Drawable backgroundImageDrawable;
111 private static int defaultButtonMinWidth = 0;
118 private static int defaultButtonMinHeight = 0;
127 view =
new android.widget.Button(container.
$context());
130 defaultButtonDrawable = view.getBackground();
131 defaultColorStateList = view.getTextColors();
136 container.
$add(
this);
139 view.setOnClickListener(
this);
140 view.setOnFocusChangeListener(
this);
141 view.setOnLongClickListener(
this);
142 view.setOnTouchListener(
this);
169 public boolean onTouch(View view, MotionEvent me) {
172 if (me.getAction() == MotionEvent.ACTION_DOWN) {
175 view.getBackground().setAlpha(70);
179 }
else if (me.getAction() == MotionEvent.ACTION_UP ||
180 me.getAction() == MotionEvent.ACTION_CANCEL) {
183 view.getBackground().setAlpha(255);
200 @
SimpleEvent(description =
"Indicates that the %type% was pressed down.")
201 public
void TouchDown() {
208 @
SimpleEvent(description =
"Indicates that the %type% has been released.")
209 public
void TouchUp() {
217 @
SimpleEvent(description =
"Indicates the cursor moved over the %type% so " +
218 "it is now possible to click it.")
219 public
void GotFocus() {
227 @
SimpleEvent(description =
"Indicates the cursor moved away from " +
228 "the %type% so it is now no longer possible to click it.")
229 public
void LostFocus() {
244 description =
"Left, center, or right.",
246 public
int TextAlignment() {
247 return textAlignment;
263 public
void TextAlignment(
int alignment) {
264 this.textAlignment = alignment;
300 @
SimpleProperty(description =
"Specifies the shape of the %type% (default, rounded," +
301 " rectangular, oval). The shape will not be visible if an Image is being displayed.",
303 public
void Shape(
int shape) {
315 description =
"Image to display on button.")
332 @
SimpleProperty(description =
"Specifies the path of the image of the %type%. " +
333 "If there is both an Image and a BackgroundColor, only the Image will be " +
338 if (path.equals(imagePath) && backgroundImageDrawable !=
null) {
342 imagePath = (path ==
null) ?
"" : path;
345 backgroundImageDrawable =
null;
348 if (imagePath.length() > 0) {
351 }
catch (IOException ioe) {
353 Log.e(LOG_TAG,
"Unable to load " + imagePath);
370 description =
"Returns the button's background color")
373 return backgroundColor;
388 @
SimpleProperty(description =
"Specifies the background color of the %type%. " +
389 "The background color will not be visible if an Image is being displayed.")
390 public
void BackgroundColor(
int argb) {
391 backgroundColor = argb;
397 private void updateAppearance() {
400 if (backgroundImageDrawable ==
null) {
406 }
else if (backgroundColor == Component.COLOR_NONE) {
408 ViewUtil.setBackgroundDrawable(view,
null);
410 ViewUtil.setBackgroundDrawable(view, getSafeBackgroundDrawable());
411 view.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.CLEAR);
414 ViewUtil.setBackgroundDrawable(view,
null);
416 ViewUtil.setBackgroundDrawable(view, getSafeBackgroundDrawable());
418 view.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.SRC_ATOP);
425 TextViewUtil.setMinSize(view, defaultButtonMinWidth, defaultButtonMinHeight);
428 ViewUtil.setBackgroundImage(view, backgroundImageDrawable);
429 TextViewUtil.setMinSize(view, 0, 0);
433 private Drawable getSafeBackgroundDrawable() {
434 if (myBackgroundDrawable ==
null) {
435 Drawable.ConstantState state = defaultButtonDrawable.getConstantState();
436 if (state !=
null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
438 myBackgroundDrawable = state.newDrawable().mutate();
439 }
catch (NullPointerException e) {
442 Log.e(LOG_TAG,
"Unable to clone button drawable", e);
443 myBackgroundDrawable = defaultButtonDrawable;
447 myBackgroundDrawable = defaultButtonDrawable;
450 return myBackgroundDrawable;
453 private ColorStateList createRippleState () {
455 int[][] states =
new int[][] {
new int[] { android.R.attr.state_enabled} };
456 int enabled_color = defaultColorStateList.getColorForState(view.getDrawableState(), android.R.attr.state_enabled);
457 int[] colors =
new int[] { Color.argb(70, Color.red(enabled_color), Color.green(enabled_color),
458 Color.blue(enabled_color)) };
460 return new ColorStateList(states, colors);
464 private void setShape() {
465 ShapeDrawable drawable =
new ShapeDrawable();
469 case Component.BUTTON_SHAPE_ROUNDED:
470 drawable.setShape(
new RoundRectShape(ROUNDED_CORNERS_ARRAY,
null,
null));
472 case Component.BUTTON_SHAPE_RECT:
473 drawable.setShape(
new RectShape());
475 case Component.BUTTON_SHAPE_OVAL:
476 drawable.setShape(
new OvalShape());
479 throw new IllegalArgumentException();
483 if (!AppInventorCompatActivity.isClassicMode() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
484 ViewUtil.setBackgroundDrawable(view,
new RippleDrawable(createRippleState(), drawable, drawable));
486 ViewUtil.setBackgroundDrawable(view, drawable);
489 if (backgroundColor == Component.COLOR_NONE) {
490 view.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.CLEAR);
492 else if (backgroundColor == Component.COLOR_DEFAULT) {
493 view.getBackground().setColorFilter(SHAPED_DEFAULT_BACKGROUND_COLOR, PorterDuff.Mode.SRC_ATOP);
496 view.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.SRC_ATOP);
508 category = PropertyCategory.BEHAVIOR,
509 description =
"If set, user can tap %type% to cause action.")
510 public
boolean Enabled() {
520 defaultValue =
"True")
535 description =
"If set, %type% text is displayed in bold.")
536 public
boolean FontBold() {
547 defaultValue =
"False")
550 public
void FontBold(
boolean bold) {
563 defaultValue =
"True")
564 @
SimpleProperty(description =
"Specifies if a visual feedback should be shown " +
565 " for a %type% that has an image as background.")
567 public
void ShowFeedback(
boolean showFeedback) {
568 this.showFeedback =showFeedback;
582 description =
"Returns the visual feedback state of the %type%")
583 public
boolean ShowFeedback() {
596 description =
"If set, %type% text is displayed in italics.")
597 public
boolean FontItalic() {
608 defaultValue =
"False")
611 public
void FontItalic(
boolean italic) {
612 this.italic = italic;
626 description =
"Point size for %type% text.")
627 public
float FontSize() {
640 public
void FontSize(
float size) {
655 description =
"Font family for %type% text.",
657 public
int FontTypeface() {
674 public
void FontTypeface(
int typeface) {
675 fontTypeface = typeface;
686 description =
"Text to display on %type%.")
687 public String Text() {
699 public void Text(String text) {
711 description =
"Color for button text.")
736 public abstract void click();