/** * Wire * Copyright (C) 2016 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.waz.zclient; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.widget.Toast; import com.localytics.android.Localytics; import com.waz.api.BitmapCallback; import com.waz.api.ImageAsset; import com.waz.api.ImageAssetFactory; import com.waz.api.LoadHandle; import com.waz.api.Self; import com.waz.utils.wrappers.AndroidURIUtil; import com.waz.zclient.controllers.navigation.NavigationControllerObserver; import com.waz.zclient.controllers.navigation.Page; import com.waz.zclient.controllers.tracking.screens.ApplicationScreen; import com.waz.zclient.controllers.userpreferences.UserPreferencesController; import com.waz.zclient.core.api.scala.AppEntryStore; import com.waz.zclient.core.controllers.tracking.attributes.Attribute; import com.waz.zclient.core.controllers.tracking.attributes.RegistrationEventContext; import com.waz.zclient.core.controllers.tracking.events.Event; import com.waz.zclient.core.controllers.tracking.events.registration.OpenedPhoneRegistrationFromInviteEvent; import com.waz.zclient.core.controllers.tracking.events.registration.SucceededWithRegistrationEvent; import com.waz.zclient.core.stores.api.ZMessagingApiStoreObserver; import com.waz.zclient.core.stores.appentry.AppEntryState; import com.waz.zclient.core.stores.appentry.AppEntryStateCallback; import com.waz.zclient.newreg.fragments.EmailAddPhoneFragment; import com.waz.zclient.newreg.fragments.EmailInvitationFragment; import com.waz.zclient.newreg.fragments.EmailRegisterFragment; import com.waz.zclient.newreg.fragments.EmailSignInFragment; import com.waz.zclient.newreg.fragments.EmailVerifyEmailFragment; import com.waz.zclient.newreg.fragments.FirstLaunchAfterLoginFragment; import com.waz.zclient.newreg.fragments.OTRPhoneAddEmailFragment; import com.waz.zclient.newreg.fragments.PhoneAddEmailFragment; import com.waz.zclient.newreg.fragments.PhoneInvitationFragment; import com.waz.zclient.newreg.fragments.PhoneRegisterFragment; import com.waz.zclient.newreg.fragments.PhoneSetNameFragment; import com.waz.zclient.newreg.fragments.PhoneSignInFragment; import com.waz.zclient.newreg.fragments.PhoneVerifyEmailFragment; import com.waz.zclient.newreg.fragments.SignUpPhotoFragment; import com.waz.zclient.newreg.fragments.VerifyPhoneFragment; import com.waz.zclient.newreg.fragments.WelcomeEmailFragment; import com.waz.zclient.newreg.fragments.country.CountryController; import com.waz.zclient.newreg.fragments.country.CountryDialogFragment; import com.waz.zclient.tracking.GlobalTrackingController; import com.waz.zclient.ui.utils.KeyboardUtils; import com.waz.zclient.utils.HockeyCrashReporting; import com.waz.zclient.utils.ViewUtils; import com.waz.zclient.utils.ZTimeFormatter; import com.waz.zclient.views.LoadingIndicatorView; import net.hockeyapp.android.NativeCrashManager; import timber.log.Timber; import static com.waz.zclient.newreg.fragments.SignUpPhotoFragment.UNSPLASH_API_URL; public class AppEntryActivity extends BaseActivity implements VerifyPhoneFragment.Container, PhoneRegisterFragment.Container, PhoneSignInFragment.Container, PhoneSetNameFragment.Container, PhoneAddEmailFragment.Container, OTRPhoneAddEmailFragment.Container, PhoneVerifyEmailFragment.Container, SignUpPhotoFragment.Container, EmailAddPhoneFragment.Container, EmailRegisterFragment.Container, EmailSignInFragment.Container, EmailVerifyEmailFragment.Container, WelcomeEmailFragment.Container, EmailInvitationFragment.Container, PhoneInvitationFragment.Container, InAppWebViewFragment.Container, CountryDialogFragment.Container, FirstLaunchAfterLoginFragment.Container, NavigationControllerObserver, AppEntryStateCallback, ZMessagingApiStoreObserver { public static final String TAG = AppEntryActivity.class.getName(); private static final String HTTPS_PREFIX = "https://"; private static final String HTTP_PREFIX = "http://"; public static final int PREFETCH_IMAGE_WIDTH = 4; private ImageAsset unsplashInitImageAsset; private LoadHandle unsplashInitLoadHandle = null; private LoadingIndicatorView progressView; private CountryController countryController; private int accentColor; private boolean createdFromSavedInstance; private boolean isPaused; @Override public void onBackPressed() { SignUpPhotoFragment fragment = (SignUpPhotoFragment) getSupportFragmentManager().findFragmentByTag( SignUpPhotoFragment.TAG); if (fragment != null && fragment.onBackPressed()) { return; } OTRPhoneAddEmailFragment otrPhoneAddEmailFragment = (OTRPhoneAddEmailFragment) getSupportFragmentManager().findFragmentByTag( OTRPhoneAddEmailFragment.TAG); if (otrPhoneAddEmailFragment != null) { getSupportFragmentManager().popBackStackImmediate(R.id.fl_main_content, FragmentManager.POP_BACK_STACK_INCLUSIVE); getStoreFactory().getZMessagingApiStore().logout(); getStoreFactory().getAppEntryStore().setState(AppEntryState.PHONE_SIGN_IN); return; } if (!getStoreFactory().getAppEntryStore().onBackPressed()) { super.onBackPressed(); } } @Override public void onCreate(Bundle savedInstanceState) { if (getActionBar() != null) { getActionBar().hide(); } super.onCreate(savedInstanceState); setTheme(R.style.Theme_Dark); ViewUtils.lockScreenOrientation(Configuration.ORIENTATION_PORTRAIT, this); setContentView(R.layout.activity_signup); countryController = new CountryController(this); progressView = ViewUtils.getView(this, R.id.liv__progress); // always disable progress bar at the beginning enableProgress(false); createdFromSavedInstance = savedInstanceState != null; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { //noinspection deprecation accentColor = getResources().getColor(R.color.text__primary_dark); } else { accentColor = getResources().getColor(R.color.text__primary_dark, getTheme()); } if (unsplashInitLoadHandle == null && unsplashInitImageAsset == null) { unsplashInitImageAsset = ImageAssetFactory.getImageAsset(AndroidURIUtil.parse(UNSPLASH_API_URL)); // This is just to force that SE will download the image so that it is probably ready when we are at the // set picture screen unsplashInitLoadHandle = unsplashInitImageAsset.getSingleBitmap(PREFETCH_IMAGE_WIDTH, new BitmapCallback() { @Override public void onBitmapLoaded(Bitmap b) {} }); } } @Override public void onStart() { super.onStart(); getControllerFactory().getNavigationController().addNavigationControllerObserver(this); getStoreFactory().getZMessagingApiStore().addApiObserver(this); getStoreFactory().getAppEntryStore().setCallback(this); if (!createdFromSavedInstance) { getStoreFactory().getAppEntryStore().resumeAppEntry(getStoreFactory().getZMessagingApiStore().getApi().getSelf(), getControllerFactory().getUserPreferencesController().getPersonalInvitationToken()); } } @Override protected void onResume() { super.onResume(); final boolean trackingEnabled = getSharedPreferences(UserPreferencesController.USER_PREFS_TAG, Context.MODE_PRIVATE) .getBoolean(getString(R.string.pref_advanced_analytics_enabled_key), true); if (trackingEnabled) { HockeyCrashReporting.checkForCrashes(getApplicationContext(), getControllerFactory().getUserPreferencesController().getDeviceId(), injectJava(GlobalTrackingController.class)); } else { HockeyCrashReporting.deleteCrashReports(getApplicationContext()); NativeCrashManager.deleteDumpFiles(getApplicationContext()); } } @Override protected void onPostResume() { super.onPostResume(); if (isPaused) { isPaused = false; getStoreFactory().getAppEntryStore().triggerStateUpdate(); } } @Override protected void onPause() { isPaused = true; super.onPause(); } @Override public void onStop() { getControllerFactory().getNavigationController().removeNavigationControllerObserver(this); getStoreFactory().getAppEntryStore().setCallback(null); getStoreFactory().getZMessagingApiStore().removeApiObserver(this); if (unsplashInitLoadHandle != null) { unsplashInitLoadHandle.cancel(); unsplashInitLoadHandle = null; } super.onStop(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Timber.i("OnActivity result: %d/%d", requestCode, resultCode); super.onActivityResult(requestCode, resultCode, data); getSupportFragmentManager().findFragmentById(R.id.fl_main_content).onActivityResult(requestCode, resultCode, data); } @Override public void onDestroy() { getStoreFactory().getAppEntryStore().clearCurrentState(); super.onDestroy(); } @Override public void enableProgress(boolean enabled) { if (enabled) { progressView.show(LoadingIndicatorView.SPINNER_WITH_DIMMED_BACKGROUND, true); } else { progressView.hide(); } } @Override public void onOpenUrl(String url) { try { if (!url.startsWith(HTTP_PREFIX) && !url.startsWith(HTTPS_PREFIX)) { url = HTTP_PREFIX + url; } Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(browserIntent); } catch (Exception e) { Timber.e("Failed to open URL: %s", url); } } @Override public int getAccentColor() { return accentColor; } @Override public void onShowPhoneInvitationPage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, PhoneInvitationFragment.newInstance(getStoreFactory().getAppEntryStore().getInvitationName(), getStoreFactory().getAppEntryStore().getInvitationPhone()), PhoneInvitationFragment.TAG) .commit(); enableProgress(false); } @Override public void onShowEmailInvitationPage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, EmailInvitationFragment.newInstance(getStoreFactory().getAppEntryStore().getInvitationName(), getStoreFactory().getAppEntryStore().getInvitationEmail()), EmailInvitationFragment.TAG) .commit(); enableProgress(false); } @Override public void onInvitationFailed() { Toast.makeText(this, getString(R.string.invitation__email__failed), Toast.LENGTH_SHORT).show(); } @Override public void onInvitationSuccess() { getControllerFactory().getUserPreferencesController().setPersonalInvitationToken(null); } @Override public void onShowPhoneRegistrationPage() { if (isPaused) { return; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, PhoneRegisterFragment.newInstance(), PhoneRegisterFragment.TAG) .commit(); enableProgress(false); if (fromGenericInvite()) { getStoreFactory().getAppEntryStore().setRegistrationContext(RegistrationEventContext.GENERIC_INVITE_PHONE); // Temporary tracking to check on high number of invite registrations AN-4117 String referralToken = getControllerFactory().getUserPreferencesController().getReferralToken(); String token = getControllerFactory().getUserPreferencesController().getGenericInvitationToken(); injectJava(GlobalTrackingController.class).tagEvent(new OpenedPhoneRegistrationFromInviteEvent( referralToken, token)); } else { getStoreFactory().getAppEntryStore().setRegistrationContext(RegistrationEventContext.PHONE); } getControllerFactory().getNavigationController().setLeftPage(Page.PHONE_REGISTRATION, TAG); } @Override public void onShowPhoneSignInPage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, PhoneSignInFragment.newInstance(), PhoneSignInFragment.TAG) .commit(); enableProgress(false); getControllerFactory().getNavigationController().setLeftPage(Page.PHONE_LOGIN, TAG); } @Override public void onShowPhoneCodePage() { if (isPaused) { return; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, VerifyPhoneFragment.newInstance(false), VerifyPhoneFragment.TAG) .commit(); enableProgress(false); getControllerFactory().getNavigationController().setLeftPage(Page.PHONE_REGISTRATION_VERIFY_CODE, TAG); } @Override public void onShowPhoneAddEmailPage() { if (isPaused) { return; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); getControllerFactory().getBackgroundController().setSelf(getStoreFactory().getZMessagingApiStore().getApi().getSelf()); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, OTRPhoneAddEmailFragment.newInstance(), OTRPhoneAddEmailFragment.TAG) .addToBackStack(OTRPhoneAddEmailFragment.TAG) .commit(); enableProgress(false); } @Override public void onShowPhoneVerifyEmailPage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, PhoneVerifyEmailFragment.newInstance(), PhoneVerifyEmailFragment.TAG) .commit(); enableProgress(false); } @Override public void onShowPhoneSetPicturePage() { if (getSupportFragmentManager().findFragmentByTag(SignUpPhotoFragment.TAG) != null) { return; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, SignUpPhotoFragment.newInstance(SignUpPhotoFragment.RegistrationType.Phone), SignUpPhotoFragment.TAG) .commit(); enableProgress(false); getControllerFactory().getNavigationController().setLeftPage(Page.PHONE_REGISTRATION_ADD_PHOTO, TAG); } @Override public void onShowEmailWelcomePage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, WelcomeEmailFragment.newInstance(), WelcomeEmailFragment.TAG) .commit(); enableProgress(false); KeyboardUtils.closeKeyboardIfShown(this); } @Override public void onShowEmailRegistrationPage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, EmailRegisterFragment.newInstance(), EmailRegisterFragment.TAG) .commit(); enableProgress(false); if (fromGenericInvite()) { getStoreFactory().getAppEntryStore().setRegistrationContext(RegistrationEventContext.GENERIC_INVITE_EMAIL); } else { getStoreFactory().getAppEntryStore().setRegistrationContext(RegistrationEventContext.EMAIL); } } @Override public void onShowEmailVerifyEmailPage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, EmailVerifyEmailFragment.newInstance(), EmailVerifyEmailFragment.TAG) .commit(); enableProgress(false); } @Override public void onShowEmailSignInPage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, EmailSignInFragment.newInstance(), EmailSignInFragment.TAG) .commit(); enableProgress(false); getControllerFactory().getNavigationController().setLeftPage(Page.EMAIL_LOGIN, TAG); } @Override public void onShowEmailSetPicturePage() { if (getSupportFragmentManager().findFragmentByTag(SignUpPhotoFragment.TAG) != null) { return; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, SignUpPhotoFragment.newInstance(SignUpPhotoFragment.RegistrationType.Email), SignUpPhotoFragment.TAG) .commit(); enableProgress(false); } @Override public void onShowEmailAddPhonePage() { if (isPaused) { return; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, EmailAddPhoneFragment.newInstance(), EmailAddPhoneFragment.TAG) .commit(); enableProgress(false); } @Override public void onShowEmailPhoneCodePage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, VerifyPhoneFragment.newInstance(true), VerifyPhoneFragment.TAG) .commit(); enableProgress(false); } @Override public void onShowFirstLaunchPage() { String id = getStoreFactory().getAppEntryStore().getUserId(); boolean hasUserLoggedIn = getControllerFactory().getUserPreferencesController().hasUserLoggedIn(id); if (id != null && hasUserLoggedIn) { getStoreFactory().getAppEntryStore().setState(AppEntryState.LOGGED_IN); } else { if (id != null) { getControllerFactory().getUserPreferencesController().userLoggedIn(id); } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, FirstLaunchAfterLoginFragment.newInstance(), FirstLaunchAfterLoginFragment.TAG) .commit(); enableProgress(false); } } @Override public void tagAppEntryEvent(Event event) { injectJava(GlobalTrackingController.class).tagEvent(event); if (event instanceof SucceededWithRegistrationEvent) { Localytics.setProfileAttribute(Attribute.REGISTRATION_WEEK.name(), ZTimeFormatter.getCurrentWeek(this), Localytics.ProfileScope.APPLICATION); } } @Override public void onShowPhoneNamePage() { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); setDefaultAnimation(transaction) .replace(R.id.fl_main_content, PhoneSetNameFragment.newInstance(), PhoneSetNameFragment.TAG) .commit(); enableProgress(false); getControllerFactory().getNavigationController().setLeftPage(Page.PHONE_REGISTRATION_ADD_NAME, TAG); } @Override public void onEnterApplication() { getControllerFactory().getNavigationController().removeNavigationControllerObserver(this); getControllerFactory().getVerificationController().finishVerification(); startActivity(new Intent(this, MainActivity.class)); finish(); } private FragmentTransaction setDefaultAnimation(FragmentTransaction transaction) { transaction.setCustomAnimations(R.anim.new_reg_in, R.anim.new_reg_out); return transaction; } @Override public void openCountryBox() { getSupportFragmentManager() .beginTransaction() .setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) .add(R.id.container__country_box, new CountryDialogFragment(), CountryDialogFragment.TAG) .addToBackStack(CountryDialogFragment.TAG) .commit(); KeyboardUtils.hideKeyboard(this); } ////////////////// // // Lifecycle & Store/Controller stuff // ////////////////// @Override protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); getStoreFactory().getAppEntryStore().onRestoreInstanceState(savedInstanceState, getStoreFactory().getZMessagingApiStore().getApi().getSelf()); } @Override protected void onSaveInstanceState(Bundle outState) { getStoreFactory().getAppEntryStore().onSaveInstanceState(outState); super.onSaveInstanceState(outState); } @Override public void onOpenUrlInApp(String url, boolean withCloseButton) { if (!url.startsWith(HTTP_PREFIX) && !url.startsWith(HTTPS_PREFIX)) { url = HTTP_PREFIX + url; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.setCustomAnimations(R.anim.new_reg_in, R.anim.new_reg_out); transaction.add(R.id.fl_main_web_view, InAppWebViewFragment.newInstance(url, withCloseButton), InAppWebViewFragment.TAG); transaction.addToBackStack(InAppWebViewFragment.TAG); transaction.commit(); KeyboardUtils.hideKeyboard(this); } @Override public void dismissInAppWebView() { getSupportFragmentManager().popBackStackImmediate(); } @Override public CountryController getCountryController() { return countryController; } @Override public void dismissCountryBox() { getSupportFragmentManager().popBackStackImmediate(); KeyboardUtils.showKeyboard(this); } ////////////////// // // ZmessagingApiStoreObserver // ////////////////// @Override public void onForceClientUpdate() { startActivity(new Intent(this, ForceUpdateActivity.class)); finish(); } @Override public void onInitialized(Self self) { } @Override public void onLogout() { } private boolean fromGenericInvite() { String referralToken = getControllerFactory().getUserPreferencesController().getReferralToken(); String token = getControllerFactory().getUserPreferencesController().getGenericInvitationToken(); return token != null || AppEntryStore.GENERAL_GENERIC_INVITE_TOKEN.equals(referralToken); } @Override public ImageAsset getUnsplashImageAsset() { return unsplashInitImageAsset; } @Override public void onPageVisible(Page page) { switch (page) { case PHONE_REGISTRATION: injectJava(GlobalTrackingController.class).onApplicationScreen(ApplicationScreen.PHONE_REGISTRATION); break; case PHONE_REGISTRATION_VERIFY_CODE: injectJava(GlobalTrackingController.class).onApplicationScreen(ApplicationScreen.PHONE_REGISTRATION__VERIFY_CODE); break; case PHONE_REGISTRATION_ADD_NAME: injectJava(GlobalTrackingController.class).onApplicationScreen(ApplicationScreen.PHONE_REGISTRATION__ADD_NAME); break; case PHONE_REGISTRATION_ADD_PHOTO: injectJava(GlobalTrackingController.class).onApplicationScreen(ApplicationScreen.PHONE_REGISTRATION__ADD_PHOTO); break; case EMAIL_LOGIN: injectJava(GlobalTrackingController.class).onApplicationScreen(ApplicationScreen.EMAIL_LOGIN); break; case PHONE_LOGIN: injectJava(GlobalTrackingController.class).onApplicationScreen(ApplicationScreen.PHONE_LOGIN); break; } } @Override public void onPageStateHasChanged(Page page) { } }