com.smoothsync.smoothsetup.microfragments.appspecificpassword.AppSpecificWebviewFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.smoothsync.smoothsetup.microfragments.appspecificpassword.AppSpecificWebviewFragment.java

Source

/*
 * Copyright (c) 2017 dmfs GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.smoothsync.smoothsetup.microfragments.appspecificpassword;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;

import com.smoothsync.smoothsetup.R;

import org.dmfs.android.microfragments.FragmentEnvironment;
import org.dmfs.android.microfragments.transitions.BackTransition;
import org.dmfs.android.microfragments.transitions.BackWithResultTransition;
import org.dmfs.pigeonpost.Cage;

import java.net.URI;

/**
 * A fragment that presents a website to create an app specific password.
 *
 * @author Marten Gajda
 */
public final class AppSpecificWebviewFragment extends Fragment implements View.OnKeyListener {

    public static final int PASSWORD_PROBE_PERIOD = 500;;
    private final Handler mHandler = new Handler();
    private WebView mWebView;
    private String mAppSpecificPassword;
    private final View.OnClickListener mOnCopyPasswordListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            FragmentEnvironment<Params> env = new FragmentEnvironment<>(AppSpecificWebviewFragment.this);
            env.host().execute(getActivity(), new BackWithResultTransition<>(env.microFragment().parameter().cage(),
                    new SimplePasswordResult(mAppSpecificPassword)));
        }
    };
    private AppSpecificPasswordProbe mPasswordProbe;
    private final Runnable mPasswordProbeRunnable = new Runnable() {
        @Override
        public void run() {
            if (mWebView != null && mPasswordProbe != null) {
                mPasswordProbe.executeOn(mWebView);
            }
            mHandler.postDelayed(mPasswordProbeRunnable, PASSWORD_PROBE_PERIOD);
        }
    };
    private Snackbar mSnackbar;
    private ProgressBar mProgress;

    @SuppressLint("SetJavaScriptEnabled")
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.smoothsetup_microfragment_webview, container, false);
        mWebView = (WebView) root.findViewById(R.id.smoothsetup_webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setDomStorageEnabled(true);
        mWebView.setOnKeyListener(this);
        mWebView.setWebChromeClient(new WebChromeClient());
        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                mProgress.animate().alpha(0).start();
            }
        });
        mWebView.addJavascriptInterface(new AppSpecificPasswordCallback() {
            @JavascriptInterface
            @Override
            public void onAppSpecificPassword(final String appSpecificPassword) {
                if (!TextUtils.isEmpty(appSpecificPassword)
                        && !TextUtils.equals(mAppSpecificPassword, appSpecificPassword)) {
                    mAppSpecificPassword = appSpecificPassword;
                    mSnackbar = Snackbar
                            .make(mWebView,
                                    getString(R.string.smoothsetup_snackbar_found_app_specific_password,
                                            appSpecificPassword),
                                    Snackbar.LENGTH_INDEFINITE)
                            .setAction(R.string.smoothsetup_button_copy_app_specific_password,
                                    mOnCopyPasswordListener);
                    mSnackbar.show();
                }
            }
        }, "SmoothSetup");
        String url = new FragmentEnvironment<Params>(this).microFragment().parameter().uri().toASCIIString();
        if (savedInstanceState == null) {
            mWebView.loadUrl(url);
        } else {
            mWebView.restoreState(savedInstanceState);
        }
        mPasswordProbe = new DefaultPasswordProbeFactory().forUrl(URI.create(url));
        mProgress = (ProgressBar) root.findViewById(android.R.id.progress);

        // start probing for the password
        mHandler.postDelayed(mPasswordProbeRunnable, PASSWORD_PROBE_PERIOD);

        return root;
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mWebView != null) {
            mWebView.onResume();
        }
    }

    @Override
    public void onPause() {
        if (mWebView != null) {
            mWebView.onPause();
        }
        super.onPause();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mWebView.saveState(outState);
    }

    @Override
    public void onDestroyView() {
        mHandler.removeCallbacks(mPasswordProbeRunnable);
        if (mWebView != null) {
            mWebView.destroy();
        }
        if (mSnackbar != null) {
            mSnackbar.dismiss();
        }
        super.onDestroyView();
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                if (mWebView.canGoBack()) {
                    // user went back a step
                    mWebView.goBack();
                } else {
                    // the user cancelled the authorization flow
                    new FragmentEnvironment<>(this).host().execute(getActivity(), new BackTransition());
                }
            }
            return true;
        }
        return false;
    }

    public interface PasswordResult extends Parcelable {
        @NonNull
        String password();
    }

    public interface Params {
        @NonNull
        URI uri();

        @NonNull
        Cage<PasswordResult> cage();
    }
}