package com.arcao.trackables.ui.fragment; import android.annotation.SuppressLint; import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.FrameLayout; import com.arcao.trackables.AppConstants; import com.arcao.trackables.R; import com.arcao.trackables.data.service.AccountService; import com.arcao.trackables.exception.ExceptionHandler; import com.arcao.trackables.internal.di.HasComponent; import com.arcao.trackables.internal.di.component.WelcomeActivityComponent; import com.arcao.trackables.internal.rx.AndroidSchedulerTransformer; import com.arcao.trackables.ui.ErrorActivity; import com.arcao.trackables.ui.WelcomeActivity; import rx.functions.Actions; import rx.internal.util.SubscriptionList; import rx.observers.Subscribers; import timber.log.Timber; import javax.inject.Inject; import java.util.Locale; public class OAuthLoginFragment extends Fragment implements HasComponent<WelcomeActivityComponent> { public static final String FRAGMENT_TAG = OAuthLoginFragment.class.getName(); private static final String STATE_PROGRESS_VISIBLE = "STATE_PROGRESS_VISIBLE"; private static final String OAUTH_VERIFIER = "oauth_verifier"; private WebView mWebView = null; private View mProgressHolder = null; private Bundle mLastInstanceState; private final SubscriptionList subscriptionList = new SubscriptionList(); @Inject protected AccountService accountService; @Inject protected ExceptionHandler exceptionHandler; public static OAuthLoginFragment newInstance() { return new OAuthLoginFragment(); } public WelcomeActivityComponent component() { return ((WelcomeActivity)getActivity()).component(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); // clear geocaching.com cookies //App.get(getActivity()).clearGeocachingCookies(); component().inject(this); subscriptionList.add( accountService.startOAuthLogin() .compose(AndroidSchedulerTransformer.get()) .subscribe(this::onLoginUrlAvailable) ); } @Override public void onDestroy() { super.onDestroy(); subscriptionList.unsubscribe(); } public void onLoginUrlAvailable(String url) { if (mWebView != null) { mWebView.loadUrl(url); } } public void onLoginFinished(Intent errorIntent) { WelcomeActivity activity = (WelcomeActivity) getActivity(); if (activity == null) return; if (errorIntent == null) { activity.switchTo(WelcomeActivity.WelcomeState.AFTER_LOGIN); } else { activity.showError(errorIntent); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mWebView != null) { mWebView.saveState(outState); } if (mProgressHolder != null) { outState.putInt(STATE_PROGRESS_VISIBLE, mProgressHolder.getVisibility()); Timber.d("setVisibility: " + mProgressHolder.getVisibility()); } mLastInstanceState = outState; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // FIX savedInstanceState is null after rotation change if (savedInstanceState != null) mLastInstanceState = savedInstanceState; //getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); View view = inflater.inflate(R.layout.fragment_login_oauth, container, false); mProgressHolder = view.findViewById(R.id.progressHolder); mProgressHolder.setVisibility(View.VISIBLE); if (mLastInstanceState != null) { //noinspection ResourceType mProgressHolder.setVisibility(mLastInstanceState.getInt(STATE_PROGRESS_VISIBLE, View.VISIBLE)); } mWebView = createWebView(mLastInstanceState); FrameLayout webViewHolder = (FrameLayout) view.findViewById(R.id.webViewPlaceholder); webViewHolder.addView(mWebView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return view; } @SuppressLint("SetJavaScriptEnabled") private WebView createWebView(Bundle savedInstanceState) { WebView webView = new FixedWebView(getActivity()); webView.setHorizontalScrollBarEnabled(false); webView.setWebViewClient(new DialogWebViewClient()); webView.getSettings().setJavaScriptEnabled(true); if (savedInstanceState != null) webView.restoreState(savedInstanceState); return webView; } private class DialogWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith(AppConstants.OAUTH_CALLBACK_URL)) { Uri uri = Uri.parse(url); if (mProgressHolder != null) { mProgressHolder.setVisibility(View.VISIBLE); } subscriptionList.add( accountService.finishOAuthLogin(uri.getQueryParameter(OAUTH_VERIFIER)) .compose(AndroidSchedulerTransformer.get()). subscribe(Subscribers.create( Actions.empty(), throwable -> onLoginFinished(exceptionHandler.handle(throwable)), () -> onLoginFinished(null))) ); return true; } if (!isOAuthUrl(url)) { Timber.d("External URL: " + url); // launch external URLs in a full browser Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getActivity().startActivity(intent); return true; } return false; } private boolean isOAuthUrl(String url) { String urlLowerCase = url.toLowerCase(Locale.US); return urlLowerCase.contains("/oauth/") || urlLowerCase.contains("/mobileoauth/") || urlLowerCase.contains("/mobilesignin/") || urlLowerCase.contains("/mobilecontent/") || urlLowerCase.contains("//m.facebook"); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); if (getActivity() != null) onLoginFinished(new ErrorActivity.IntentBuilder(getActivity()).withAdditionalMessage(description).build()); } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); if (mProgressHolder != null) { mProgressHolder.setVisibility(View.VISIBLE); } } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); if (mProgressHolder != null && !url.startsWith(AppConstants.OAUTH_CALLBACK_URL)) { mProgressHolder.setVisibility(View.GONE); } } } private static class FixedWebView extends WebView { public FixedWebView(Context context) { super (context); } public FixedWebView(Context context, AttributeSet attrs, int defStyle) { super (context, attrs, defStyle); } public FixedWebView(Context context, AttributeSet attrs) { super (context, attrs); } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { try { super.onWindowFocusChanged(hasWindowFocus); } catch (NullPointerException e) { // Catch null pointer exception // suggested workaround from Web } } } }