com.takondi.tartt.ARActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.takondi.tartt.ARActivity.java

Source

package com.takondi.tartt;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.takondi.tartt.helper.Const;
import com.takondi.tartt.helper.GuiHelper;
import com.takondi.tartt.helper.GuiHelper.GUI_STATE;
import com.takondi.tartt.zxing.QrCodeResultListener;
import com.takondi.tartt.zxing.SampleZXingPlugin;
import com.takondi.tarttsdk.ChannelManager;
import com.takondi.tarttsdk.Tartt;
import com.takondi.tarttsdk.model.Channel;
import com.takondi.tarttsdk.model.TarttRequestOptions;
import com.takondi.tarttsdk.utils.Utils;
import com.wikitude.architect.ArchitectJavaScriptInterfaceListener;
import com.wikitude.architect.ArchitectStartupConfiguration;
import com.wikitude.architect.ArchitectView;
import com.wikitude.common.plugins.PluginManager;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;

public class ARActivity extends AppCompatActivity
        implements ArchitectView.ArchitectUrlListener, ArchitectJavaScriptInterfaceListener,
        ArchitectView.ArchitectWorldLoadedListener, ChannelManager.Callback, QrCodeResultListener {
    private final static String TAG = ARActivity.class.getSimpleName();

    private final static String ARG_INIT_WITH_QR = "arg_init_qr";
    private static final String LANG_FALLBACK = "de";
    private static final String JS_START_EXPERIENCE = "startExperience";
    private static final String JS_BARCODE_RECEIVED = "performBarcodeRequest";
    private static final String JS_GET_USER_DEFAULTS_RESULT = "getUserDefaultsResult";
    private static final String JS_SET_USER_DEFAULTS_RESULT = "setUserDefaultsResult";
    private static final String JS_GET_USER_DEFAULTS_BY_KEY_RESULT = "getUserDefaultsByKeyResult";
    private static final String JS_RESET_USER_DEFAULTS_RESULT = "resetUserDefaultsResult";
    private static final String JS_DESTROY = "AR.context.destroyAll()";
    private static final String URL_ARCHITECTSDK_SCHEME = "architectsdk";
    private static final String METHOD_TARGET_LOADED = "targetsLoaded";
    private static final String METHOD_ENTER_VISION = "augmentationsOnEnterFieldOfVision";
    private static final String METHOD_EXIT_VISION = "augmentationsOnExitFieldOfVision";
    private static final String METHOD_READY_FOR_EXECUTION = "readyForExecution";
    private static final String METHOD_QR_TRIGGER = "qrCodeTrigger";
    private static final String METHOD_CHANGE_CHANNEL = "changeChannel";
    private static final String METHOD_GET_USER_DEFAULT_BY_KEY = "getUserDefaultsByKey";
    private static final String METHOD_GET_USER_DEFAULT = "getUserDefaults";
    private static final String METHOD_SET_USER_DEFAULT = "setUserDefaults";
    private static final String METHOD_RESET_USER_DEFAULT = "resetUserDefaults";
    private static final String QR_TARTT_SCHEME = "tartt";
    private static final String JSON_METHOD = "method";
    private static final String JSON_PARAMS = "parameters";
    private static final String QR_CHANNEL_HOST = "channelCode";

    private ArchitectView mArchitectView;
    private SampleZXingPlugin mQrPlugin;

    private long mBytesToLoad;
    private GuiHelper mGuiHelper;
    private ChannelManager mChannelManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (areAnyRequiredPermissionsMissing()) {
            Intent intent = new Intent(this, PermissionActivity.class);
            startActivity(intent);
            finish();
            return;
        }

        setContentView(R.layout.activity_ar);

        mGuiHelper = new GuiHelper(this);
        mChannelManager = new ChannelManager(this);
        mArchitectView = (ArchitectView) findViewById(R.id.architectView);

        mGuiHelper.mSwitchButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                switchChannelRequested();
            }
        });
        mGuiHelper.mRetryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doInitialLoad();
            }
        });
        mGuiHelper.mCancelButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mChannelManager.cancel();
                mGuiHelper.changeGuiState(GUI_STATE.SCAN_QR);
                mQrPlugin.activate();
            }
        });
        final ArchitectStartupConfiguration config = new ArchitectStartupConfiguration();
        config.setLicenseKey(Const.WIKITUDE_KEY);
        config.setFeatures(ArchitectStartupConfiguration.Features.ImageTracking);
        try {
            mArchitectView.onCreate(config);
        } catch (RuntimeException e) {
            e.printStackTrace();
            mArchitectView = null;
        }
    }

    private boolean areAnyRequiredPermissionsMissing() {
        return ContextCompat.checkSelfPermission(this,
                Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this,
                        Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
    }

    @Override
    protected void onPostCreate(@Nullable Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        if (this.mArchitectView != null) {
            mArchitectView.onPostCreate();
            mQrPlugin = new SampleZXingPlugin("com.plugin.zxing", this);
            mArchitectView.registerPlugin(mQrPlugin, new PluginManager.PluginErrorCallback() {
                @Override
                public void onRegisterError(int i, String s) {
                    Toast.makeText(ARActivity.this, "The barcode scanner plugin could not be loaded.",
                            Toast.LENGTH_SHORT).show();
                }
            });
            mArchitectView.registerWorldLoadedListener(this);
            mArchitectView.addArchitectJavaScriptInterfaceListener(this);
            mArchitectView.registerUrlListener(this);

            if (!ArchitectView.isDeviceSupported(ARActivity.this)) {
                mGuiHelper.changeGuiState(GUI_STATE.HIDE);
                Toast.makeText(ARActivity.this, "Device is not supported", Toast.LENGTH_SHORT).show();
            } else if (getIntent() != null && getIntent().hasExtra(ARG_INIT_WITH_QR)) {
                mGuiHelper.changeGuiState(GUI_STATE.SCAN_QR);
                loadDefaultWorld();
                mArchitectView.post(new Runnable() {
                    @Override
                    public void run() {
                        onQrCodeRead(getIntent().getStringExtra(ARG_INIT_WITH_QR));
                    }
                });

            } else {
                doInitialLoad();
            }
        }
    }

    private void doInitialLoad() {
        mGuiHelper.changeGuiState(GUI_STATE.INITIAL_LOADING);
        mChannelManager.findChannels(this);
    }

    private void loadDefaultWorld() {
        mArchitectView.callJavascript(JS_DESTROY);
        try {
            String url = Const.DUMMY_WORLD_URL;
            mArchitectView.load(url);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (mGuiHelper.mGuiState == GUI_STATE.SCAN_QR || mGuiHelper.mGuiState == GUI_STATE.SCAN) {
            if (mQrPlugin != null) {
                mQrPlugin.activate();
            }
        }
    }

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

    @Override
    protected void onPause() {
        super.onPause();
        if (this.mArchitectView != null) {
            mArchitectView.onPause();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mQrPlugin != null) {
            mQrPlugin.deactivate();
        }
        mChannelManager.cancel();
    }

    @Override
    protected void onDestroy() {
        if (this.mArchitectView != null) {
            mArchitectView.onDestroy();
        }
        super.onDestroy();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        if (mArchitectView != null) {
            mArchitectView.onLowMemory();
        }
    }

    @Override
    public void worldWasLoaded(String s) {
        Log.d(TAG, "worldWasLoaded " + s);
    }

    @Override
    public boolean urlWasInvoked(String url) {
        Log.d(TAG, "urlWasInvoked " + url);
        if (url != null) {
            Uri uri = Uri.parse(url);
            if (URL_ARCHITECTSDK_SCHEME.equals(uri.getScheme())) {
                JSONObject paramJson = new JSONObject();
                if (!uri.getQueryParameterNames().isEmpty()) {
                    for (String param : uri.getQueryParameterNames()) {
                        try {
                            paramJson.put(param, uri.getQueryParameter(param));
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                }
                handleEvent(uri.getHost(), paramJson);
            }
        }
        return false;
    }

    @Override
    public void onJSONObjectReceived(final JSONObject jsonObject) {
        Log.d(TAG, "onJSONObjectReceived " + jsonObject.toString());
        if (jsonObject.has(JSON_METHOD) && jsonObject.has(JSON_PARAMS)) {
            String methodName = jsonObject.optString(JSON_METHOD);
            JSONObject paramsJson = jsonObject.optJSONObject(JSON_PARAMS);
            handleEvent(methodName, paramsJson);
        }
    }

    private void handleEvent(final String methodName, final JSONObject paramJson) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                switch (methodName) {
                case METHOD_READY_FOR_EXECUTION:
                    mArchitectView
                            .callJavascript(JS_START_EXPERIENCE + "("
                                    + Utils.getStartExperienceJson(ARActivity.this,
                                            PreferenceManager.getInstance(ARActivity.this).getDefaults(null))
                                    + ")");
                    break;
                case METHOD_TARGET_LOADED:
                    mGuiHelper.changeGuiState(GUI_STATE.SCAN);
                    mQrPlugin.activate();
                    break;
                case METHOD_ENTER_VISION:
                    mGuiHelper.changeGuiState(GUI_STATE.HIDE);
                    mQrPlugin.deactivate();
                    break;
                case METHOD_EXIT_VISION:
                    mGuiHelper.changeGuiState(GUI_STATE.SCAN);
                    mQrPlugin.activate();
                    break;
                case METHOD_QR_TRIGGER:
                    processQr(paramJson.optString("code"));
                    break;
                case METHOD_CHANGE_CHANNEL:
                    switchChannelRequested();
                    break;
                case METHOD_GET_USER_DEFAULT_BY_KEY:
                    String key = paramJson.optString("key");
                    String value = PreferenceManager.getInstance(ARActivity.this).getDefault(key);
                    String taskId = paramJson.optString("taskid");
                    taskId = "".equals(taskId) ? null : taskId;
                    try {
                        JSONObject obj = new JSONObject();
                        obj.put("key", key);
                        obj.put("value", value == null ? JSONObject.NULL : value);
                        obj.put("taskid", taskId);
                        mArchitectView
                                .callJavascript(JS_GET_USER_DEFAULTS_BY_KEY_RESULT + "(" + obj.toString() + ")");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    break;
                case METHOD_GET_USER_DEFAULT:
                    String prefix = paramJson.optString("prefix");
                    prefix = "".equals(prefix) ? null : prefix;
                    String taskIdGetDefaults = paramJson.optString("taskid");
                    taskIdGetDefaults = "".equals(taskIdGetDefaults) ? null : taskIdGetDefaults;
                    try {
                        JSONObject obj = PreferenceManager.getInstance(ARActivity.this).getDefaults(prefix);
                        obj.put("taskid", taskIdGetDefaults);
                        mArchitectView.callJavascript(JS_GET_USER_DEFAULTS_RESULT + "(" + obj.toString() + ")");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    break;
                case METHOD_SET_USER_DEFAULT:
                    String keySet = paramJson.optString("key");
                    keySet = "".equals(keySet) ? null : keySet;
                    String setValue = paramJson.optString("value");
                    setValue = "".equals(setValue) ? null : setValue;
                    String taskIdSet = paramJson.optString("taskid");
                    taskIdSet = "".equals(taskIdSet) ? null : taskIdSet;
                    try {
                        JSONObject obj = PreferenceManager.getInstance(ARActivity.this).setDefault(keySet,
                                setValue);
                        obj.put("taskid", taskIdSet);
                        mArchitectView.callJavascript(JS_SET_USER_DEFAULTS_RESULT + "(" + obj.toString() + ")");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    break;
                case METHOD_RESET_USER_DEFAULT:
                    String prefixReset = paramJson.optString("prefix");
                    prefixReset = "".equals(prefixReset) ? null : prefixReset;
                    String resetTaskId = paramJson.optString("taskid");
                    resetTaskId = "".equals(resetTaskId) ? null : resetTaskId;
                    JSONObject obj = PreferenceManager.getInstance(ARActivity.this).deleteDefaults(prefixReset);
                    try {
                        obj.put("taskid", resetTaskId);
                        mArchitectView.callJavascript(JS_RESET_USER_DEFAULTS_RESULT + "(" + obj.toString() + ")");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    break;
                }
            }
        });
    }

    private void switchChannelRequested() {
        loadDefaultWorld();
        mGuiHelper.changeGuiState(GUI_STATE.SCAN_QR);
        mQrPlugin.activate();
    }

    @Override
    public void onQrCodeRead(String qrContent) {
        mQrPlugin.deactivate();
        //only react to qr codes when we are in QR or scan page mode
        if ((mGuiHelper.mGuiState == GUI_STATE.SCAN_QR || mGuiHelper.mGuiState == GUI_STATE.SCAN)
                && qrContent != null) {
            Log.d(TAG, "qr: " + qrContent);
            mArchitectView.callJavascript(JS_BARCODE_RECEIVED + "('" + qrContent + "');");
        } else {
            mQrPlugin.activate();
        }
    }

    private void processQr(String qrContent) {
        Uri qrUri = Uri.parse(qrContent);
        if (QR_TARTT_SCHEME.equals(qrUri.getScheme()) && QR_CHANNEL_HOST.equals(qrUri.getHost())
                && qrUri.getQueryParameter(Channel.CHANNEL_KEY) != null) {
            //we now might also be receiving a scanned qr/barcode out of an active world, so let's make sure to deactivate the world's AR
            loadDefaultWorld();

            mGuiHelper.changeGuiState(GUI_STATE.LOADING);
            TarttRequestOptions newConfig = Tartt
                    .getInitialConfigForChannel(qrUri.getQueryParameter(Channel.CHANNEL_KEY));
            try {
                if (qrUri.getQueryParameter(Channel.STATE) != null) {
                    newConfig.setState(TarttRequestOptions.State
                            .getStateForValue(Integer.valueOf(qrUri.getQueryParameter(Channel.STATE))));
                }
                if (qrUri.getQueryParameter(Channel.TARGET_TYPE) != null) {
                    newConfig.setTargetType(
                            TarttRequestOptions.TargetType.valueOf(qrUri.getQueryParameter(Channel.TARGET_TYPE)));
                }
                if (qrUri.getQueryParameter(Channel.ENV_TYPE) != null) {
                    newConfig.setEnvType(
                            TarttRequestOptions.EnvironmentType.valueOf(qrUri.getQueryParameter(Channel.ENV_TYPE)));
                }
                if (qrUri.getQueryParameter(Channel.TARGET_API) != null) {
                    newConfig.setTargetApi(Integer.valueOf(qrUri.getQueryParameter(Channel.TARGET_API)));
                }
                if (qrUri.getQueryParameter(Channel.LANGUAGE) != null) {
                    newConfig.setLanguage(qrUri.getQueryParameter(Channel.LANGUAGE));
                }
            } catch (NumberFormatException eNFE) {
                Log.e(TAG, "QR-Code contained invalid value for parameter (requires a number)");
            } catch (IllegalArgumentException eIAE) {
                Log.e(TAG, "QR-Code contained invalid value for a parameter (not in valid range)");
            }
            mChannelManager.fetchFilesForChannelWithConfig(newConfig, this);
        } else {
            mQrPlugin.activate();
        }
    }

    @Override
    public void worldLoadFailed(int i, String s, String s1) {
        Log.d(TAG, "worldLoadFailed i: " + i + " s: " + s + "  s1: " + s1);
    }

    @Override
    public void onMultipleChannelsAvailable() {
        loadDefaultWorld();
        mGuiHelper.changeGuiState(GUI_STATE.SCAN_QR);
        mQrPlugin.activate();
    }

    @Override
    public void onNoChannelFound(TarttRequestOptions tarttRequestOptions) {
        if (!LANG_FALLBACK.equals(tarttRequestOptions.getLanguage())) {
            Log.d(TAG, "onNoChannelFound fall back to " + LANG_FALLBACK);
            //No worlds could be initialized for the default language, so we fall back to LANG_FALLBACK
            tarttRequestOptions.setLanguage(LANG_FALLBACK);
            if (tarttRequestOptions.getChannelKey() == null) {
                //we fallback for our initial call, so we still want onMultipleChannelsAvailable() to be invoked if multiple channels are found that we can select between
                mChannelManager.findChannelsWithConfig(tarttRequestOptions, this);
            } else {
                //we fallback for a call that already has a channel specified, so we simply want to get the latest data set for it
                mChannelManager.fetchFilesForChannelWithConfig(tarttRequestOptions, this);
            }
        } else {
            Log.e(TAG, "onNoChannelFound no fallback");
            Toast.makeText(this, "No channels found", Toast.LENGTH_SHORT).show();
            if (tarttRequestOptions.getChannelKey() == null) {
                //we fallback for our initial call, no point in showing the qr scanner
                mGuiHelper.changeGuiState(GUI_STATE.HIDE);
            } else {
                //we fallback for a call that already has a channel specified, so we let the user select a different one
                loadDefaultWorld();
                mGuiHelper.changeGuiState(GUI_STATE.SCAN_QR);
                mQrPlugin.activate();
            }
        }
    }

    @Override
    public void onDownloadStarted(long bytesToLoad) {
        Log.d(TAG, "onDownloadStarted " + bytesToLoad);
        mBytesToLoad = bytesToLoad;
    }

    @Override
    public void onDownloadProgress(long bytesLoaded) {
        int progressPercent = (int) ((bytesLoaded * 100) / mBytesToLoad);
        if (progressPercent >= 1) {
            //only switch to progress bar when we show some progress, otherwise it'd be barely visible
            if (mGuiHelper.mGuiState != GUI_STATE.INITIAL_PROGRESS && mGuiHelper.mGuiState != GUI_STATE.PROGRESS) {
                mGuiHelper.changeGuiState(
                        mGuiHelper.mGuiState == GUI_STATE.INITIAL_LOADING ? GUI_STATE.INITIAL_PROGRESS
                                : GUI_STATE.PROGRESS);
            }
            mGuiHelper.mProgressBar.setProgress(progressPercent);
        }
    }

    @Override
    public void onNewChannelFilesAvailable(String channelKey, File folder) {
        Log.d(TAG, "onNewChannelFilesAvailable " + folder.getPath());
        //hiding the cancel button, because we can't cancel the wikitude loading
        mGuiHelper.changeGuiState((mGuiHelper.mGuiState == GUI_STATE.INITIAL_LOADING
                || mGuiHelper.mGuiState == GUI_STATE.INITIAL_PROGRESS) ? GUI_STATE.INITIAL_LOADING
                        : GUI_STATE.LOADING_NO_CANCEL);
        try {
            if (this.mArchitectView != null) {
                mArchitectView.callJavascript(JS_DESTROY);
                Log.d(TAG, "load " + "file://" + folder.getPath() + File.separator + "index.html");
                mArchitectView.load("file://" + folder.getPath() + File.separator + "index.html");
            }
        } catch (IOException e) {
            Log.e(TAG, "An error occured loading the AR world");
            Toast.makeText(ARActivity.this, "An error occured loading the AR world", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onError(ChannelManager.TARTT_ERROR tarttError) {
        Log.e(TAG, "onError " + tarttError);
        if (mGuiHelper.mGuiState == GUI_STATE.INITIAL_LOADING
                || mGuiHelper.mGuiState == GUI_STATE.INITIAL_PROGRESS) {
            mGuiHelper.changeGuiState(GUI_STATE.RETRY);
        } else {
            loadDefaultWorld();
            mGuiHelper.changeGuiState(GUI_STATE.SCAN_QR);
            mQrPlugin.activate();
            Toast.makeText(ARActivity.this, "An error occured", Toast.LENGTH_SHORT).show();
        }
    }
}