code: public static void open(@NonNull Context context,
                              Config config,
                              String activityName) {
          synchronized (Sift.class) {
              if (instance == null) {
                  Context c = context.getApplicationContext();
                  instance = new SiftImpl(c, config, unboundUserId, hasUnboundUserId);
                  devicePropertiesCollector = new DevicePropertiesCollector(instance, c);
                  appStateCollector = new AppStateCollector(instance, c);
                  unboundUserId = null;
                  hasUnboundUserId = false;
              } else {
                  if (config != null) {
                      instance.setConfig(config);
                  }
              }
          }
  
          appStateCollector.setActivityName(activityName == null ?
                  context.getClass().getSimpleName() : activityName);
      }
docs: Call Sift.open() in the onCreate() callback of each Activity.
  
  Creates the Sift singleton and collectors if they do not exist,
  and passes along the current Activity context.
  
  For your application's main Activity, make sure to provide a Sift.Config
  object as the second parameter.
  
  If you are integrating per-Activity rather than at the Application level,
  you can specify the name that will be associated with each Activity event
  (defaults to the class name of the embedding Activity).
  
  There are overloaded methods below for your convenience.
  
  @param context the Activity context
  @param config the Sift.Config object
  @param activityName the Activity