edu.umich.oasis.testapp.TestActivity.java Source code

Java tutorial

Introduction

Here is the source code for edu.umich.oasis.testapp.TestActivity.java

Source

/*
 * Copyright (C) 2017 The Regents of the University of Michigan
 *
 * 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 edu.umich.oasis.testapp;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.Toast;

import org.apache.commons.lang3.time.StopWatch;

import edu.umich.oasis.client.OASISConnection;
import edu.umich.oasis.client.Sealed;
import edu.umich.oasis.client.Soda;
import edu.umich.oasis.common.IOASISService;
import edu.umich.oasis.common.OASISConstants;
import edu.umich.oasis.common.SodaDescriptor;

public class TestActivity extends Activity {

    OASISConnection connection;

    Soda.S0<TestSoda> init0;
    Soda.S1<String, TestSoda> init1;

    Soda.S2<String, String, String> concat;

    Soda.S1<TestSoda, String> getState;
    Soda.S2<TestSoda, String, String> swapState;
    Soda.S2<TestSoda, String, Void> log;
    Soda.S2<String, String, Void> logStatic;

    Soda.S1<String, String> throwStatic;
    Soda.S2<TestSoda, String, Void> throwInstance;

    Soda.S2<String, Boolean, Void> putValueSoda;
    Soda.S0<Void> toastValueSoda;
    Soda.S0<Void> pushValueSoda;
    Soda.S0<Void> toastECUSoda;
    Soda.S0<Void> pushECUSoda;
    Soda.S0<Void> pushOtherSoda;

    Soda.S1<Boolean, Void> nop;

    Soda.S1<Long, String> sleep;

    EditText kvsValueField;
    CheckBox shouldTaintBox;
    RelativeLayout rootLayout;
    Spinner sandboxCount;
    Spinner sandboxCountType;
    EditText perfPassCount;
    CheckBox taintPerfBox;

    private static final String TAG = "OASIS.TestActivity";

    public void runTest(View ignored) {
        try {
            setButtonsEnabled(false);
            OASISConnection conn = connection;

            // start resolving
            init0 = conn.resolveConstructor(TestSoda.class);
            init1 = conn.resolveConstructor(TestSoda.class, String.class);

            concat = conn.resolveStatic(String.class, TestSoda.class, "concat", String.class, String.class);

            getState = conn.resolveInstance(String.class, TestSoda.class, "getState");
            swapState = conn.resolveInstance(String.class, TestSoda.class, "swapState", String.class);

            log = conn.resolveInstance(void.class, TestSoda.class, "log", String.class);
            logStatic = conn.resolveStatic(void.class, TestSoda.class, "log", String.class, String.class);

            throwStatic = conn.resolveStatic(String.class, TestSoda.class, "throwStatic", String.class);
            throwInstance = conn.resolveInstance(void.class, TestSoda.class, "throwInstance", String.class);
            sleep = conn.resolveStatic(String.class, TestSoda.class, "sleep", long.class);
            Log.i(TAG, "Done resolving");

            ComponentName cn = new ComponentName(getPackageName(), "testChannel");
            SodaDescriptor sd = logStatic.getDescriptor();
            conn.getRawInterface().subscribeEventChannel(cn, sd);

            Log.i(TAG, "Constructing with init0");
            Sealed<TestSoda> obj1 = init0.call();
            obj1.buildCall(log).arg("obj1").call();

            Log.i(TAG, "Constructing with init1");
            Sealed<TestSoda> obj2 = init1.arg("<foobar>").call();
            Sealed<String> obj2State = getState.arg(obj2).call();
            logStatic.arg("obj2State").arg(obj2State).call();

            Log.i(TAG, "Calling static method");
            Sealed<String> newState = concat.arg("state").arg(obj2State).call();
            logStatic.arg("newState").arg(newState).call();

            Log.i(TAG, "Calling instance with inout");
            Sealed<String> oldState1 = swapState.inOut(obj1).arg(newState).call();
            logStatic.arg("oldState1").arg(oldState1).call();
            obj1.buildCall(log).arg("obj1'").call();

            Log.i(TAG, "Calling instance without inout");
            Sealed<String> oldState2 = swapState.in(obj2).arg(newState).call();
            logStatic.arg("oldState2").arg(oldState2).call();
            obj2.buildCall(log).arg("obj2'").call();

            Log.i(TAG, "Testing exception propagation - static");
            Sealed<String> excStatic = throwStatic.in("static test #1").call();
            Sealed<String> excStatic2 = throwStatic.in("static test #2").call();
            logStatic.arg(excStatic).arg(excStatic2).call();

            Log.i(TAG, "Testing exception propagation - instance");

            obj1.buildCall(throwInstance).arg("instance test - obj1").call();
            obj1.buildCall(log).argNull().call();

            throwInstance.in(obj2).arg("instance test - obj2").call();
            obj2.buildCall(log).argNull().call();

            Log.i(TAG, "Testing async method calls");
            Sealed<String> sleepResult = sleep.arg(15 * 1000L).asAsync().call();
            logStatic.arg("Sleep result").arg(sleepResult).asAsync().call();

            Log.i(TAG, "All done!");

        } catch (Exception e) {
            Log.wtf(TAG, "Exception in post-connect handler", e);
        } finally {
            Log.i(TAG, "Finishing");
            setButtonsEnabled(true);
        }
    }

    public void putValue(View ignored) {
        try {
            setButtonsEnabled(false);

            if (putValueSoda == null) {
                putValueSoda = connection.resolveStatic(void.class, KeyValueTest.class, "setValue", String.class,
                        boolean.class);
            }

            putValueSoda.arg(kvsValueField.getText().toString()).arg(shouldTaintBox.isChecked()).call();

        } catch (Exception e) {
            Log.wtf(TAG, "Exception in putValue()", e);
        } finally {
            Log.i(TAG, "Finishing");
            setButtonsEnabled(true);
        }
    }

    public void toastValue(View ignored) {
        try {
            setButtonsEnabled(false);

            if (toastValueSoda == null) {
                toastValueSoda = connection.resolveStatic(void.class, KeyValueTest.class, "toastValue");
            }

            toastValueSoda.call();
        } catch (Exception e) {
            Log.wtf(TAG, "Exception in toastValue()", e);
        } finally {
            Log.i(TAG, "Finishing");
            setButtonsEnabled(true);
        }
    }

    public void pushValue(View ignored) {
        try {
            setButtonsEnabled(false);

            if (pushValueSoda == null) {
                pushValueSoda = connection.resolveStatic(void.class, KeyValueTest.class, "pushValue");
            }

            pushValueSoda.call();
        } catch (Exception e) {
            Log.wtf(TAG, "Exception in pushValue()", e);
        } finally {
            Log.i(TAG, "Finishing");
            setButtonsEnabled(true);
        }
    }

    public void toastECU(View ignored) {
        try {
            setButtonsEnabled(false);

            if (toastECUSoda == null) {
                toastECUSoda = connection.resolveStatic(void.class, GMTest.class, "toastValue");
            }

            toastECUSoda.call();
        } catch (Exception e) {
            Log.wtf(TAG, "Exception in toastECU()", e);
        } finally {
            Log.i(TAG, "Finishing");
            setButtonsEnabled(true);
        }
    }

    public void pushECU(View ignored) {
        try {
            setButtonsEnabled(false);

            if (pushECUSoda == null) {
                pushECUSoda = connection.resolveStatic(void.class, GMTest.class, "pushValue");
            }

            pushECUSoda.call();
        } catch (Exception e) {
            Log.wtf(TAG, "Exception in pushECU()", e);
        } finally {
            Log.i(TAG, "Finishing");
            setButtonsEnabled(true);
        }
    }

    public void pushOther(View ignored) {
        try {
            setButtonsEnabled(false);

            if (pushOtherSoda == null) {
                pushOtherSoda = connection.resolveStatic(void.class, GMTest.class, "pushNonValue");
            }

            pushOtherSoda.call();
        } catch (Exception e) {
            Log.wtf(TAG, "Exception in pushOther()", e);
        } finally {
            Log.i(TAG, "Finishing");
            setButtonsEnabled(true);
        }
    }

    public void setSandboxCount(View v) {
        int numSandboxes = sandboxCount.getSelectedItemPosition();
        int countTypeId = sandboxCountType.getSelectedItemPosition();
        String countType = (String) sandboxCountType.getSelectedItem();
        try {
            int oldCount;
            if (countTypeId == 0) { // total sandboxes
                oldCount = connection.getRawInterface().setSandboxCount(numSandboxes);

                // Run nop in each sandbox to ensure code is loaded.
                for (int i = oldCount; i < numSandboxes; i++) {
                    getNop().arg(false).forceSandbox(i).call();
                }
            } else if (countTypeId == 1) {
                oldCount = connection.getRawInterface().setMaxIdleCount(numSandboxes);
            } else if (countTypeId == 2) {
                oldCount = connection.getRawInterface().setMinHotSpare(numSandboxes);
            } else if (countTypeId == 3) {
                oldCount = connection.getRawInterface().setMaxHotSpare(numSandboxes);
            } else {
                throw new IllegalStateException("No idea how to set " + countType);
            }

            Toast.makeText(this, String.format("%s changed from %d to %d", countType, oldCount, numSandboxes),
                    Toast.LENGTH_LONG).show();
        } catch (RemoteException | ClassNotFoundException | IllegalStateException e) {
            Toast.makeText(this, "Set count failed: " + e, Toast.LENGTH_LONG).show();
        }
    }

    public void doPerfTest(View ignored) {
        LatencyTestTask task = new LatencyTestTask();
        int numPasses = Integer.parseInt(perfPassCount.getText().toString());
        task.execute(numPasses);
    }

    public void connectToOASIS(View ignored) {
        Log.i(TAG, "Binding to OASIS...");
        OASISConnection.bind(this, new OASISConnection.DisconnectCallback() {
            @Override
            public void onConnect(OASISConnection conn) throws Exception {
                Log.i(TAG, "Bound to OASIS");
                onOASISConnectStateChange(conn);
            }

            @Override
            public void onDisconnect(OASISConnection conn) throws Exception {
                Log.i(TAG, "Unbound from OASIS");
                onOASISConnectStateChange(null);
            }
        });
    }

    private void setButtonsEnabled(boolean enabled) {
        int childCount = rootLayout.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View v = rootLayout.getChildAt(i);
            if (v instanceof Button && v.getId() != R.id.reconnect && v.getId() != R.id.perf_tests) {
                v.setEnabled(enabled);
            }
        }
    }

    private void onOASISConnectStateChange(OASISConnection conn) {
        connection = conn;
        putValueSoda = null;
        toastValueSoda = null;
        pushValueSoda = null;
        toastECUSoda = null;
        pushECUSoda = null;
        pushOtherSoda = null;
        nop = null;
        setButtonsEnabled(conn != null);
    }

    private synchronized Soda.S1<Boolean, Void> getNop() throws RemoteException, ClassNotFoundException {
        if (nop == null) {
            nop = connection.resolveStatic(void.class, TestSoda.class, "nop", boolean.class);
        }
        return nop;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        kvsValueField = (EditText) findViewById(R.id.kvs_value);
        shouldTaintBox = (CheckBox) findViewById(R.id.is_tainted);
        rootLayout = (RelativeLayout) findViewById(R.id.root_layout);
        sandboxCount = (Spinner) findViewById(R.id.sandbox_count);
        sandboxCountType = (Spinner) findViewById(R.id.sandbox_count_type);
        perfPassCount = (EditText) findViewById(R.id.perf_pass_count);
        taintPerfBox = (CheckBox) findViewById(R.id.perf_taint);

        // Set up adapter for sandbox count spinner
        CharSequence[] countList = new CharSequence[OASISConstants.NUM_SANDBOXES + 1];
        for (int i = 0; i <= OASISConstants.NUM_SANDBOXES; i++) {
            countList[i] = getResources().getQuantityString(R.plurals.sandbox_plurals, i, i);
        }
        ArrayAdapter<CharSequence> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item,
                countList);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        sandboxCount.setAdapter(adapter);
        sandboxCount.setSelection(OASISConstants.NUM_SANDBOXES);

        adapter = ArrayAdapter.createFromResource(this, R.array.sandbox_count_labels,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        sandboxCountType.setAdapter(adapter);

        setButtonsEnabled(false);
        connectToOASIS(null);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_test, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void launchPerfTests(View v) {
        startActivity(new Intent(this, PerfActivity.class));
        finish();
    }

    private class LatencyTestTask extends AsyncTask<Integer, Void, String> {
        private boolean shouldTaint;

        @Override
        protected void onPreExecute() {
            setButtonsEnabled(false);
            shouldTaint = taintPerfBox.isChecked();
        }

        @Override
        protected void onPostExecute(String result) {
            setButtonsEnabled(true);
            Notification notification = new Notification.Builder(TestActivity.this)
                    .setSmallIcon(android.R.drawable.ic_menu_recent_history).setContentTitle("Perf run complete")
                    .setContentText(result).build();
            ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify(0, notification);
        }

        @Override
        protected void onCancelled() {
            setButtonsEnabled(true);
        }

        @Override
        protected String doInBackground(Integer... params) {
            IOASISService svc = connection.getRawInterface();
            int numPasses = params[0];
            try {
                Soda.S1<Boolean, Void> nop = getNop();
                StopWatch stopwatch = new StopWatch();
                nop.arg(shouldTaint).call();

                stopwatch.start();
                for (int i = 0; i < numPasses; i++) {
                    nop.arg(shouldTaint).call();
                }
                stopwatch.stop();

                return String.format("Completed %d calls in %s", numPasses, stopwatch);
            } catch (Exception e) {
                Log.e("TestActivity", "Latency test failed", e);
                return "Test failed: " + e;
            }
        }
    }
}