org.wso2.iot.agent.activities.AuthenticationActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.iot.agent.activities.AuthenticationActivity.java

Source

/*
 * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 * 
 * WSO2 Inc. licenses this file to you 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 org.wso2.iot.agent.activities;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.util.Linkify;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.wso2.iot.agent.AndroidAgentException;
import org.wso2.iot.agent.R;
import org.wso2.iot.agent.api.DeviceInfo;
import org.wso2.iot.agent.api.TenantResolverCallback;
import org.wso2.iot.agent.api.TenantResolverHandler;
import org.wso2.iot.agent.beans.ApiRegistrationProfile;
import org.wso2.iot.agent.beans.ServerConfig;
import org.wso2.iot.agent.beans.Tenant;
import org.wso2.iot.agent.proxy.IdentityProxy;
import org.wso2.iot.agent.proxy.authenticators.AuthenticatorFactory;
import org.wso2.iot.agent.proxy.authenticators.ClientAuthenticator;
import org.wso2.iot.agent.proxy.beans.CredentialInfo;
import org.wso2.iot.agent.proxy.interfaces.APIAccessCallBack;
import org.wso2.iot.agent.proxy.interfaces.APIResultCallBack;
import org.wso2.iot.agent.proxy.interfaces.AuthenticationCallback;
import org.wso2.iot.agent.proxy.utils.Constants.HTTP_METHODS;
import org.wso2.iot.agent.services.AgentDeviceAdminReceiver;
import org.wso2.iot.agent.services.DynamicClientManager;
import org.wso2.iot.agent.services.LocalNotification;
import org.wso2.iot.agent.services.location.LocationService;
import org.wso2.iot.agent.utils.CommonDialogUtils;
import org.wso2.iot.agent.utils.CommonUtils;
import org.wso2.iot.agent.utils.Constants;
import org.wso2.iot.agent.utils.Preference;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Activity that captures username, password and device ownership details
 * and handles authentication.
 */
public class AuthenticationActivity extends AppCompatActivity
        implements APIAccessCallBack, APIResultCallBack, AuthenticationCallback {
    private Button btnSignIn;
    private EditText etUsername;
    private EditText etDomain;
    private EditText etPassword;
    private String deviceType;
    private Context context;
    private String username;
    private String usernameVal;
    private String passwordVal;
    private String adminAccessToken;
    private ProgressDialog progressDialog;
    private boolean isReLogin = false;
    private boolean isCloudLogin = false;
    private int kioskExit;

    private DeviceInfo deviceInfo;
    private static final String TAG = AuthenticationActivity.class.getSimpleName();
    private static final int ACTIVATION_REQUEST = 47;
    private static final String[] SUBSCRIBED_API = new String[] { "android" };
    private Tenant currentTenant;
    private DevicePolicyManager devicePolicyManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        } else {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }

        setContentView(R.layout.activity_authentication);
        RelativeLayout relativeLayout = (RelativeLayout) this.findViewById(R.id.relavtiveLayoutAuthentication);

        if (Constants.DEFAULT_OWNERSHIP.equals(Constants.OWNERSHIP_COSU)) {
            relativeLayout.setVisibility(RelativeLayout.GONE);
        }
        deviceInfo = new DeviceInfo(context);
        etDomain = (EditText) findViewById(R.id.etDomain);
        etUsername = (EditText) findViewById(R.id.etUsername);
        etPassword = (EditText) findViewById(R.id.etPassword);
        etDomain.setFocusable(true);
        etDomain.requestFocus();
        btnSignIn = (Button) findViewById(R.id.btnSignIn);
        btnSignIn.setOnClickListener(onClickAuthenticate);
        btnSignIn.setEnabled(false);

        // change button color background till user enters a valid input
        btnSignIn.setBackgroundResource(R.drawable.btn_grey);
        btnSignIn.setTextColor(ContextCompat.getColor(this, R.color.black));
        TextView textViewSignIn = (TextView) findViewById(R.id.textViewSignIn);
        LinearLayout loginLayout = (LinearLayout) findViewById(R.id.loginLayout);

        if (Preference.hasPreferenceKey(context, Constants.TOKEN_EXPIRED)) {
            etDomain.setEnabled(false);
            etDomain.setTextColor(ContextCompat.getColor(this, R.color.black));
            etUsername.setEnabled(false);
            etUsername.setTextColor(ContextCompat.getColor(this, R.color.black));
            btnSignIn.setText(R.string.btn_sign_in);
            etPassword.setFocusable(true);
            etPassword.requestFocus();
            String tenantedUserName = Preference.getString(context, Constants.USERNAME);
            int tenantSeparator = tenantedUserName.lastIndexOf('@');
            etUsername.setText(tenantedUserName.substring(0, tenantSeparator));
            etDomain.setText(tenantedUserName.substring(tenantSeparator + 1, tenantedUserName.length()));
            isReLogin = true;
            textViewSignIn.setText(R.string.msg_need_to_sign_in);
        } else if (Constants.CLOUD_MANAGER != null) {
            isCloudLogin = true;
            etDomain.setVisibility(View.GONE);
            textViewSignIn.setText(R.string.txt_sign_in_cloud);
        }

        if (Preference.getBoolean(context, Constants.PreferenceFlag.DEVICE_ACTIVE) && !isReLogin) {
            Intent intent = new Intent(AuthenticationActivity.this, AlreadyRegisteredActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(intent);
            finish();
            return;
        }

        TextView textViewSignUp = (TextView) findViewById(R.id.textViewSignUp);
        if (!isReLogin && Constants.SIGN_UP_URL != null) {
            Linkify.TransformFilter transformFilter = new Linkify.TransformFilter() {
                @Override
                public String transformUrl(Matcher match, String url) {
                    return Constants.SIGN_UP_URL;
                }
            };
            Pattern pattern = Pattern.compile(getResources().getString(R.string.txt_sign_up_linkify));
            Linkify.addLinks(textViewSignUp, pattern, null, null, transformFilter);
        } else {
            textViewSignUp.setVisibility(View.GONE);
        }

        if (Constants.HIDE_LOGIN_UI) {
            loginLayout.setVisibility(View.GONE);
        }

        if (Constants.OWNERSHIP_COSU.equals(Constants.DEFAULT_OWNERSHIP)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                startLockTask();
            }
        }

        TextView textViewWipeData = (TextView) this.findViewById(R.id.textViewWipeData);
        if (Constants.OWNERSHIP_COSU.equals(Constants.DEFAULT_OWNERSHIP) && Constants.DISPLAY_WIPE_DEVICE_BUTTON) {
            textViewWipeData.setVisibility(View.VISIBLE);
            textViewWipeData.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    new AlertDialog.Builder(AuthenticationActivity.this).setTitle(getString(R.string.app_name))
                            .setMessage(R.string.wipe_confirmation)
                            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int whichButton) {
                                    DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getApplicationContext()
                                            .getSystemService(Context.DEVICE_POLICY_SERVICE);
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                                        devicePolicyManager.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE
                                                | DevicePolicyManager.WIPE_RESET_PROTECTION_DATA);
                                    } else {
                                        devicePolicyManager.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
                                    }
                                }
                            }).setNegativeButton(android.R.string.no, null).show();
                }
            });
        }

        ImageView logo = (ImageView) findViewById(R.id.imageViewLogo);
        if (Constants.COSU_SECRET_EXIT) {
            logo.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    kioskExit++;
                    if (kioskExit == 6) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            stopLockTask();
                        }
                        finish();
                    }
                }
            });
        }

        etUsername.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                enableSubmitIfReady();
            }

            @Override
            public void afterTextChanged(Editable s) {
                enableSubmitIfReady();
            }
        });

        etPassword.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                enableSubmitIfReady();
            }

            @Override
            public void afterTextChanged(Editable s) {
                enableSubmitIfReady();
            }
        });

        if (org.wso2.iot.agent.proxy.utils.Constants.Authenticator.AUTHENTICATOR_IN_USE
                .equals(org.wso2.iot.agent.proxy.utils.Constants.Authenticator.MUTUAL_SSL_AUTHENTICATOR)) {

            AuthenticatorFactory authenticatorFactory = new AuthenticatorFactory();
            ClientAuthenticator authenticator = authenticatorFactory.getClient(
                    org.wso2.iot.agent.proxy.utils.Constants.Authenticator.AUTHENTICATOR_IN_USE,
                    AuthenticationActivity.this, Constants.AUTHENTICATION_REQUEST_CODE);
            authenticator.doAuthenticate();
        }

        //This is an override to ownership type.
        if (Constants.DEFAULT_OWNERSHIP != null) {
            deviceType = Constants.DEFAULT_OWNERSHIP;
            Preference.putString(context, Constants.DEVICE_TYPE, deviceType);
        } else {
            deviceType = Constants.OWNERSHIP_BYOD;
        }

        if (Constants.OWNERSHIP_COSU.equals(Constants.DEFAULT_OWNERSHIP)) {
            Intent intent = getIntent();
            if (intent.hasExtra("android.app.extra.token")) {
                adminAccessToken = intent.getStringExtra("android.app.extra.token");
                proceedToAuthentication();
            }
        }

        // This is added so that in case due to an agent customisation, if the authentication
        // activity is called the AUTO_ENROLLMENT_BACKGROUND_SERVICE_ENABLED is set, the activity
        // must be finished.
        if (Constants.AUTO_ENROLLMENT_BACKGROUND_SERVICE_ENABLED) {
            finish();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (progressDialog != null) {
            progressDialog.show();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
        } else {
            progressDialog = null;
        }
    }

    @Override
    protected void onDestroy() {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
        super.onDestroy();
        CommonDialogUtils.stopProgressDialog(progressDialog);
        progressDialog = null;
    }

    private OnClickListener onClickAuthenticate = new OnClickListener() {

        @Override
        public void onClick(View view) {
            if (etUsername.getText() != null && !etUsername.getText().toString().trim().isEmpty()
                    && etPassword.getText() != null && !etPassword.getText().toString().trim().isEmpty()) {

                passwordVal = etPassword.getText().toString().trim();
                usernameVal = etUsername.getText().toString().trim();

                if (isCloudLogin) {
                    obtainTenantDomain(usernameVal, passwordVal);
                } else {
                    proceedToAuthentication();
                }
            } else {
                if (etUsername.getText() != null && !etUsername.getText().toString().trim().isEmpty()) {
                    Toast.makeText(context, getResources().getString(R.string.toast_error_password),
                            Toast.LENGTH_LONG).show();
                } else {
                    Toast.makeText(context, getResources().getString(R.string.toast_error_username),
                            Toast.LENGTH_LONG).show();
                }
            }
        }
    };

    private DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            switch (which) {
            case DialogInterface.BUTTON_POSITIVE:
                getClientCredentials();
                dialog.dismiss();
                break;
            case DialogInterface.BUTTON_NEGATIVE:
                dialog.dismiss();
                break;
            case DialogInterface.BUTTON_NEUTRAL:
                dialog.dismiss();
                break;
            default:
                break;
            }
        }
    };

    private void proceedToAuthentication() {
        if (etDomain.getText() != null && !etDomain.getText().toString().trim().isEmpty()) {
            usernameVal += getResources().getString(R.string.intent_extra_at)
                    + etDomain.getText().toString().trim();
        }
        if (Constants.OWNERSHIP_COPE.equals(deviceType) && !CommonUtils.isSystemAppInstalled(context)) {
            showNoSystemAppDialog();
        } else {
            getClientCredentials();
        }
    }

    private void obtainTenantDomain(String username, String password) {
        // Check network connection availability before calling the API.
        currentTenant = null;
        if (CommonUtils.isNetworkAvailable(context)) {
            progressDialog = ProgressDialog.show(context, getResources().getString(R.string.dialog_authenticate),
                    getResources().getString(R.string.dialog_message_please_wait), true);
            IdentityProxy.getInstance().setContext(this.getApplicationContext());
            TenantResolverHandler tenantResolverHandler = new TenantResolverHandler(new TenantResolverCallback() {
                @Override
                public void onTenantResolved(final List<Tenant> tenants) {
                    if (tenants.isEmpty()) {
                        showEnrollmentFailedErrorMessage(
                                getResources().getString(R.string.dialog_tenants_not_available));
                    } else if (tenants.size() == 1) {
                        currentTenant = tenants.get(0);
                        CommonDialogUtils.stopProgressDialog(progressDialog);
                        etDomain.setText(currentTenant.getTenantDomain());
                        proceedToAuthentication();
                    } else {
                        CommonDialogUtils.stopProgressDialog(progressDialog);
                        List<String> tenantNames = new ArrayList<>();
                        for (Tenant t : tenants) {
                            tenantNames.add(t.getDisplayName());
                        }
                        CommonDialogUtils.getAlertDialogWithSingleChoices(context,
                                getResources().getString(R.string.dialog_select_tenant),
                                tenantNames.toArray(new String[0]), new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        currentTenant = tenants.get(which);
                                        etDomain.setText(currentTenant.getTenantDomain());
                                        proceedToAuthentication();
                                        dialog.dismiss();
                                    }
                                }).show();
                    }
                }

                @Override
                public void onAuthenticationSuccess() {
                    CommonDialogUtils.stopProgressDialog(progressDialog);
                    progressDialog = ProgressDialog.show(context,
                            getResources().getString(R.string.dialog_tenant_resolving),
                            getResources().getString(R.string.dialog_message_please_wait), true);
                }

                @Override
                public void onAuthenticationFail() {
                    showAuthenticationError();
                }

                @Override
                public void onFailure(AndroidAgentException exception) {
                    showEnrollmentFailedErrorMessage(exception.getMessage());
                }
            });
            tenantResolverHandler.resolveTenantDomain(username, password);
        } else {
            CommonDialogUtils.showNetworkUnavailableMessage(context);
        }
    }

    /**
     * Start device admin activation request.
     *
     */
    private void startDeviceAdminPrompt() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP
                && devicePolicyManager.isProfileOwnerApp(getPackageName())) {
            checkManifestPermissions();
            CommonUtils.callSystemApp(context, null, null, null);
            Log.i("onActivityResult", "Administration enabled!");
        } else {
            DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getSystemService(
                    Context.DEVICE_POLICY_SERVICE);
            ComponentName cdmDeviceAdmin = new ComponentName(AuthenticationActivity.this,
                    AgentDeviceAdminReceiver.class);
            if (!devicePolicyManager.isAdminActive(cdmDeviceAdmin)) {
                Intent deviceAdminIntent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
                deviceAdminIntent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, cdmDeviceAdmin);
                deviceAdminIntent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
                        getResources().getString(R.string.device_admin_enable_alert));
                startActivityForResult(deviceAdminIntent, ACTIVATION_REQUEST);
            }
        }
    }

    /**
     * Start authentication process.
     */
    private void startAuthentication() {
        Preference.putString(context, Constants.DEVICE_TYPE, deviceType);

        // Check network connection availability before calling the API.
        if (CommonUtils.isNetworkAvailable(context)) {
            String clientId = Preference.getString(context, Constants.CLIENT_ID);
            String clientSecret = Preference.getString(context, Constants.CLIENT_SECRET);

            if (clientId == null || clientSecret == null) {
                String clientCredentials = Preference.getString(context,
                        getResources().getString(R.string.shared_pref_client_credentials));
                if (clientCredentials != null) {
                    try {
                        JSONObject payload = new JSONObject(clientCredentials);
                        clientId = payload.getString(Constants.CLIENT_ID);
                        clientSecret = payload.getString(Constants.CLIENT_SECRET);

                        if (clientId != null && !clientId.isEmpty() && clientSecret != null
                                && !clientSecret.isEmpty()) {
                            initializeIDPLib(clientId, clientSecret);
                        }
                    } catch (JSONException e) {
                        String msg = "error occurred while parsing client credential payload";
                        Log.e(TAG, msg, e);
                        CommonDialogUtils.stopProgressDialog(progressDialog);
                        showInternalServerErrorMessage();
                    }
                } else {
                    String msg = "error occurred while retrieving client credentials";
                    Log.e(TAG, msg);
                    CommonDialogUtils.stopProgressDialog(progressDialog);
                    showInternalServerErrorMessage();
                }
            } else {
                initializeIDPLib(clientId, clientSecret);
            }

        } else {
            CommonDialogUtils.stopProgressDialog(progressDialog);
            CommonDialogUtils.showNetworkUnavailableMessage(context);
        }

    }

    /**
     * Initialize the Android IDP SDK by passing credentials,client ID and
     * client secret.
     *
     * @param clientKey    client id value to access APIs..
     * @param clientSecret client secret value to access APIs.
     */
    private void initializeIDPLib(String clientKey, String clientSecret) {
        String serverIP = Constants.DEFAULT_HOST;
        String prefIP = Preference.getString(AuthenticationActivity.this, Constants.PreferenceFlag.IP);

        if (prefIP != null) {
            serverIP = prefIP;
        }
        if (serverIP != null && !serverIP.isEmpty()) {
            ServerConfig utils = new ServerConfig();
            utils.setServerIP(serverIP);
            String serverURL = utils.getServerURL(context) + Constants.OAUTH_ENDPOINT;
            Editable tenantDomain = etDomain.getText();

            if (tenantDomain != null && !tenantDomain.toString().trim().isEmpty()) {
                username = etUsername.getText().toString().trim()
                        + context.getResources().getString(R.string.intent_extra_at)
                        + tenantDomain.toString().trim();

            } else {
                username = etUsername.getText().toString().trim();
            }

            Preference.putString(context, Constants.CLIENT_ID, clientKey);
            Preference.putString(context, Constants.CLIENT_SECRET, clientSecret);

            CredentialInfo info = new CredentialInfo();
            info.setClientID(clientKey);
            info.setClientSecret(clientSecret);
            info.setUsername(username);

            info.setPassword(passwordVal);
            info.setTokenEndPoint(serverURL);

            if (adminAccessToken != null) {
                info.setAdminAccessToken(adminAccessToken);
            }

            //adding device-specific scope
            String deviceScope = "device_" + deviceInfo.getDeviceId();
            info.setScopes(deviceScope);

            if (tenantDomain != null && !tenantDomain.toString().trim().isEmpty()) {
                info.setTenantDomain(tenantDomain.toString().trim());
            }

            IdentityProxy.getInstance().init(info, AuthenticationActivity.this, this.getApplicationContext());
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == ACTIVATION_REQUEST) {
            if (resultCode == Activity.RESULT_OK) {
                checkManifestPermissions();
                CommonUtils.callSystemApp(context, null, null, null);
                Log.i("onActivityResult", "Administration enabled!");
            } else {
                Log.i("onActivityResult", "Administration enable FAILED!");
                startDeviceAdminPrompt();
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onAPIAccessReceive(String status) {
        if (status != null) {
            if (status.trim().equals(Constants.Status.SUCCESSFUL)) {
                CommonDialogUtils.stopProgressDialog(progressDialog);
                if (isReLogin) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(context, R.string.authentication_successful, Toast.LENGTH_LONG).show();
                        }
                    });
                    LocalNotification.startPolling(context);
                    Preference.removePreference(context, Constants.TOKEN_EXPIRED);
                    NotificationManager mNotificationManager = (NotificationManager) context
                            .getSystemService(Context.NOTIFICATION_SERVICE);
                    mNotificationManager.cancel(Constants.TOKEN_EXPIRED, Constants.SIGN_IN_NOTIFICATION_ID);
                    finish();
                } else {
                    Preference.putString(context, Constants.USERNAME, username);
                    // Check network connection availability before calling the API.
                    if (CommonUtils.isNetworkAvailable(context)) {
                        getLicense();
                    } else {
                        CommonDialogUtils.showNetworkUnavailableMessage(AuthenticationActivity.this);
                    }
                }
            } else if (status.trim().equals(Constants.Status.AUTHENTICATION_FAILED)) {
                showAuthenticationError();
                // clearing client credentials from shared memory
                CommonUtils.clearClientCredentials(context);
            } else if (status.trim().equals(Constants.Status.INTERNAL_SERVER_ERROR)) {
                showInternalServerErrorMessage();
            } else {
                showAuthCommonErrorMessage();
            }
        } else {
            showAuthCommonErrorMessage();
        }

    }

    /**
     * Initialize get device license agreement. Check if the user has already
     * agreed to license agreement
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void getLicense() {
        boolean isAgreed = Preference.getBoolean(context, Constants.PreferenceFlag.IS_AGREED);
        deviceType = Preference.getString(context, Constants.DEVICE_TYPE);

        if (deviceType == null) {
            deviceType = Constants.DEFAULT_OWNERSHIP;
            Preference.putString(context, Constants.DEVICE_TYPE, deviceType);
        }

        if (deviceType != null && Constants.OWNERSHIP_BYOD.equals(deviceType.trim())) {

            if (!isAgreed) {
                final OnCancelListener cancelListener = new OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface arg0) {
                        CommonDialogUtils.getAlertDialogWithOneButtonAndTitle(context,
                                getResources().getString(R.string.error_enrollment_failed_detail),
                                getResources().getString(R.string.error_enrollment_failed),
                                getResources().getString(R.string.button_ok), null);
                    }
                };

                AuthenticationActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        progressDialog = CommonDialogUtils.showProgressDialog(context,
                                getResources().getString(R.string.dialog_license_agreement),
                                getResources().getString(R.string.dialog_please_wait), cancelListener);
                    }
                });

                // Check network connection availability before calling the API.
                if (CommonUtils.isNetworkAvailable(context)) {
                    getLicenseFromServer();
                } else {
                    CommonDialogUtils.stopProgressDialog(progressDialog);
                    CommonDialogUtils.showNetworkUnavailableMessage(context);
                }

            } else {
                startDeviceAdminPrompt();
            }
        } else if (deviceType != null) {
            checkManifestPermissions();
        }

    }

    /**
     * Retriever license agreement details from the server.
     */
    private void getLicenseFromServer() {
        String ipSaved = Constants.DEFAULT_HOST;
        String prefIP = Preference.getString(context.getApplicationContext(), Constants.PreferenceFlag.IP);
        if (prefIP != null) {
            ipSaved = prefIP;
        }

        if (ipSaved != null && !ipSaved.isEmpty()) {
            ServerConfig utils = new ServerConfig();
            utils.setServerIP(ipSaved);
            CommonUtils.callSecuredAPI(AuthenticationActivity.this,
                    utils.getAPIServerURL(context) + Constants.LICENSE_ENDPOINT, HTTP_METHODS.GET, null,
                    AuthenticationActivity.this, Constants.LICENSE_REQUEST_CODE);
        } else {
            Log.e(TAG, "There is no valid IP to contact the server");
        }
    }

    /**
     * Retriever configurations from the server.
     */
    private void checkManifestPermissions() {
        if (ActivityCompat.checkSelfPermission(AuthenticationActivity.this,
                android.Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(AuthenticationActivity.this,
                    new String[] { android.Manifest.permission.READ_PHONE_STATE,
                            android.Manifest.permission.ACCESS_COARSE_LOCATION,
                            android.Manifest.permission.ACCESS_FINE_LOCATION,
                            android.Manifest.permission.WRITE_EXTERNAL_STORAGE },
                    110);
        } else {
            getConfigurationsFromServer();
        }
        //Since the agent in Work Profile already granted the Device Admin Permissions,
        // the relevant preference flag is changed to True.
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            if (devicePolicyManager.isProfileOwnerApp(getApplicationContext().getPackageName())) {
                Preference.putBoolean(context, Constants.PreferenceFlag.DEVICE_ACTIVE, true);
            }
        } else {
            Log.e(TAG, "Phones running an SDK before lollipop, hence couldn't execute isProfileOwnerApp() method");
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        if (requestCode == 110) {
            getConfigurationsFromServer();
        }
    }

    /**
     * Retriever configurations from the server.
     */
    private void getConfigurationsFromServer() {
        final OnCancelListener cancelListener = new OnCancelListener() {

            @Override
            public void onCancel(DialogInterface arg0) {
                CommonDialogUtils.getAlertDialogWithOneButtonAndTitle(context,
                        getResources().getString(R.string.error_enrollment_failed_detail),
                        getResources().getString(R.string.error_enrollment_failed),
                        getResources().getString(R.string.button_ok), null);
            }
        };
        AuthenticationActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                progressDialog = CommonDialogUtils.showProgressDialog(context,
                        getResources().getString(R.string.dialog_sender_id),
                        getResources().getString(R.string.dialog_please_wait), cancelListener);
            }
        });

        String ipSaved = Constants.DEFAULT_HOST;
        String prefIP = Preference.getString(context.getApplicationContext(), Constants.PreferenceFlag.IP);
        if (prefIP != null) {
            ipSaved = prefIP;
        }

        if (ipSaved != null && !ipSaved.isEmpty()) {
            ServerConfig utils = new ServerConfig();
            utils.setServerIP(ipSaved);
            CommonUtils.callSecuredAPI(AuthenticationActivity.this,
                    utils.getAPIServerURL(context) + Constants.CONFIGURATION_ENDPOINT, HTTP_METHODS.GET, null,
                    AuthenticationActivity.this, Constants.CONFIGURATION_REQUEST_CODE);
        } else {
            Log.e(TAG, "There is no valid IP to contact the server");
        }
    }

    @Override
    public void onReceiveAPIResult(Map<String, String> result, int requestCode) {
        if (requestCode == Constants.LICENSE_REQUEST_CODE) {
            manipulateLicenseResponse(result);
        } else if (requestCode == Constants.CONFIGURATION_REQUEST_CODE) {
            manipulateConfigurationResponse(result);
        } else if (requestCode == Constants.DYNAMIC_CLIENT_REGISTER_REQUEST_CODE) {
            manipulateDynamicClientResponse(result);
        }
    }

    /**
     * Manipulates the dynamic client registration response received from server.
     *
     * @param result the result of the dynamic client request
     */
    private void manipulateDynamicClientResponse(Map<String, String> result) {
        String responseStatus;
        if (result != null) {
            responseStatus = result.get(Constants.STATUS);
            if (Constants.Status.CREATED.equals(responseStatus)) {
                String dynamicClientResponse = result.get(Constants.RESPONSE);
                if (dynamicClientResponse != null) {
                    Preference.putString(context, getResources().getString(R.string.shared_pref_client_credentials),
                            dynamicClientResponse);
                    startAuthentication();
                }
            } else if (Constants.Status.UNAUTHORIZED.equals(responseStatus)) {
                showAuthenticationError();
            } else if (!Constants.Status.SUCCESSFUL.equals(responseStatus)) {
                if (result.containsKey(Constants.RESPONSE)) {
                    showEnrollmentFailedErrorMessage(
                            "Code: " + responseStatus + "\nError: " + result.get(Constants.RESPONSE));
                } else {
                    showEnrollmentFailedErrorMessage("Code: " + responseStatus);
                }
            }
        } else {
            showEnrollmentFailedErrorMessage(null);
        }
    }

    /**
     * Manipulates the Configuration response received from server.
     *
     * @param result the result of the configuration request
     */
    private void manipulateConfigurationResponse(Map<String, String> result) {
        boolean proceedNext = true;
        String responseStatus;
        CommonDialogUtils.stopProgressDialog(progressDialog);

        if (result != null) {
            responseStatus = result.get(Constants.STATUS);
            if (Constants.Status.SUCCESSFUL.equals(responseStatus)) {
                String configurationResponse = result.get(Constants.RESPONSE);

                if (configurationResponse != null) {
                    try {
                        JSONObject config = new JSONObject(configurationResponse);
                        if (!config.isNull(context.getString(R.string.shared_pref_configuration))) {
                            JSONArray configList = new JSONArray(
                                    config.getString(context.getString(R.string.shared_pref_configuration)));
                            for (int i = 0; i < configList.length(); i++) {
                                JSONObject param = new JSONObject(configList.get(i).toString());
                                if (param.getString(context.getString(R.string.shared_pref_config_key)).trim()
                                        .equals(Constants.PreferenceFlag.NOTIFIER_TYPE)) {
                                    String type = param
                                            .getString(context.getString(R.string.shared_pref_config_value)).trim();
                                    if (type.equals(String.valueOf(Constants.NOTIFIER_CHECK))) {
                                        Preference.putString(context, Constants.PreferenceFlag.NOTIFIER_TYPE,
                                                Constants.NOTIFIER_FCM);
                                    } else {
                                        Preference.putString(context, Constants.PreferenceFlag.NOTIFIER_TYPE,
                                                Constants.NOTIFIER_LOCAL);
                                    }
                                } else if (param.getString(context.getString(R.string.shared_pref_config_key))
                                        .trim().equals(context.getString(R.string.shared_pref_frequency))
                                        && !param.getString(context.getString(R.string.shared_pref_config_value))
                                                .trim().isEmpty()) {
                                    Preference.putInt(context,
                                            getResources().getString(R.string.shared_pref_frequency),
                                            Integer.valueOf(param
                                                    .getString(context.getString(R.string.shared_pref_config_value))
                                                    .trim()));
                                } else if (param.getString(context.getString(R.string.shared_pref_config_key))
                                        .trim().equals(context.getString(R.string.shared_pref_gcm))) {
                                    Preference.putString(context,
                                            getResources().getString(R.string.shared_pref_sender_id),
                                            param.getString(context.getString(R.string.shared_pref_config_value))
                                                    .trim());
                                }
                            }
                            String notifierType = Preference.getString(context,
                                    Constants.PreferenceFlag.NOTIFIER_TYPE);
                            if (notifierType == null || notifierType.isEmpty()) {
                                setDefaultNotifier();
                            }
                        }

                    } catch (JSONException e) {
                        Log.e(TAG, "Error parsing configuration response JSON", e);
                        setDefaultNotifier();
                    }
                } else {
                    Log.e(TAG, "Empty configuration response");
                    setDefaultNotifier();
                }
            } else if (Constants.Status.UNAUTHORIZED.equals(responseStatus)) {
                String response = result.get(Constants.RESPONSE);
                Log.e(TAG, "Unauthorized :" + response);
                showAuthenticationError();
                proceedNext = false;
            } else if (Constants.Status.INTERNAL_SERVER_ERROR.equals(responseStatus)) {
                Log.e(TAG, "Empty configuration response.");
                setDefaultNotifier();
            } else {
                Log.e(TAG, "Empty configuration response.");
                setDefaultNotifier();
            }

        } else {
            Log.e(TAG, "Empty configuration response.");
            setDefaultNotifier();
        }
        if (proceedNext) {
            if (!CommonUtils.isServiceRunning(context, LocationService.class)) {
                Intent serviceIntent = new Intent(context, LocationService.class);
                context.startService(serviceIntent);
            }
            loadNextActivity();
        }
    }

    private void setDefaultNotifier() {
        Preference.putString(context, Constants.PreferenceFlag.NOTIFIER_TYPE, Constants.NOTIFIER_LOCAL);
        Preference.putInt(context, getResources().getString(R.string.shared_pref_frequency),
                Constants.DEFAULT_INTERVAL);
    }

    /**
     * Manipulates the License agreement response received from server.
     *
     * @param result the result of the license agreement request
     */
    private void manipulateLicenseResponse(Map<String, String> result) {
        String responseStatus;
        CommonDialogUtils.stopProgressDialog(progressDialog);

        if (result != null) {
            responseStatus = result.get(Constants.STATUS);
            if (Constants.Status.SUCCESSFUL.equals(responseStatus)) {
                String licenseAgreement = result.get(Constants.RESPONSE);

                if (licenseAgreement != null) {
                    Preference.putString(context, getResources().getString(R.string.shared_pref_eula),
                            licenseAgreement);
                    showAgreement(licenseAgreement, Constants.EULA_TITLE);
                } else {
                    CommonUtils.clearClientCredentials(context);
                    showErrorMessage(getResources().getString(R.string.error_enrollment_failed_detail),
                            getResources().getString(R.string.error_enrollment_failed));
                }

            } else if (Constants.Status.INTERNAL_SERVER_ERROR.equals(responseStatus)) {
                CommonUtils.clearClientCredentials(context);
                showInternalServerErrorMessage();
            } else if (Constants.Status.UNAUTHORIZED.equals(responseStatus)) {
                String response = result.get(Constants.RESPONSE);
                Log.e(TAG, "Unauthorized :" + response);
                showAuthenticationError();
            } else {
                CommonUtils.clearClientCredentials(context);
                showEnrollmentFailedErrorMessage(responseStatus);
            }

        } else {
            CommonUtils.clearClientCredentials(context);
            showEnrollmentFailedErrorMessage(null);
        }
    }

    private void showNoSystemAppDialog() {
        AlertDialog.Builder alertDialog = CommonDialogUtils.getAlertDialogWithNeutralButtonAndTitle(context,
                getResources().getString(R.string.dialog_title_system_app_required),
                getResources().getString(R.string.dialog_system_app_required),
                getResources().getString(R.string.ok), dialogClickListener);
        alertDialog.show();
    }

    private void showErrorMessage(String message, String title) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setMessage(message);
        builder.setTitle(title);
        builder.setCancelable(true);
        builder.setPositiveButton(getResources().getString(R.string.button_ok),
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        cancelEntry();
                        dialog.dismiss();
                    }
                });
        AlertDialog alert = builder.create();
        alert.show();
    }

    /**
     * Show the license text retrieved from the server.
     *
     * @param licenseText Message text to be shown as the license.
     * @param title   Title of the license.
     */
    private void showAgreement(final String licenseText, final String title) {
        AuthenticationActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                final Dialog dialog = new Dialog(context, R.style.Dialog);
                dialog.setContentView(R.layout.dialog_license);
                dialog.setCancelable(false);

                WebView webView = (WebView) dialog.findViewById(R.id.webViewLicense);
                webView.loadDataWithBaseURL(null, licenseText, Constants.MIME_TYPE, Constants.ENCODING_METHOD,
                        null);

                TextView textViewTitle = (TextView) dialog.findViewById(R.id.textViewDeviceNameTitle);
                textViewTitle.setText(title);

                Button btnAgree = (Button) dialog.findViewById(R.id.dialogButtonOK);
                Button btnCancel = (Button) dialog.findViewById(R.id.dialogButtonCancel);

                btnAgree.setOnClickListener(new OnClickListener() {
                    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
                    @Override
                    public void onClick(View v) {
                        Preference.putBoolean(context, Constants.PreferenceFlag.IS_AGREED, true);
                        dialog.dismiss();
                        //load the next intent based on ownership type
                        startDeviceAdminPrompt();
                    }
                });

                btnCancel.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        dialog.dismiss();
                        CommonUtils.clearClientCredentials(context);
                        cancelEntry();
                    }
                });

                dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
                    @Override
                    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                        if (keyCode == KeyEvent.KEYCODE_SEARCH
                                && event.getRepeatCount() == Constants.DEFAULT_REPEAT_COUNT) {
                            return true;
                        } else if (keyCode == KeyEvent.KEYCODE_BACK
                                && event.getRepeatCount() == Constants.DEFAULT_REPEAT_COUNT) {
                            return true;
                        }
                        return false;
                    }
                });

                dialog.show();
            }
        });
    }

    private void loadPinCodeActivity() {
        Intent intent = new Intent(AuthenticationActivity.this, PinCodeActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.putExtra(Constants.USERNAME, usernameVal);
        startActivity(intent);
        finish();
    }

    private void loadRegistrationActivity() {
        Intent intent = new Intent(AuthenticationActivity.this, RegistrationActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.putExtra(Constants.USERNAME, usernameVal);
        startActivity(intent);
        finish();
    }

    private void cancelEntry() {
        Preference.putBoolean(context, Constants.PreferenceFlag.IS_AGREED, false);
        Preference.putBoolean(context, Constants.PreferenceFlag.REGISTERED, false);
        Preference.putString(context, Constants.PreferenceFlag.IP, null);

        Intent intentIP = new Intent(AuthenticationActivity.this, SplashActivity.class);
        intentIP.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intentIP);
        finish();
    }

    /**
     * Validation done to see if the username and password fields are properly
     * entered.
     */
    private void enableSubmitIfReady() {

        boolean isReady = false;

        if (etUsername.getText().toString().length() >= 1 && etPassword.getText().toString().length() >= 1) {
            isReady = true;
        }

        if (isReady) {
            btnSignIn.setBackgroundResource(R.drawable.btn_orange);
            btnSignIn.setTextColor(ContextCompat.getColor(this, R.color.white));
            btnSignIn.setEnabled(true);
        } else {
            btnSignIn.setBackgroundResource(R.drawable.btn_grey);
            btnSignIn.setTextColor(ContextCompat.getColor(this, R.color.black));
            btnSignIn.setEnabled(false);
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && !isReLogin) {
            finish();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    private DialogInterface.OnClickListener senderIdFailedClickListener = new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            btnSignIn.setBackgroundResource(R.drawable.btn_orange);
            btnSignIn.setTextColor(ContextCompat.getColor(AuthenticationActivity.this, R.color.white));
            btnSignIn.setEnabled(true);
        }
    };

    /**
     * Shows enrollment failed error.
     */
    private void showEnrollmentFailedErrorMessage(String message) {
        CommonDialogUtils.stopProgressDialog(progressDialog);
        final String messageDescription;
        String descriptionText = getResources().getString(R.string.error_enrollment_failed_detail);
        if (message != null) {
            messageDescription = descriptionText + " " + message;
        } else {
            messageDescription = descriptionText;
        }
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                CommonDialogUtils.getAlertDialogWithOneButtonAndTitle(context,
                        getResources().getString(R.string.error_enrollment_failed), messageDescription,
                        getResources().getString(R.string.button_ok), senderIdFailedClickListener);
            }
        });

    }

    /**
     * Shows internal server error message for authentication.
     */
    private void showInternalServerErrorMessage() {
        CommonDialogUtils.stopProgressDialog(progressDialog);
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                CommonDialogUtils.getAlertDialogWithOneButtonAndTitle(context,
                        getResources().getString(R.string.title_head_connection_error),
                        getResources().getString(R.string.error_internal_server),
                        getResources().getString(R.string.button_ok), null);
            }
        });

    }

    /**
     * Shows credentials error message for authentication.
     */
    private void showAuthenticationError() {
        CommonDialogUtils.stopProgressDialog(progressDialog);
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                CommonDialogUtils.getAlertDialogWithOneButtonAndTitle(context,
                        getResources().getString(R.string.title_head_authentication_error),
                        getResources().getString(R.string.error_authentication_failed),
                        getResources().getString(R.string.button_ok), null);
            }
        });
    }

    /**
     * Shows common error message for authentication.
     */
    private void showAuthCommonErrorMessage() {
        CommonDialogUtils.stopProgressDialog(progressDialog);
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                CommonDialogUtils.getAlertDialogWithOneButtonAndTitle(context,
                        getResources().getString(R.string.title_head_authentication_error),
                        getResources().getString(R.string.error_for_all_unknown_authentication_failures),
                        getResources().getString(R.string.button_ok), null);
            }
        });

    }

    /**
     * This method is used to retrieve consumer-key and consumer-secret.
     */
    private void getClientCredentials() {
        String ipSaved = Constants.DEFAULT_HOST;
        String prefIP = Preference.getString(context.getApplicationContext(), Constants.PreferenceFlag.IP);
        if (prefIP != null) {
            ipSaved = prefIP;
        }
        String authenticationTitle;
        if (currentTenant != null) {
            authenticationTitle = String.format(getResources().getString(R.string.dialog_registering),
                    currentTenant.getDisplayName());
        } else {
            authenticationTitle = getResources().getString(R.string.dialog_authenticate);
        }
        progressDialog = ProgressDialog.show(context, authenticationTitle,
                getResources().getString(R.string.dialog_message_please_wait), true);
        if (ipSaved != null && !ipSaved.isEmpty()) {
            ServerConfig utils = new ServerConfig();
            utils.setServerIP(ipSaved);
            String applicationName = Constants.API_APPLICATION_NAME_PREFIX + deviceInfo.getDeviceId();
            ApiRegistrationProfile apiRegistrationProfile = new ApiRegistrationProfile();
            apiRegistrationProfile.setApplicationName(applicationName);
            apiRegistrationProfile.setIsAllowedToAllDomains(false);
            apiRegistrationProfile.setIsMappingAnExistingOAuthApp(false);
            apiRegistrationProfile.setTags(SUBSCRIBED_API);
            DynamicClientManager dynamicClientManager = new DynamicClientManager();
            try {
                if (adminAccessToken != null) {
                    dynamicClientManager.getClientCredentials(adminAccessToken, utils, context,
                            AuthenticationActivity.this, apiRegistrationProfile);
                } else {
                    dynamicClientManager.getClientCredentials(usernameVal, passwordVal, utils, context,
                            AuthenticationActivity.this, apiRegistrationProfile);
                }
                Preference.putString(context, Constants.CLIENT_NAME, applicationName);
            } catch (AndroidAgentException e) {
                String message = "Client credentials generation failed";
                Log.e(TAG, message, e);
                showEnrollmentFailedErrorMessage(message);
            }
        } else {
            String message = "There is no valid IP to contact the server";
            Log.e(TAG, message);
            showEnrollmentFailedErrorMessage(message);
        }
    }

    /**
     * This method is used to bypass the intents based on the
     * ownership type.
     */
    private void loadNextActivity() {
        if (Constants.OWNERSHIP_BYOD.equalsIgnoreCase(deviceType)) {
            loadPinCodeActivity();
        } else {
            loadRegistrationActivity();
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onAuthenticated(boolean status, int requestCode) {
        if (requestCode == Constants.AUTHENTICATION_REQUEST_CODE) {
            if (status && org.wso2.iot.agent.proxy.utils.Constants.Authenticator.AUTHENTICATOR_IN_USE
                    .equals(org.wso2.iot.agent.proxy.utils.Constants.Authenticator.MUTUAL_SSL_AUTHENTICATOR)) {
                if (Constants.SKIP_LICENSE) {
                    startDeviceAdminPrompt();
                } else {
                    getLicense();
                }
            }
        }
    }

}