AI2 Component  (Version nb184)
FirebaseDB.java
Go to the documentation of this file.
1 // -*- mode: java; c-basic-offset: 2; -*-
2 // Copyright 2015-2017 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 
9 import android.app.Activity;
10 import android.os.Handler;
11 import android.util.Log;
12 
13 import com.firebase.client.AuthData;
14 import com.firebase.client.ChildEventListener;
15 import com.firebase.client.Config;
16 import com.firebase.client.DataSnapshot;
17 import com.firebase.client.Firebase;
18 import com.firebase.client.FirebaseError;
19 import com.firebase.client.MutableData;
20 import com.firebase.client.Transaction;
21 import com.firebase.client.ValueEventListener;
22 
39 
40 import java.util.concurrent.atomic.AtomicReference;
41 import java.util.ArrayList;
42 import java.util.HashMap;
43 import java.util.List;
44 
45 import org.json.JSONException;
46 
47 
62 @DesignerComponent(version = YaVersion.FIREBASE_COMPONENT_VERSION,
63  description = "Non-visible component that communicates with Firebase to store and " +
64  "retrieve information.",
65  designerHelpDescription = "Non-visible component that communicates with a Firebase" +
66  " to store and retrieve information.",
67  category = ComponentCategory.EXPERIMENTAL,
68  nonVisible = true,
69  androidMinSdk = 10,
70  iconName = "images/firebaseDB.png")
71 @SimpleObject
72 @UsesPermissions(permissionNames = "android.permission.INTERNET")
73 @UsesLibraries(libraries = "firebase.jar")
74 public class FirebaseDB extends AndroidNonvisibleComponent implements Component {
75 
76  private static final String LOG_TAG = "Firebase";
77  private String firebaseURL = null;
78  private String defaultURL = null;
79  private boolean useDefault = true;
80  private String developerBucket;
81  private String projectBucket;
82  private String firebaseToken;
83  // Note: The two variables below are static because the systems they
84  // interact with within Firebase are also static
85  private static boolean isInitialized = false; // Whether we have made our first
86  // connection to Firebase
87  private static boolean persist = false; // Whether or not we are in persistant mode
88  // where variables are kept when an app exits
89  // when off-line
90  private Handler androidUIHandler;
91  private final Activity activity;
92  private Firebase myFirebase;
93  private ChildEventListener childListener;
94  private Firebase.AuthStateListener authListener;
95 
96  // ReturnVal -- Holder which can be used as a final value but whose content
97  // remains mutable.
98  private static class ReturnVal {
99  String err; // Holder for any errors
100  Object retval; // Returned value
101 
102  Object getRetval() {
103  return retval;
104  }
105 
106  }
107 
108  private abstract static class Transactional {
109  final Object arg1;
110  final Object arg2;
111  final ReturnVal retv;
112 
113  Transactional(Object arg1, Object arg2, ReturnVal retv) {
114  this.arg1 = arg1;
115  this.arg2 = arg2;
116  this.retv = retv;
117  }
118 
119  abstract Transaction.Result run(MutableData currentData);
120 
121  ReturnVal getResult() {
122  return retv;
123  }
124 
125  }
126 
132  public FirebaseDB(ComponentContainer container) {
133  super(container.$form());
134  // We use androidUIHandler when we set up operations that run asynchronously
135  // in a separate thread, but which themselves want to cause actions
136  // back in the UI thread. They do this by posting those actions
137  // to androidUIHandler.
138  androidUIHandler = new Handler();
139  this.activity = container.$context();
140  Firebase.setAndroidContext(activity);
141 
142  developerBucket = ""; // set dynamically in the Designer
143  projectBucket = ""; // given a dynamic default value in the Designer
144  firebaseToken = ""; // set dynamically in the Designer
145 
146  childListener = new ChildEventListener() {
147  // Retrieve new posts as they are added to the Firebase.
148  @Override
149  public void onChildAdded(final DataSnapshot snapshot, String previousChildKey) {
150  androidUIHandler.post(new Runnable() {
151  public void run() {
152  // Signal an event to indicate that the child data was changed.
153  // We post this to run in the Application's main UI thread.
154  DataChanged(snapshot.getKey(), snapshot.getValue());
155  }
156  });
157  }
158 
159  @Override
160  public void onCancelled(final FirebaseError error) {
161  androidUIHandler.post(new Runnable() {
162  public void run() {
163  // Signal an event to indicate that an error occurred.
164  // We post this to run in the Application's main UI thread.
165  FirebaseError(error.getMessage());
166  }
167  });
168  }
169 
170  @Override
171  public void onChildChanged(final DataSnapshot snapshot, String previousChildKey) {
172  androidUIHandler.post(new Runnable() {
173  public void run() {
174  // Signal an event to indicate that the child data was changed.
175  // We post this to run in the Application's main UI thread.
176  DataChanged(snapshot.getKey(), snapshot.getValue());
177  }
178  });
179  }
180 
181  @Override
182  public void onChildMoved(DataSnapshot snapshot, String previousChildKey) {
183  }
184 
185  @Override
186  public void onChildRemoved(final DataSnapshot snapshot) {
187  Log.i(LOG_TAG, "onChildRemoved: " + snapshot.getKey() + " removed.");
188  // We do *NOT* run the code below because triggering an event
189  // with a null argument causes problems in App Inventor programs
190  // If people need to know when a child is removed, we should add
191  // a new event which only takes the tag as a parameter
192  // androidUIHandler.post(new Runnable() {
193  // public void run() {
194  // // Signal an event to indicate that the child data was changed.
195  // // We post this to run in the Application's main UI thread.
196  // DataChanged(snapshot.getKey(), null);
197  // }
198  // });
199  }
200  };
201 
202  authListener = new Firebase.AuthStateListener() {
203  @Override
204  public void onAuthStateChanged(AuthData data) {
205  Log.i(LOG_TAG, "onAuthStateChanged: data = " + data);
206  if (data == null) {
207  myFirebase.authWithCustomToken(firebaseToken, new Firebase.AuthResultHandler() {
208  @Override
209  public void onAuthenticated(AuthData authData) {
210  Log.i(LOG_TAG, "Auth Successful.");
211  }
212 
213  @Override
214  public void onAuthenticationError(FirebaseError error) {
215  Log.e(LOG_TAG, "Auth Failed: " + error.getMessage());
216  }
217  });
218  }
219  }
220  };
221  }
222 
235  public void Initialize() {
236  Log.i(LOG_TAG, "Initalize called!");
237  isInitialized = true;
238  resetListener();
239  }
240 
247  description = "Gets the URL for this FirebaseDB.",
248  userVisible = false)
249  public String FirebaseURL() {
250  if (useDefault) {
251  return "DEFAULT";
252  } else {
253  return firebaseURL;
254  }
255  }
256 
266  defaultValue = "DEFAULT")
267  @SimpleProperty(description = "Sets the URL for this FirebaseDB.")
268  public void FirebaseURL(String url) {
269  if (url.equals("DEFAULT")) {
270  if (!useDefault) { // If we weren't setup for the default
271  useDefault = true;
272  if (defaultURL == null) { // Not setup yet
273  Log.d(LOG_TAG, "FirebaseURL called before DefaultURL (should not happen!)");
274  } else {
275  firebaseURL = defaultURL;
276  resetListener();
277  }
278  } else {
279  firebaseURL = defaultURL; // Should already be the case
280  }
281  } else {
282  useDefault = false;
283  url = url + (url.endsWith("/") ? "" : "/");
284 
285  if (firebaseURL.equals(url)) {
286  return; // Nothing to do
287  } else {
288  firebaseURL = url;
289  useDefault = false;
290  resetListener();
291  }
292  }
293  }
294 
307  public void DeveloperBucket(String bucket) {
308  developerBucket = bucket;
309  resetListener();
310  }
311 
317  @SimpleProperty(category = PropertyCategory.BEHAVIOR, userVisible = false)
318  public String DeveloperBucket() {
319  return developerBucket;
320  }
321 
328  defaultValue = "")
329  @SimpleProperty(description = "Sets the ProjectBucket for this FirebaseDB.")
330  public void ProjectBucket(String bucket) {
331  if (!projectBucket.equals(bucket)) {
332  projectBucket = bucket;
333  resetListener();
334  }
335  }
336 
343  description = "Gets the ProjectBucket for this FirebaseDB.")
344  public String ProjectBucket() {
345  return projectBucket;
346  }
347 
356  public void FirebaseToken(String JWT) {
357  firebaseToken = JWT;
358  resetListener();
359  }
360 
366  @SimpleProperty(category = PropertyCategory.BEHAVIOR, userVisible = false)
367  public String FirebaseToken() {
368  return firebaseToken;
369  }
370 
372  defaultValue = "False")
373  @SimpleProperty(userVisible = false,
374  description = "If true, variables will retain their values when off-line and the App " +
375  "exits. Values will be uploaded to Firebase the next time the App is " +
376  "run while connected to the network. This is useful for applications " +
377  "which will gather data while not connected to the network. Note: " +
378  "AppendValue and RemoveFirst will not work correctly when off-line, " +
379  "they require a network connection.<br/><br/> " +
380  "<i>Note</i>: If you set Persist on any Firebase component, on any " +
381  "screen, it makes all Firebase components on all screens persistent. " +
382  "This is a limitation of the low level Firebase library. Also be " +
383  "aware that if you want to set persist to true, you should do so " +
384  "before connecting the Companion for incremental development.")
385  public void Persist(boolean value) {
386  Log.i(LOG_TAG, "Persist Called: Value = " + value);
387  if (persist != value) { // We are making a change
388  if (isInitialized) {
389  throw new RuntimeException("You cannot change the Persist value of Firebase " +
390  "after Application Initialization, this includes the Companion");
391  }
392  Config config = Firebase.getDefaultConfig();
393  config.setPersistenceEnabled(value);
394  Firebase.setDefaultConfig(config);
395  persist = value;
396  resetListener();
397  }
398  }
399 
400  private void resetListener() {
401  // If Firebase has not been inialized, then
402  // we do nothing.
403  if (!isInitialized) {
404  return;
405  }
406  // remove listeners from the old Firebase path
407  if (myFirebase != null) {
408  myFirebase.removeEventListener(childListener);
409  myFirebase.removeAuthStateListener(authListener);
410  }
411 
412  myFirebase = null;
413  connectFirebase(); // Reconnect to Firebase with new parameters
414  }
415 
416  /*
417  TODO (William Byrne): Implement Transactions
418 
419  As things stand, any operation performed on a tag that depends on the
420  existing data at the tag is vulnerable to concurrent modification bugs.
421  This is caused by the inherent non-atomicity of such an operation using
422  the current component blocks. One way to solve this problem would be to
423  use the Firebase#runTransaction(Transaction.Handler) method to run such an
424  operation atomically. However, that entails either creating a RunTransaction
425  block that accepts both an operation to perform on the cloud variable and
426  additional data or creating individual blocks performing commonly needed
427  operations on cloud variables (e.g. increment, decrement, append to list, etc)
428  atomically. Since both of those solutions require involved implementations,
429  this issue is being left for Version 2.
430 
431  Additional Documentation relating to Firebase Transactions can be found below:
432 
433  https://www.firebase.com/docs/android/guide/saving-data.html#section-transactions
434 
435  https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/Transaction.html,
436 
437  https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/Transaction.Handler.html,
438 
439  https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/Firebase.html#runTransaction-com.firebase.client.Transaction.Handler-
440  */
441 
448  @SimpleFunction(description = "Remove the tag from Firebase")
449  public void ClearTag(final String tag) {
450  this.myFirebase.child(tag).removeValue();
451  }
452 
461  public void StoreValue(final String tag, Object valueToStore) {
462  try {
463  if(valueToStore != null) {
464  valueToStore = JsonUtil.getJsonRepresentation(valueToStore);
465  }
466  } catch(JSONException e) {
467  throw new YailRuntimeError("Value failed to convert to JSON.", "JSON Creation Error.");
468  }
469 
470  // perform the store operation
471  this.myFirebase.child(tag).setValue(valueToStore);
472  }
473 
484  public void GetValue(final String tag, final Object valueIfTagNotThere) {
485  this.myFirebase.child(tag).addListenerForSingleValueEvent(new ValueEventListener() {
486  @Override
487  public void onDataChange(final DataSnapshot snapshot) {
488  final AtomicReference<Object> value = new AtomicReference<Object>();
489 
490  // Set value to either the JSON from the Firebase
491  // or the JSON representation of valueIfTagNotThere
492  try {
493  if (snapshot.exists()) {
494  value.set(snapshot.getValue());
495  } else {
496  value.set(JsonUtil.getJsonRepresentation(valueIfTagNotThere));
497  }
498  } catch(JSONException e) {
499  throw new YailRuntimeError("Value failed to convert to JSON.", "JSON Creation Error.");
500  }
501 
502  androidUIHandler.post(new Runnable() {
503  public void run() {
504  // Signal an event to indicate that the value was
505  // received. We post this to run in the Application's main
506  // UI thread.
507  GotValue(tag, value.get());
508  }
509  });
510  }
511 
512  @Override
513  public void onCancelled(final FirebaseError error) {
514  androidUIHandler.post(new Runnable() {
515  public void run() {
516  // Signal an event to indicate that an error occurred.
517  // We post this to run in the Application's main
518  // UI thread.
519  FirebaseError(error.getMessage());
520  }
521  });
522  }
523  });
524  }
525 
532  @SimpleEvent
533  public void GotValue(String tag, Object value) {
534  try {
535  if(value != null && value instanceof String) {
536  value = JsonUtil.getObjectFromJson((String) value, true);
537  }
538  } catch(JSONException e) {
539  throw new YailRuntimeError("Value failed to convert from JSON.", "JSON Retrieval Error.");
540  }
541 
542  // Invoke the application's "GotValue" event handler
543  EventDispatcher.dispatchEvent(this, "GotValue", tag, value);
544  }
545 
553  @SimpleEvent
554  public void DataChanged(String tag, Object value) {
555  try {
556  if(value != null && value instanceof String) {
557  value = JsonUtil.getObjectFromJson((String) value, true);
558  }
559  } catch(JSONException e) {
560  throw new YailRuntimeError("Value failed to convert from JSON.", "JSON Retrieval Error.");
561  }
562 
563  // Invoke the application's "DataChanged" event handler
564  EventDispatcher.dispatchEvent(this, "DataChanged", tag, value);
565  }
566 
572  @SimpleEvent
573  public void FirebaseError(String message) {
574  // Log the error message for advanced developers
575  Log.e(LOG_TAG, message);
576 
577  // Invoke the application's "FirebaseError" event handler
578  boolean dispatched = EventDispatcher.dispatchEvent(this, "FirebaseError", message);
579  if (!dispatched) {
580  // If the handler doesn't exist, then put up our own alert
581  Notifier.oneButtonAlert(form, message, "FirebaseError", "Continue");
582  }
583  }
584 
585  private void connectFirebase() {
587  Notifier.oneButtonAlert(activity, "The version of Android on this device is too old to use Firebase.",
588  "Android Too Old", "OK");
589  return;
590  }
591  if(useDefault) {
592  myFirebase = new Firebase(firebaseURL + "developers/" + developerBucket + projectBucket);
593  } else {
594  myFirebase = new Firebase(firebaseURL + projectBucket);
595  }
596  // add listeners to the new Firebase path
597  myFirebase.addChildEventListener(childListener);
598  myFirebase.addAuthStateListener(authListener);
599  }
600 
621  @SimpleFunction(description = "If you are having difficulty with the Companion and you " +
622  "are switching between different Firebase accounts, you may need to use this function " +
623  "to clear internal Firebase caches. You can just use the \"Do It\" function on this block " +
624  "in the blocks editor. Note: You should not normally need to use this block as part of " +
625  "an application.")
626  public void Unauthenticate() {
627  if (myFirebase == null) {
628  connectFirebase();
629  }
630  myFirebase.unauth();
631  }
632 
633  // This is a non-documented property because it is hidden in the
634  // UI. Its purpose in life is to transmit the default firebase URL
635  // from the system into the Companion or packaged app. The Default
636  // URL is set in appengine-web.xml (the firebase.url property). It
637  // is sent to the client from the server via the system config call
638  // and sent hear from MockFirebaseDB.java
639 
642  userVisible = false)
643  public void DefaultURL(String url) {
644  defaultURL = url;
645  if (useDefault) {
646  firebaseURL = defaultURL;
647  resetListener();
648  }
649  }
650 
651  @SimpleFunction(description = "Return the first element of a list and atomically remove it. " +
652  "If two devices use this function simultaneously, one will get the first element and the " +
653  "the other will get the second element, or an error if there is no available element. " +
654  "When the element is available, the \"FirstRemoved\" event will be triggered.")
655  public void RemoveFirst(final String tag) {
656  final ReturnVal result = new ReturnVal();
657  Firebase firebaseChild = myFirebase.child(tag);
658  Transactional toRun = new Transactional(null, null, result) {
659  @Override
660  Transaction.Result run(MutableData currentData) {
661  Object value = currentData.getValue();
662  if (value == null) {
663  result.err = "Previous value was empty.";
664  return Transaction.abort();
665  }
666  try {
667  if (value instanceof String) {
668  value = JsonUtil.getObjectFromJson((String) value, true);
669  } else {
670  result.err = "Invalid JSON object in database (shouldn't happen!)";
671  return Transaction.abort();
672  }
673  } catch (JSONException e) {
674  result.err = "Invalid JSON object in database (shouldn't happen!)";
675  return Transaction.abort();
676  }
677  if (value instanceof List) {
678  if (((List)value).isEmpty()) {
679  result.err = "The list was empty";
680  return Transaction.abort();
681  }
682  result.retval = ((List)value).remove(0);
683  try {
684  value = JsonUtil.getJsonRepresentation(YailList.makeList((List)value));
685  } catch (JSONException e) {
686  result.err = "Could not convert value to JSON.";
687  return Transaction.abort();
688  }
689  currentData.setValue(value);
690  return Transaction.success(currentData);
691  } else {
692  result.err = "You can only remove elements from a list.";
693  return Transaction.abort();
694  }
695  }
696  };
697  firebaseTransaction(toRun, firebaseChild, new Runnable() {
698  @Override
699  public void run() {
700  FirstRemoved(result.getRetval());
701  }
702  });
703  }
704 
705  @SimpleFunction(description = "Get the list of tags for this application. " +
706  "When complete a \"TagList\" event will be triggered with the list of " +
707  "known tags.")
708  public void GetTagList() {
709  Firebase zFireBase = myFirebase.child(""); // Does this really clone the parent?
710  zFireBase.addListenerForSingleValueEvent(new ValueEventListener() {
711  @Override
712  public void onDataChange(DataSnapshot data) {
713  Object value = data.getValue();
714  if (value instanceof HashMap) {
715  value = new ArrayList(((HashMap)value).keySet());
716  final List listValue = (List) value;
717  androidUIHandler.post(new Runnable() {
718  @Override
719  public void run() {
720  TagList(listValue);
721  }
722  });
723  }
724  }
725  @Override
726  public void onCancelled(FirebaseError error) {
727  // Do Nothing
728  }
729  });
730  }
731 
732  @SimpleEvent(description = "Event triggered when we have received the list of known tags. " +
733  "Used with the \"GetTagList\" Function.")
734  public void TagList(List value) {
735  EventDispatcher.dispatchEvent(this, "TagList", value);
736  }
737 
738  @SimpleEvent(description = "Event triggered by the \"RemoveFirst\" function. The " +
739  "argument \"value\" is the object that was the first in the list, and which is now " +
740  "removed.")
741  public void FirstRemoved(Object value) {
742  EventDispatcher.dispatchEvent(this, "FirstRemoved", value);
743  }
744 
745  @SimpleFunction(description = "Append a value to the end of a list atomically. " +
746  "If two devices use this function simultaneously, both will be appended and no " +
747  "data lost.")
748  public void AppendValue(final String tag, final Object valueToAdd) {
749  final ReturnVal result = new ReturnVal();
750  Firebase firebaseChild = myFirebase.child(tag);
751  Transactional toRun = new Transactional(null, null, result) {
752  @Override
753  Transaction.Result run(MutableData currentData) {
754  Object value = currentData.getValue();
755  if (value == null) {
756  result.err = "Previous value was empty.";
757  return Transaction.abort();
758  }
759  try {
760  if (value instanceof String) {
761  value = JsonUtil.getObjectFromJson((String) value, true);
762  } else {
763  result.err = "Invalid JSON object in database (shouldn't happen!)";
764  return Transaction.abort();
765  }
766  } catch (JSONException e) {
767  result.err = "Invalid JSON object in database (shouldn't happen!)";
768  return Transaction.abort();
769  }
770  if (value instanceof List) {
771  ((List)value).add(valueToAdd);
772  try {
773  value = JsonUtil.getJsonRepresentation((List)value);
774  } catch (JSONException e) {
775  result.err = "Could not convert value to JSON.";
776  return Transaction.abort();
777  }
778  currentData.setValue(value);
779  return Transaction.success(currentData);
780  } else {
781  result.err = "You can only append to a list.";
782  return Transaction.abort();
783  }
784  }
785  };
786  firebaseTransaction(toRun, firebaseChild, null);
787  }
788 
789  private void firebaseTransaction(final Transactional toRun, Firebase firebase, final Runnable whenDone) {
790  final ReturnVal result = toRun.getResult();
791  firebase.runTransaction(new Transaction.Handler() {
792  @Override
793  public Transaction.Result doTransaction(MutableData currentData) {
794  return toRun.run(currentData);
795  }
796 
797  @Override
798  public void onComplete(final FirebaseError firebaseError, boolean committed,
799  DataSnapshot currentData) {
800  if (firebaseError != null) {
801  androidUIHandler.post(new Runnable() {
802  @Override
803  public void run() {
804  Log.i(LOG_TAG, "AppendValue(onComplete): firebase: " + firebaseError.getMessage());
805  Log.i(LOG_TAG, "AppendValue(onComplete): result.err: " + result.err);
806  FirebaseError(firebaseError.getMessage());
807  }
808  });
809  return;
810  }
811  if (!committed) {
812  androidUIHandler.post(new Runnable() {
813  @Override
814  public void run() {
815  Log.i(LOG_TAG, "AppendValue(!committed): result.err: " + result.err);
816  FirebaseError(result.err);
817  }
818  });
819  } else {
820  if (whenDone != null) {
821  androidUIHandler.post(whenDone);
822  }
823  }
824  return;
825  }
826  });
827  }
828 }
com.google.appinventor.components.runtime.EventDispatcher
Definition: EventDispatcher.java:22
com.google.appinventor.components.runtime.util.YailList
Definition: YailList.java:26
com.google.appinventor.components.runtime.FirebaseDB.StoreValue
void StoreValue(final String tag, Object valueToStore)
Definition: FirebaseDB.java:461
com.google.appinventor.components.annotations.SimpleFunction
Definition: SimpleFunction.java:23
com.google.appinventor.components.annotations.UsesLibraries
Definition: UsesLibraries.java:21
com.google.appinventor.components.runtime.util
-*- mode: java; c-basic-offset: 2; -*-
Definition: AccountChooser.java:7
com.google.appinventor.components.common.YaVersion
Definition: YaVersion.java:14
com.google.appinventor.components.annotations.DesignerProperty
Definition: DesignerProperty.java:25
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_STRING
static final String PROPERTY_TYPE_STRING
Definition: PropertyTypeConstants.java:237
com.google.appinventor.components
com.google.appinventor.components.runtime.FirebaseDB.GetValue
void GetValue(final String tag, final Object valueIfTagNotThere)
Definition: FirebaseDB.java:484
com.google.appinventor.components.runtime.util.YailList.makeList
static YailList makeList(Object[] objects)
Definition: YailList.java:59
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_FIREBASE_URL
static final String PROPERTY_TYPE_FIREBASE_URL
Definition: PropertyTypeConstants.java:310
com.google.appinventor.components.runtime.util.JsonUtil
Definition: JsonUtil.java:42
com.google.appinventor.components.common.PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN
static final String PROPERTY_TYPE_BOOLEAN
Definition: PropertyTypeConstants.java:35
com.google.appinventor.components.annotations.DesignerComponent
Definition: DesignerComponent.java:22
com.google.appinventor.components.annotations.SimpleEvent
Definition: SimpleEvent.java:20
com.google.appinventor.components.annotations.PropertyCategory.BEHAVIOR
BEHAVIOR
Definition: PropertyCategory.java:15
com.google.appinventor.components.runtime.FirebaseDB.DeveloperBucket
void DeveloperBucket(String bucket)
Definition: FirebaseDB.java:307
com.google.appinventor.components.runtime.FirebaseDB.DataChanged
void DataChanged(String tag, Object value)
Definition: FirebaseDB.java:554
com.google.appinventor.components.runtime.FirebaseDB.FirebaseError
void FirebaseError(String message)
Definition: FirebaseDB.java:573
com.google.appinventor.components.annotations.UsesPermissions
Definition: UsesPermissions.java:21
com.google.appinventor.components.runtime.Notifier
Definition: Notifier.java:78
com.google.appinventor.components.runtime.EventDispatcher.dispatchEvent
static boolean dispatchEvent(Component component, String eventName, Object...args)
Definition: EventDispatcher.java:188
com.google.appinventor.components.runtime.AndroidNonvisibleComponent
Definition: AndroidNonvisibleComponent.java:17
com.google.appinventor.components.runtime.util.SdkLevel
Definition: SdkLevel.java:19
com.google.appinventor.components.runtime.errors.YailRuntimeError
Definition: YailRuntimeError.java:14
com.google.appinventor.components.annotations.SimpleProperty
Definition: SimpleProperty.java:23
com.google.appinventor.components.annotations.PropertyCategory
Definition: PropertyCategory.java:13
com.google.appinventor.components.runtime.ComponentContainer
Definition: ComponentContainer.java:16
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.FirebaseDB.Initialize
void Initialize()
Definition: FirebaseDB.java:235
com.google.appinventor.components.common
Definition: ComponentCategory.java:7
com.google.appinventor.components.common.ComponentCategory
Definition: ComponentCategory.java:48
com.google.appinventor.components.runtime.FirebaseDB
Definition: FirebaseDB.java:74
com.google.appinventor.components.runtime.util.JsonUtil.getObjectFromJson
static Object getObjectFromJson(String jsonString)
Definition: JsonUtil.java:317
com.google.appinventor.components.runtime.FirebaseDB.GotValue
void GotValue(String tag, Object value)
Definition: FirebaseDB.java:533
com.google.appinventor.components.annotations.SimpleObject
Definition: SimpleObject.java:23
com.google
com.google.appinventor.components.runtime.util.SdkLevel.LEVEL_GINGERBREAD_MR1
static final int LEVEL_GINGERBREAD_MR1
Definition: SdkLevel.java:27
com
com.google.appinventor.components.runtime.FirebaseDB.FirebaseToken
void FirebaseToken(String JWT)
Definition: FirebaseDB.java:356
com.google.appinventor.components.runtime.errors
Definition: ArrayIndexOutOfBoundsError.java:7
com.google.appinventor.components.runtime.ComponentContainer.$form
Form $form()
com.google.appinventor.components.runtime.ComponentContainer.$context
Activity $context()
com.google.appinventor.components.runtime.Notifier.oneButtonAlert
static void oneButtonAlert(Activity activity, String message, String title, String buttonText, final Runnable callBack)
Definition: Notifier.java:164
com.google.appinventor.components.runtime.util.JsonUtil.getJsonRepresentation
static String getJsonRepresentation(Object value)
Definition: JsonUtil.java:246
com.google.appinventor.components.runtime.FirebaseDB.FirebaseDB
FirebaseDB(ComponentContainer container)
Definition: FirebaseDB.java:132
com.google.appinventor.components.common.PropertyTypeConstants
Definition: PropertyTypeConstants.java:14
com.google.appinventor.components.annotations
com.google.appinventor