com.nestapi.lib.UserAuthActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.nestapi.lib.UserAuthActivity.java

Source

/**
 * Copyright 2014 Nest Labs Inc. All Rights Reserved.
 * 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.nestapi.lib;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import com.nestapi.lib.API.AccessToken;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.util.List;

public class UserAuthActivity extends Activity implements LoaderManager.LoaderCallbacks<AccessToken> {
    public static final String TAG = "UserAuthFlow";
    private final static String CLIENT_METADATA_KEY = "client_metadata_key";
    private final static String ACCESS_TOKEN_KEY = "access_token_key";
    private ProgressBar mProgressBar;
    private ClientMetadata mClientMetadata;
    private String mCode = "BF59WJEJ";
    private String mWebViewUrl;
    private WebView clientWebView;

    private static void log(String msg) {
        Log.v(TAG, msg);
    }

    static void launchAuthFlowForResult(Activity activity, int requestCode, ClientMetadata data) {
        final Intent authFlowIntent = new Intent(activity, UserAuthActivity.class);
        authFlowIntent.putExtra(CLIENT_METADATA_KEY, data);
        log("Launching auth flow Activity...");
        activity.startActivityForResult(authFlowIntent, requestCode);
    }

    static boolean hasAccessToken(Intent data) {
        return data != null && data.hasExtra(ACCESS_TOKEN_KEY);
    }

    static AccessToken getAccessToken(Intent data) {
        return data == null ? null : (AccessToken) data.getParcelableExtra(ACCESS_TOKEN_KEY);
    }

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.nest_auth_webview_layout);

        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.height = ViewGroup.LayoutParams.MATCH_PARENT;
        params.width = ViewGroup.LayoutParams.MATCH_PARENT;
        params.horizontalMargin = 50;
        params.verticalMargin = 50;
        getWindow().setAttributes(params);

        clientWebView = (WebView) findViewById(R.id.auth_webview);
        mProgressBar = (ProgressBar) findViewById(R.id.webview_progress);
        mClientMetadata = getClientMetadata();

        if (!hasValidArgs(mClientMetadata.getRedirectURL(), mClientMetadata.getClientID(),
                mClientMetadata.getStateValue())) {
            log("invalid arguments...");
            setResult(RESULT_CANCELED);
            log("finishing");
            finish();
        }

        clientWebView.setWebChromeClient(new ProgressChromeClient());
        clientWebView.setWebViewClient(new RedirectClient());

        mWebViewUrl = String.format(APIUrls.CLIENT_CODE_URL, mClientMetadata.getClientID(),
                mClientMetadata.getStateValue());
        log("setting url: " + mWebViewUrl);
        WebSettings webSettings = clientWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        clientWebView.loadUrl(mWebViewUrl);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        finishWithResult(RESULT_CANCELED, null);
    }

    private void finishWithResult(int result, AccessToken token) {
        final Intent intent = new Intent();
        intent.putExtra(ACCESS_TOKEN_KEY, token);
        setResult(result, intent);
        finish();
    }

    private String parseCodeQuery(String urlStr) {
        try {
            List<NameValuePair> params = URLEncodedUtils.parse(new URI(urlStr), "UTF-8");
            for (NameValuePair pair : params) {
                log("Parsed parameters: " + pair.getName() + " value: " + pair.getValue());
                if (pair.getName().equals("code")) {
                    return pair.getValue();
                }
            }
            return null;
        } catch (URISyntaxException excep) {
            return null;
        }
    }

    @Override
    public Loader<AccessToken> onCreateLoader(int id, Bundle args) {
        return new ObtainAccessTokenTask(this, mClientMetadata, mCode);
    }

    @Override
    public void onLoadFinished(Loader<AccessToken> loader, AccessToken data) {
        log("resolved access token is null: " + (data == null));
        if (data != null) {
            finishWithResult(RESULT_OK, data);
        } else {
            finishWithResult(RESULT_CANCELED, null);
        }
    }

    @Override
    public void onLoaderReset(Loader<AccessToken> loader) {
        //NO-OP
    }

    private ClientMetadata getClientMetadata() {
        final Intent intent = getIntent();
        return intent == null ? null : (ClientMetadata) intent.getParcelableExtra(CLIENT_METADATA_KEY);
    }

    private boolean hasValidArgs(String... args) {
        if (args == null) {
            return true;
        }

        for (String s : args) {
            if (TextUtils.isEmpty(s)) {
                return false;
            }
        }
        return true;
    }

    private static class ObtainAccessTokenTask extends AsyncTaskLoader<AccessToken> {

        private static final int BUFFER_SIZE = 4096;

        private ClientMetadata mClientMetadata;
        private String mCode = "9XEE7GK4";

        public ObtainAccessTokenTask(Context context, ClientMetadata metadata, String code) {
            super(context);
            mClientMetadata = metadata;
            mCode = code;
        }

        private static String readStream(InputStream stream) throws IOException {
            final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            final byte[] buffer = new byte[BUFFER_SIZE];
            int read;
            while ((read = stream.read(buffer, 0, buffer.length)) != -1) {
                outStream.write(buffer, 0, read);
            }
            final byte[] data = outStream.toByteArray();
            return new String(data);
        }

        @Override
        protected void onStartLoading() {
            forceLoad();
        }

        @Override
        public AccessToken loadInBackground() {
            try {
                String formattedUrl = String.format(APIUrls.ACCESS_URL, mCode, mClientMetadata.getClientID(),
                        mClientMetadata.getClientSecret());
                log("Getting auth from: " + formattedUrl);
                URL url = new URL(formattedUrl);
                log("Created url...");
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                log("Opened connection...");
                conn.setRequestMethod("POST");

                InputStream in = new BufferedInputStream(conn.getInputStream());
                String result = readStream(in);
                JSONObject object = new JSONObject(result);

                return AccessToken.fromJSON(object);
            } catch (JSONException | IOException excep) {
                Log.e(TAG, "Unable to load access token.", excep);
                return null;
            }
        }
    }

    private class ProgressChromeClient extends WebChromeClient {

        private static final String PINCODE_PREFIX = "pincode=";

        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            final int currentVisibility = mProgressBar.getVisibility();
            if (newProgress < 100 && currentVisibility != View.VISIBLE) {
                mProgressBar.setVisibility(View.VISIBLE);
            } else if (newProgress == 100 && currentVisibility != View.GONE) {
                mProgressBar.setVisibility(View.GONE);
            }
        }

        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            if (message.contains(PINCODE_PREFIX)) {
                mCode = message.substring(PINCODE_PREFIX.length());
                getLoaderManager().restartLoader(0, null, UserAuthActivity.this);
                return true;
            }

            return false;
        }
    }

    private class RedirectClient extends WebViewClient {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            String authScriptHackData = IOUtils.readRawResourceAsString(UserAuthActivity.this, R.raw.autho_script);
            clientWebView.loadUrl("javascript:$('html').append('" + authScriptHackData + "')");
        }
    }
}